authhero 9.6.1 → 9.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/u/widget/index.esm.js +1 -1
- package/dist/authhero.cjs +156 -142
- package/dist/authhero.d.ts +188 -188
- package/dist/authhero.mjs +11226 -11030
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/helpers/dcr/metadata-mapping.d.ts +1 -1
- package/dist/types/helpers/users.d.ts +111 -20
- package/dist/types/hooks/helpers/post-login-account-linking.d.ts +3 -2
- package/dist/types/index.d.ts +188 -188
- package/dist/types/routes/auth-api/authorize.d.ts +3 -3
- package/dist/types/routes/auth-api/index.d.ts +13 -13
- package/dist/types/routes/auth-api/oidc-logout.d.ts +2 -2
- package/dist/types/routes/auth-api/passwordless.d.ts +10 -10
- package/dist/types/routes/auth-api/register/index.d.ts +2 -2
- package/dist/types/routes/auth-api/revoke.d.ts +6 -6
- package/dist/types/routes/management-api/authentication-methods.d.ts +1 -1
- package/dist/types/routes/management-api/branding.d.ts +2 -2
- package/dist/types/routes/management-api/clients.d.ts +14 -14
- package/dist/types/routes/management-api/connections.d.ts +1 -1
- package/dist/types/routes/management-api/custom-domains.d.ts +6 -6
- package/dist/types/routes/management-api/forms.d.ts +126 -126
- package/dist/types/routes/management-api/guardian.d.ts +5 -5
- package/dist/types/routes/management-api/helpers.d.ts +1 -1
- package/dist/types/routes/management-api/index.d.ts +170 -170
- package/dist/types/routes/management-api/logs.d.ts +4 -4
- package/dist/types/routes/management-api/organizations.d.ts +5 -5
- package/dist/types/routes/management-api/prompts.d.ts +4 -4
- package/dist/types/routes/management-api/roles.d.ts +1 -1
- package/dist/types/routes/management-api/tenant-export-import.d.ts +5 -5
- package/dist/types/routes/management-api/tenants.d.ts +28 -28
- package/dist/types/routes/management-api/users.d.ts +2 -2
- package/dist/types/routes/universal-login/flow-api.d.ts +8 -8
- package/dist/types/routes/universal-login/u2-index.d.ts +5 -5
- package/dist/types/routes/universal-login/u2-routes.d.ts +5 -5
- package/package.json +6 -6
|
@@ -24,10 +24,10 @@ export declare const dcrRequestSchema: z.ZodObject<{
|
|
|
24
24
|
response_types: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
25
25
|
token_endpoint_auth_method: z.ZodOptional<z.ZodEnum<{
|
|
26
26
|
none: "none";
|
|
27
|
-
private_key_jwt: "private_key_jwt";
|
|
28
27
|
client_secret_post: "client_secret_post";
|
|
29
28
|
client_secret_basic: "client_secret_basic";
|
|
30
29
|
client_secret_jwt: "client_secret_jwt";
|
|
30
|
+
private_key_jwt: "private_key_jwt";
|
|
31
31
|
}>>;
|
|
32
32
|
jwks_uri: z.ZodOptional<z.ZodString>;
|
|
33
33
|
jwks: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -3,6 +3,18 @@ import { EnrichedClient } from "./client";
|
|
|
3
3
|
import { Context } from "hono";
|
|
4
4
|
import { Bindings, Variables } from "../types";
|
|
5
5
|
export declare function getUsersByEmail(userAdapter: UserDataAdapter, tenantId: string, email: string): Promise<User[]>;
|
|
6
|
+
/**
|
|
7
|
+
* Every user sharing `email`, across all pages.
|
|
8
|
+
*
|
|
9
|
+
* {@link getUsersByEmail} returns a single ten-row page, which is fine for the
|
|
10
|
+
* Auth0-shaped `/users-by-email` endpoint but not for a uniqueness check:
|
|
11
|
+
* {@link findEmailConflict} *filters* candidates by connection and cluster, so a
|
|
12
|
+
* truncated page can hide the one row that genuinely conflicts and let a
|
|
13
|
+
* duplicate through. An address legitimately spans many rows (one per provider
|
|
14
|
+
* in a linked cluster), so ten is well within reach. Mirrors the pagination loop
|
|
15
|
+
* in `resolveLinkCandidates`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getAllUsersByEmail(userAdapter: UserDataAdapter, tenantId: string, email: string): Promise<User[]>;
|
|
6
18
|
interface GetUserByProviderParams {
|
|
7
19
|
userAdapter: UserDataAdapter;
|
|
8
20
|
tenant_id: string;
|
|
@@ -89,33 +101,71 @@ interface GetLastUsedUserByEmailParams {
|
|
|
89
101
|
*/
|
|
90
102
|
export declare function getLastUsedUserByEmail({ userAdapter, tenant_id, email, }: GetLastUsedUserByEmailParams): Promise<User | undefined>;
|
|
91
103
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
104
|
+
* Walk `linked_to` from `userId` to the root of its cluster.
|
|
105
|
+
*
|
|
106
|
+
* Correct data resolves in a single hop — {@link linkUserTo} is the only writer
|
|
107
|
+
* of `linked_to` and it keeps clusters flat. This follows the chain anyway, and
|
|
108
|
+
* loudly, because pre-existing rows written before that invariant was enforced
|
|
109
|
+
* can still be several hops deep: degrading to the right answer beats handing a
|
|
110
|
+
* caller a mid-chain identity that reads as a different person.
|
|
111
|
+
*
|
|
112
|
+
* Returns `userId` unchanged when it is a root, is unknown to the adapter, or
|
|
113
|
+
* carries a dangling link, so callers never lose the identity they started
|
|
114
|
+
* with. Cycles and over-deep chains stop at the last id reached.
|
|
115
|
+
*/
|
|
116
|
+
export declare function resolveClusterRootId(userAdapter: UserDataAdapter, tenant_id: string, userId: string): Promise<string>;
|
|
117
|
+
/**
|
|
118
|
+
* Resolve a user to the primary of its linked cluster, falling back to the
|
|
119
|
+
* given user when the link is dangling so callers never lose the identity they
|
|
120
|
+
* started with.
|
|
121
|
+
*
|
|
122
|
+
* This is the single resolver every read path should use — token minting
|
|
123
|
+
* (authorization-code, refresh-token, silent, token-exchange, password), the
|
|
124
|
+
* forms engine, and anything else that needs the canonical identity behind a
|
|
125
|
+
* session. Resolving through {@link resolveClusterRootId} means a cluster that
|
|
126
|
+
* is already corrupt degrades to the correct answer instead of minting a token
|
|
127
|
+
* for a mid-chain `sub`.
|
|
100
128
|
*/
|
|
101
129
|
export declare function resolvePrimaryUser(userAdapter: UserDataAdapter, tenant_id: string, user: User): Promise<User>;
|
|
102
|
-
interface
|
|
130
|
+
interface LinkUserToParams {
|
|
131
|
+
/**
|
|
132
|
+
* Must be an *undecorated* adapter. {@link linkUserTo} is what the user-update
|
|
133
|
+
* decorator's `linked_to` fast-path calls, so handing it a decorated adapter
|
|
134
|
+
* would make its own writes re-enter that fast-path and recurse. Hook code
|
|
135
|
+
* holding `ctx.env.data` should not call this — a plain
|
|
136
|
+
* `users.update(id, { linked_to })` already routes through here.
|
|
137
|
+
*/
|
|
103
138
|
userAdapter: UserDataAdapter;
|
|
104
139
|
tenant_id: string;
|
|
105
|
-
|
|
106
|
-
|
|
140
|
+
/** The user being demoted to a secondary. */
|
|
141
|
+
userId: string;
|
|
142
|
+
/** The intended primary. Resolved to its own cluster root first. */
|
|
143
|
+
primaryId: string;
|
|
107
144
|
}
|
|
108
145
|
/**
|
|
109
|
-
* Demote `
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* the
|
|
146
|
+
* Demote `userId` to a secondary of `primaryId`'s cluster — the one and only
|
|
147
|
+
* way `linked_to` is ever set (issue #1250).
|
|
148
|
+
*
|
|
149
|
+
* Two things have to happen together for the graph to stay a single hop deep,
|
|
150
|
+
* and doing either without the other silently corrupts it:
|
|
151
|
+
*
|
|
152
|
+
* - **Resolve the target.** Linking onto a row that is itself a secondary
|
|
153
|
+
* would build a second hop, so the real root is resolved first.
|
|
154
|
+
* - **Repoint the children.** Any users already linked to `userId` are moved
|
|
155
|
+
* onto the root *before* `userId` is demoted. Skipping this strands them
|
|
156
|
+
* behind a now-secondary parent, where no resolver can reach them and they
|
|
157
|
+
* disappear from the API entirely.
|
|
158
|
+
*
|
|
159
|
+
* Callers get this for free: the decorator routes every single-field
|
|
160
|
+
* `linked_to` update through here, so a bare
|
|
161
|
+
* `users.update(id, { linked_to })` — from the management API, a consumer's
|
|
162
|
+
* hook, or internal linking code — is safe by construction rather than by
|
|
163
|
+
* remembering to call the right helper.
|
|
164
|
+
*
|
|
165
|
+
* Returns the cluster root `userId` was actually linked to, which may differ
|
|
166
|
+
* from the requested `primaryId`.
|
|
117
167
|
*/
|
|
118
|
-
export declare function
|
|
168
|
+
export declare function linkUserTo({ userAdapter, tenant_id, userId, primaryId, }: LinkUserToParams): Promise<string>;
|
|
119
169
|
/**
|
|
120
170
|
* True for identities whose *login identifier* is the email address: the native
|
|
121
171
|
* username-password providers (`auth0`/`auth2`) and the passwordless `email`
|
|
@@ -128,6 +178,47 @@ export declare function repointPrimary({ userAdapter, tenant_id, formerPrimary,
|
|
|
128
178
|
* is email-identified and neither should have its `email` rewritten by a cascade.
|
|
129
179
|
*/
|
|
130
180
|
export declare function isEmailIdentifiedUser(user: Pick<User, "provider" | "connection">): boolean;
|
|
181
|
+
interface EmailConflictParams {
|
|
182
|
+
/** Every user sharing the new address, as returned by {@link getUsersByEmail}. */
|
|
183
|
+
candidates: User[];
|
|
184
|
+
/** The identity whose email is being changed. */
|
|
185
|
+
target: Pick<User, "user_id" | "provider" | "connection">;
|
|
186
|
+
/**
|
|
187
|
+
* The cluster root of the patched user. `target` may be the root itself or one
|
|
188
|
+
* of its linked secondaries (when the caller passed `connection`).
|
|
189
|
+
*/
|
|
190
|
+
clusterRootId: string;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Find the user, if any, that genuinely blocks changing `target`'s email to an
|
|
194
|
+
* address already present on other rows.
|
|
195
|
+
*
|
|
196
|
+
* Two rows sharing an email is only a *conflict* when it makes a login ambiguous,
|
|
197
|
+
* and login lookups are always provider-scoped (`getUserByProvider` filters on
|
|
198
|
+
* `email:x provider:y`). So the check is scoped the way Auth0 scopes it — per
|
|
199
|
+
* connection — with one hard floor from the storage layer:
|
|
200
|
+
*
|
|
201
|
+
* - **Same provider** → always a conflict, cluster-mate or not. The
|
|
202
|
+
* `(tenant_id, provider, email)` unique index makes a second row with that
|
|
203
|
+
* address unrepresentable, so the write cannot succeed; a 409 is the honest
|
|
204
|
+
* answer where allowing it would surface as a constraint-violation 500.
|
|
205
|
+
* - **Same connection, different provider** → a conflict *between* clusters. Two
|
|
206
|
+
* `Username-Password-Authentication` rows (the `auth0`/`auth2` pair) sharing an
|
|
207
|
+
* address are competing login rows for one credential. Unknown/custom
|
|
208
|
+
* connections are included, so tenant-specific database connections keep the
|
|
209
|
+
* protection they have today.
|
|
210
|
+
* - **Different connection** → not a conflict. An `sms` identity is keyed by
|
|
211
|
+
* `phone_number` and a social identity by its provider sub, so their `email` is
|
|
212
|
+
* ordinary profile data that can't shadow an email login. This mirrors the
|
|
213
|
+
* `phone_number` carve-out on the same route (#1162) and matches Auth0, where
|
|
214
|
+
* one address may exist across connections.
|
|
215
|
+
* - **Cluster-mates** (the root and its secondaries) → not a conflict, provider
|
|
216
|
+
* permitting: they are the same person, and `cascadeEmailToLinkedIdentities`
|
|
217
|
+
* deliberately converges the cluster onto one address right after this check.
|
|
218
|
+
* Because AuthHero keeps secondaries as real rows (Auth0 folds them into the
|
|
219
|
+
* primary's `identities[]`), they'd otherwise surface here as "another user".
|
|
220
|
+
*/
|
|
221
|
+
export declare function findEmailConflict({ candidates, target, clusterRootId, }: EmailConflictParams): User | undefined;
|
|
131
222
|
interface CascadeEmailParams {
|
|
132
223
|
userAdapter: UserDataAdapter;
|
|
133
224
|
tenant_id: string;
|
|
@@ -29,8 +29,9 @@ export type PostLoginUserApi = {
|
|
|
29
29
|
* logging-in user must have a verified email, regardless of what the action
|
|
30
30
|
* asserts.
|
|
31
31
|
* - **Direction.** Older account wins (`compareUsersByAge`): if the logging-in
|
|
32
|
-
* user pre-dates the target, the target is demoted
|
|
33
|
-
*
|
|
32
|
+
* user pre-dates the target, the target is demoted instead. Either way the
|
|
33
|
+
* write goes through the update decorator's `linkUserTo` chokepoint, which
|
|
34
|
+
* keeps the cluster a single hop deep.
|
|
34
35
|
* - **Idempotency.** A no-op when the user is already linked to the target.
|
|
35
36
|
*/
|
|
36
37
|
export declare function createPostLoginUserApi(params: {
|