authhero 9.6.3 → 9.7.0

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.
Files changed (47) hide show
  1. package/dist/assets/u/widget/index.esm.js +1 -1
  2. package/dist/authhero.cjs +144 -144
  3. package/dist/authhero.d.ts +460 -240
  4. package/dist/authhero.mjs +14192 -14009
  5. package/dist/tsconfig.types.tsbuildinfo +1 -1
  6. package/dist/types/authentication-flows/common.d.ts +17 -1
  7. package/dist/types/authentication-flows/passwordless.d.ts +5 -5
  8. package/dist/types/helpers/dcr/metadata-mapping.d.ts +1 -1
  9. package/dist/types/helpers/revoke-user-refresh-tokens.d.ts +21 -0
  10. package/dist/types/helpers/users.d.ts +58 -20
  11. package/dist/types/hooks/helpers/post-login-account-linking.d.ts +3 -2
  12. package/dist/types/index.d.ts +460 -240
  13. package/dist/types/routes/auth-api/index.d.ts +29 -29
  14. package/dist/types/routes/auth-api/passwordless.d.ts +12 -12
  15. package/dist/types/routes/auth-api/revoke.d.ts +6 -6
  16. package/dist/types/routes/auth-api/token.d.ts +10 -10
  17. package/dist/types/routes/auth-api/well-known.d.ts +1 -1
  18. package/dist/types/routes/management-api/action-executions.d.ts +1 -1
  19. package/dist/types/routes/management-api/actions.d.ts +1 -1
  20. package/dist/types/routes/management-api/branding.d.ts +1 -1
  21. package/dist/types/routes/management-api/clients.d.ts +6 -6
  22. package/dist/types/routes/management-api/connections.d.ts +16 -16
  23. package/dist/types/routes/management-api/custom-domains.d.ts +6 -6
  24. package/dist/types/routes/management-api/email-templates.d.ts +18 -18
  25. package/dist/types/routes/management-api/failed-events.d.ts +1 -1
  26. package/dist/types/routes/management-api/forms.d.ts +126 -126
  27. package/dist/types/routes/management-api/guardian.d.ts +5 -5
  28. package/dist/types/routes/management-api/helpers.d.ts +1 -1
  29. package/dist/types/routes/management-api/index.d.ts +424 -204
  30. package/dist/types/routes/management-api/logs.d.ts +4 -4
  31. package/dist/types/routes/management-api/migration-sources.d.ts +6 -6
  32. package/dist/types/routes/management-api/organizations.d.ts +1 -1
  33. package/dist/types/routes/management-api/prompts.d.ts +4 -4
  34. package/dist/types/routes/management-api/refresh_tokens.d.ts +7 -0
  35. package/dist/types/routes/management-api/roles.d.ts +1 -1
  36. package/dist/types/routes/management-api/tenant-export-import.d.ts +5 -5
  37. package/dist/types/routes/management-api/tenants.d.ts +4 -4
  38. package/dist/types/routes/management-api/users.d.ts +148 -2
  39. package/dist/types/routes/universal-login/common.d.ts +6 -6
  40. package/dist/types/routes/universal-login/flow-api.d.ts +12 -12
  41. package/dist/types/routes/universal-login/identifier.d.ts +2 -2
  42. package/dist/types/routes/universal-login/index.d.ts +2 -2
  43. package/dist/types/routes/universal-login/u2-index.d.ts +5 -5
  44. package/dist/types/routes/universal-login/u2-routes.d.ts +5 -5
  45. package/dist/types/utils/jwks.d.ts +2 -2
  46. package/dist/types/utils/user-id.d.ts +19 -1
  47. package/package.json +6 -6
@@ -1,4 +1,4 @@
1
- import { AuthorizationResponseType, AuthParams, LoginSession, RefreshToken, User, TokenResponse } from "@authhero/adapter-interfaces";
1
+ import { AuthorizationResponseType, AuthParams, LoginSession, LoginSessionAuthStrategy, RefreshToken, User, TokenResponse } from "@authhero/adapter-interfaces";
2
2
  import { EnrichedClient } from "../helpers/client";
3
3
  import { Context } from "hono";
4
4
  import { Bindings, Variables } from "../types";
@@ -82,6 +82,22 @@ export interface CreateRefreshTokenParams {
82
82
  login_id: string;
83
83
  scope: string;
84
84
  audience?: string;
85
+ /**
86
+ * The authenticated session this token is issued under — Auth0's
87
+ * `session_id`. Stored so revoking a session can revoke its tokens in one
88
+ * hop, and so the refresh grant never has to resolve it through the
89
+ * short-lived login session. Optional: flows without a session still mint
90
+ * tokens, and the column is nullable for exactly that reason.
91
+ */
92
+ session_id?: string;
93
+ /**
94
+ * Auth-event facts, denormalised from the login session. All are immutable
95
+ * for the life of the token; keeping them here means the grant no longer
96
+ * degrades silently when the login session has been cleaned up.
97
+ */
98
+ organization?: string;
99
+ auth_connection?: string;
100
+ auth_strategy?: LoginSessionAuthStrategy;
85
101
  }
86
102
  export interface CreatedRefreshToken {
87
103
  row: RefreshToken;
@@ -372,7 +372,7 @@ export declare function passwordlessGrantUser(ctx: Context<{
372
372
  active?: boolean | undefined;
373
373
  } | undefined;
374
374
  signup?: {
375
- status?: "optional" | "required" | "disabled" | undefined;
375
+ status?: "required" | "optional" | "disabled" | undefined;
376
376
  verification?: {
377
377
  active?: boolean | undefined;
378
378
  } | undefined;
@@ -389,7 +389,7 @@ export declare function passwordlessGrantUser(ctx: Context<{
389
389
  active?: boolean | undefined;
390
390
  } | undefined;
391
391
  signup?: {
392
- status?: "optional" | "required" | "disabled" | undefined;
392
+ status?: "required" | "optional" | "disabled" | undefined;
393
393
  } | undefined;
394
394
  validation?: {
395
395
  max_length?: number | undefined;
@@ -406,7 +406,7 @@ export declare function passwordlessGrantUser(ctx: Context<{
406
406
  active?: boolean | undefined;
407
407
  } | undefined;
408
408
  signup?: {
409
- status?: "optional" | "required" | "disabled" | undefined;
409
+ status?: "required" | "optional" | "disabled" | undefined;
410
410
  } | undefined;
411
411
  } | undefined;
412
412
  } | undefined;
@@ -554,8 +554,8 @@ export declare function passwordlessGrantUser(ctx: Context<{
554
554
  } | undefined;
555
555
  authenticated_at?: string | undefined;
556
556
  };
557
- connectionType: "sms" | "email" | "username";
558
- authConnection: "sms" | "email" | "username";
557
+ connectionType: "email" | "username" | "sms";
558
+ authConnection: "email" | "username" | "sms";
559
559
  session_id: string | undefined;
560
560
  authParams: {
561
561
  client_id: string;
@@ -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>>;
@@ -0,0 +1,21 @@
1
+ import { Context } from "hono";
2
+ import { Bindings, Variables } from "../types";
3
+ /**
4
+ * Soft-revoke every active refresh token belonging to a user.
5
+ *
6
+ * Unlike the single-token admin delete (which also hard-removes the row), this
7
+ * keeps the rows around with `revoked_at` set so the admin UI and the audit
8
+ * trail can still show what was invalidated and when.
9
+ *
10
+ * Delegates to the adapter so the match is a pair of exact predicates rather
11
+ * than a `q` filter: the Lucene grammar splits on ` OR ` before tokenizing, so
12
+ * a user id containing ` OR user_id:<other> OR ` would widen a `q`-based
13
+ * revoke to another user's tokens. The adapter also skips already-revoked
14
+ * rows, so a concurrent revocation cannot overwrite an existing timestamp.
15
+ *
16
+ * Returns the number of tokens revoked.
17
+ */
18
+ export declare function revokeUserRefreshTokens(ctx: Context<{
19
+ Bindings: Bindings;
20
+ Variables: Variables;
21
+ }>, tenant_id: string, user_id: string): Promise<number>;
@@ -101,33 +101,71 @@ interface GetLastUsedUserByEmailParams {
101
101
  */
102
102
  export declare function getLastUsedUserByEmail({ userAdapter, tenant_id, email, }: GetLastUsedUserByEmailParams): Promise<User | undefined>;
103
103
  /**
104
- * Resolve a user to the primary of its linked cluster. Follows a single
105
- * `linked_to` hop — the linking invariants keep clusters one level deep
106
- * (see {@link repointPrimary}) and falls back to the given user on a
107
- * dangling link so callers never lose the identity they started with.
108
- *
109
- * Used by the forms engine so that post-login profile forms evaluate
110
- * router conditions against, and stamp submitted values onto, the primary
111
- * identity even when the session points at a secondary.
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`.
112
128
  */
113
129
  export declare function resolvePrimaryUser(userAdapter: UserDataAdapter, tenant_id: string, user: User): Promise<User>;
114
- interface RepointPrimaryParams {
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
+ */
115
138
  userAdapter: UserDataAdapter;
116
139
  tenant_id: string;
117
- formerPrimary: User;
118
- newPrimaryId: string;
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;
119
144
  }
120
145
  /**
121
- * Demote `formerPrimary` to a secondary of `newPrimaryId`. Any users
122
- * currently linked to `formerPrimary` are repointed first so the resulting
123
- * graph remains a single hop deep — `getPrimaryUserByProvider` and similar
124
- * resolvers only follow one `linked_to` step.
125
- *
126
- * Each write is a single-field `linked_to` update so the user-update
127
- * decorator's fast-path bypasses the pre/post hooks and we don't re-enter
128
- * the linking logic recursively.
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`.
129
167
  */
130
- export declare function repointPrimary({ userAdapter, tenant_id, formerPrimary, newPrimaryId, }: RepointPrimaryParams): Promise<void>;
168
+ export declare function linkUserTo({ userAdapter, tenant_id, userId, primaryId, }: LinkUserToParams): Promise<string>;
131
169
  /**
132
170
  * True for identities whose *login identifier* is the email address: the native
133
171
  * username-password providers (`auth0`/`auth2`) and the passwordless `email`
@@ -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 via `repointPrimary`
33
- * (avoiding 2-hop chains) instead.
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: {