You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 05b9276
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: apps/web/content/docs/dev/events/built-in-events.mdx
+32-2Lines changed: 32 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -38,7 +38,7 @@ core event as for one of your own.
38
38
39
39
## Core events (`@vitnode/core`)
40
40
41
-
Six names, all declared in `VitNodeEvents` in
41
+
Seven names, all declared in `VitNodeEvents` in
42
42
`packages/vitnode/src/api/models/events.ts`. Every one of them fires **after**
43
43
the write it describes has committed.
44
44
@@ -47,6 +47,7 @@ the write it describes has committed.
47
47
|`user.created`|`{ userId, email, name, emailVerified }`| A user row is inserted - public sign-up, AdminCP creation, or SSO sign-up |
48
48
|`user.updated`|`{ userId, email, name }`| A user is edited in the AdminCP (profile fields and/or role assignments) |
49
49
|`user.deleted`|`{ userId, email }`| Never - the name is declared for plugins, core has no deletion flow |
50
+
|`user.sso.linked`|`{ userId, email, providerId }`| A visitor proves an existing account is theirs with its password and an SSO identity is linked to it |
50
51
|`role.created`|`{ roleId }`| A role is created in the AdminCP |
51
52
|`role.updated`|`{ roleId }`| A role is edited in the AdminCP |
52
53
|`role.deleted`|`{ roleId }`| A role is deleted in the AdminCP |
@@ -74,7 +75,7 @@ AdminCP, and the first sign-in through an [SSO provider](/docs/dev/sso).
74
75
},
75
76
emailVerified: {
76
77
description:
77
-
'Whether the account starts verified. True for the very first user in an installation (the root account) and whenever no email adapter is configured, because nothing could send a verification mail.',
78
+
'Whether the account starts verified. True for the very first user in an installation (the root account), whenever no email adapter is configured (nothing could send a verification mail), and for every account created through an SSO provider, which has already verified the address.',
78
79
type: 'boolean',
79
80
},
80
81
}}
@@ -125,6 +126,35 @@ name, name code) and/or role assignments. The payload carries the user's
125
126
list), invalidate a plugin-owned cache keyed by user, or audit-log the staff
126
127
edit using the envelope's `actor`.
127
128
129
+
</Accordion>
130
+
<Accordiontitle="user.sso.linked">
131
+
132
+
Emitted by `SSOModel.link` after the `core_users_sso` row is committed - the
133
+
moment a social identity that arrived with an already-registered email is tied
134
+
to that account. It does not fire on the first sign-in through a provider (that
135
+
is a `user.created`) or on a later sign-in through an identity that is already
136
+
linked.
137
+
138
+
<TypeTable
139
+
type={{
140
+
userId: {
141
+
description: 'Id of the account the identity was linked to.',
142
+
type: 'number',
143
+
},
144
+
email: {
145
+
description: "The account's email - the address the provider and the account had in common.",
146
+
type: 'string',
147
+
},
148
+
providerId: {
149
+
description: "The adapter's id, e.g. 'google' or 'facebook'.",
150
+
type: 'string',
151
+
},
152
+
}}
153
+
/>
154
+
155
+
**A listener would** notify the account owner that a new sign-in method was
156
+
added, or audit-log the link with the envelope's `actor`.
157
+
128
158
</Accordion>
129
159
<Accordiontitle="user.deleted (declared, never emitted)">
description: "Fetches user profile (id, email, username, avatarUrl).",
138
+
description: "Fetches user profile (id, email, username, avatarUrl). Return only an email the provider has verified - VitNode treats it as confirmed and will mark a matching unconfirmed account verified. The built-in adapters reject unverified addresses with a 400.",
Copy file name to clipboardExpand all lines: apps/web/content/docs/dev/sso/index.mdx
+31-1Lines changed: 31 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -81,9 +81,39 @@ For example: `https://your-domain.com/login/sso/google`.
81
81
82
82
When a user signs in via SSO:
83
83
1.**Known Identity**: The provider account was linked before, so the user is signed straight into it.
84
-
2.**Existing Email Match**: An account already uses that address, so the request is refused with `409`. A social login can never take over an account someone else registered with a password.
84
+
2.**Existing Email Match**: An account already uses that address. The visitor is asked for that account's password; once it checks out, the provider identity is linked to the account and they are signed in. From then on that provider signs them straight in (case 1). A social login can never take over an account on its own - the password is what proves ownership.
85
85
3.**New Visitor**: A new user is created with their social display name, email, and avatar.
86
86
87
+
### SSO confirms the email
88
+
89
+
A provider only hands VitNode an address it has verified itself (the built-in
90
+
adapters refuse anything else), so a social sign-in doubles as email
91
+
confirmation:
92
+
93
+
- a **new visitor** starts out with `emailVerified: true`, even when an email
94
+
adapter is configured and password sign-ups would have to confirm first;
95
+
- a **known identity** or a **freshly linked** account whose address is still
96
+
unconfirmed is marked confirmed - provided the address the provider returned
97
+
is the one on the account. An account whose email was changed since the link
98
+
was made is left alone.
99
+
100
+
### Linking an existing account
101
+
102
+
The callback answers `409` with a short-lived, signed **link offer** - the
103
+
account's email, whether it has a password, and a token good for ten minutes.
104
+
The login page turns that into a "Connect *Provider* to your account" form: the
105
+
email is shown read-only, the visitor types their password, and
106
+
`POST /users/sso/{providerId}/link` verifies both before it writes the
107
+
`core_users_sso` row and mints a session. The token carries the provider account
108
+
id, so nothing about *which* identity gets linked is taken from the browser.
109
+
110
+
An account created by another provider has no password to confirm with. When an
111
+
email adapter is configured the form offers **Set a password** (the ordinary
112
+
reset flow) and asks them to try the provider again afterwards; without one it
113
+
points back to the login page.
114
+
115
+
Every successful link emits [`user.sso.linked`](/docs/dev/events/built-in-events).
116
+
87
117
The address the provider returns is matched in its canonical form, so a Google account that reports `jan.kowalski@gmail.com` finds the member who registered as `jankowalski@gmail.com` instead of quietly becoming a second account. See [One Mailbox, One Account](/docs/dev/advanced/auth#one-mailbox-one-account).
0 commit comments