authhero 9.8.0 → 9.9.1
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 +543 -344
- package/dist/authhero.d.ts +158 -138
- package/dist/authhero.mjs +12631 -12103
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/authentication-flows/grant-tokens.d.ts +16 -0
- package/dist/types/authentication-flows/passwordless.d.ts +26 -3
- package/dist/types/helpers/refresh-token-lifetime.d.ts +103 -0
- package/dist/types/helpers/revoke-session-refresh-tokens.d.ts +33 -0
- package/dist/types/hooks/addDataHooks.d.ts +4 -3
- package/dist/types/index.d.ts +158 -138
- package/dist/types/routes/auth-api/index.d.ts +59 -39
- package/dist/types/routes/auth-api/passwordless.d.ts +6 -6
- package/dist/types/routes/auth-api/revoke.d.ts +6 -6
- package/dist/types/routes/auth-api/token.d.ts +44 -24
- package/dist/types/routes/auth-api/well-known.d.ts +1 -1
- package/dist/types/routes/management-api/custom-domains.d.ts +6 -6
- package/dist/types/routes/management-api/failed-events.d.ts +1 -1
- package/dist/types/routes/management-api/forms.d.ts +126 -126
- package/dist/types/routes/management-api/index.d.ts +69 -69
- package/dist/types/routes/management-api/keys.d.ts +16 -16
- package/dist/types/routes/management-api/logs.d.ts +4 -4
- package/dist/types/routes/management-api/organizations.d.ts +2 -2
- 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 +2 -2
- package/dist/types/routes/management-api/users.d.ts +17 -17
- package/dist/types/routes/universal-login/info-code-exchange.d.ts +27 -0
- package/dist/types/routes/universal-login/token-info-page.d.ts +26 -0
- 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/dist/types/state-machines/login-session.d.ts +1 -1
- package/dist/types/utils/email.d.ts +21 -9
- package/dist/types/utils/jwks.d.ts +2 -2
- package/package.json +8 -8
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Context } from "hono";
|
|
2
|
+
import { GrantType, TokenResponse } from "@authhero/adapter-interfaces";
|
|
3
|
+
import { Bindings, Variables } from "../types";
|
|
4
|
+
import { GrantFlowResult } from "../types/GrantFlowResult";
|
|
5
|
+
/**
|
|
6
|
+
* Turn a resolved grant into wire tokens: narrow the requested scopes to what
|
|
7
|
+
* the user/client is actually granted for the audience, pick the token
|
|
8
|
+
* lifetime from the resource server, then mint the tokens.
|
|
9
|
+
*
|
|
10
|
+
* Shared by the /oauth/token endpoint and the server-side code exchange on the
|
|
11
|
+
* /u2/info test page so both mint identical tokens for the same grant.
|
|
12
|
+
*/
|
|
13
|
+
export declare function issueTokensForGrant(ctx: Context<{
|
|
14
|
+
Bindings: Bindings;
|
|
15
|
+
Variables: Variables;
|
|
16
|
+
}>, grantResult: GrantFlowResult, grantType: GrantType): Promise<TokenResponse>;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { Context } from "hono";
|
|
2
2
|
import { z } from "@hono/zod-openapi";
|
|
3
3
|
import { Bindings, Variables } from "../types";
|
|
4
|
+
import { GrantFlowUserResult } from "../types/GrantFlowResult";
|
|
4
5
|
export declare const passwordlessGrantParamsSchema: z.ZodObject<{
|
|
5
6
|
client_id: z.ZodString;
|
|
6
7
|
username: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
7
8
|
otp: z.ZodString;
|
|
9
|
+
scope: z.ZodOptional<z.ZodString>;
|
|
10
|
+
audience: z.ZodOptional<z.ZodString>;
|
|
8
11
|
authParams: z.ZodOptional<z.ZodObject<{
|
|
9
12
|
client_id: z.ZodString;
|
|
10
13
|
act_as: z.ZodOptional<z.ZodString>;
|
|
@@ -42,7 +45,7 @@ export declare const passwordlessGrantParamsSchema: z.ZodObject<{
|
|
|
42
45
|
export declare function passwordlessGrantUser(ctx: Context<{
|
|
43
46
|
Bindings: Bindings;
|
|
44
47
|
Variables: Variables;
|
|
45
|
-
}>, { client_id, username, otp, authParams, enforceIpCheck, }: z.input<typeof passwordlessGrantParamsSchema>): Promise<{
|
|
48
|
+
}>, { client_id, username, otp, scope, audience, authParams, enforceIpCheck, }: z.input<typeof passwordlessGrantParamsSchema>): Promise<{
|
|
46
49
|
user: {
|
|
47
50
|
connection: string;
|
|
48
51
|
email_verified: boolean;
|
|
@@ -558,16 +561,16 @@ export declare function passwordlessGrantUser(ctx: Context<{
|
|
|
558
561
|
authConnection: "username" | "email" | "sms";
|
|
559
562
|
session_id: string | undefined;
|
|
560
563
|
authParams: {
|
|
564
|
+
audience?: string | undefined;
|
|
565
|
+
scope?: string | undefined;
|
|
561
566
|
client_id: string;
|
|
562
567
|
act_as?: string | undefined;
|
|
563
568
|
response_type?: import("@authhero/adapter-interfaces").AuthorizationResponseType | undefined;
|
|
564
569
|
response_mode?: import("@authhero/adapter-interfaces").AuthorizationResponseMode | undefined;
|
|
565
570
|
redirect_uri?: string | undefined;
|
|
566
|
-
audience?: string | undefined;
|
|
567
571
|
organization?: string | undefined;
|
|
568
572
|
state?: string | undefined;
|
|
569
573
|
nonce?: string | undefined;
|
|
570
|
-
scope?: string | undefined;
|
|
571
574
|
prompt?: string | undefined;
|
|
572
575
|
code_challenge_method?: import("@authhero/adapter-interfaces").CodeChallengeMethod | undefined;
|
|
573
576
|
code_challenge?: string | undefined;
|
|
@@ -590,6 +593,26 @@ export declare function passwordlessGrantUser(ctx: Context<{
|
|
|
590
593
|
vendor_id?: string | undefined;
|
|
591
594
|
};
|
|
592
595
|
}>;
|
|
596
|
+
/**
|
|
597
|
+
* The `http://auth0.com/oauth/grant-type/passwordless/otp` grant at
|
|
598
|
+
* /oauth/token.
|
|
599
|
+
*
|
|
600
|
+
* Unlike the authorization-code exchange — where /authorize has already
|
|
601
|
+
* authenticated the login session and created a session — nothing has run for
|
|
602
|
+
* this login yet: /passwordless/start only stores a PENDING login session and
|
|
603
|
+
* an OTP. So authenticate it here, which creates the session the auth cookie
|
|
604
|
+
* and the refresh token below both hang off, then mint a refresh token when
|
|
605
|
+
* `offline_access` was requested (issue #1273).
|
|
606
|
+
*
|
|
607
|
+
* The sibling front-channel path (`passwordlessGrant`, used by
|
|
608
|
+
* /co/authenticate) does not go through here: createFrontChannelAuthResponse
|
|
609
|
+
* does both steps itself, and skips the refresh token for code flows so the
|
|
610
|
+
* exchange issues it instead.
|
|
611
|
+
*/
|
|
612
|
+
export declare function passwordlessOtpGrant(ctx: Context<{
|
|
613
|
+
Bindings: Bindings;
|
|
614
|
+
Variables: Variables;
|
|
615
|
+
}>, params: z.input<typeof passwordlessGrantParamsSchema>): Promise<GrantFlowUserResult>;
|
|
593
616
|
export declare function passwordlessGrant(ctx: Context<{
|
|
594
617
|
Bindings: Bindings;
|
|
595
618
|
Variables: Variables;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refresh-token lifetimes (issue #1260).
|
|
3
|
+
*
|
|
4
|
+
* Auth0 keeps refresh-token expiry and session expiry as two separate
|
|
5
|
+
* concepts: the former is configured per *client* (`client.refresh_token.*`,
|
|
6
|
+
* in seconds), the latter per *tenant* (`session_lifetime` /
|
|
7
|
+
* `idle_session_lifetime`, in hours). AuthHero historically derived
|
|
8
|
+
* refresh-token expiry from the tenant session lifetimes only, which made
|
|
9
|
+
* `infinite_token_lifetime` — the setting native/mobile clients rely on —
|
|
10
|
+
* unrepresentable.
|
|
11
|
+
*
|
|
12
|
+
* These helpers resolve the effective lifetime: per-client config wins when
|
|
13
|
+
* set, otherwise we fall back to the tenant-derived behaviour so existing
|
|
14
|
+
* tenants see no change.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* A resolved refresh-token lifetime.
|
|
18
|
+
*
|
|
19
|
+
* - `seconds` — expires this many seconds after the anchor point.
|
|
20
|
+
* - `infinite` — explicitly configured never to expire.
|
|
21
|
+
* - `unset` — nothing configured at either level. Distinct from `infinite`
|
|
22
|
+
* so callers can tell "the operator asked for no expiry" from "no opinion":
|
|
23
|
+
* at mint both mean no expiry, but on rotation only `infinite` clears an
|
|
24
|
+
* expiry the parent row already carried.
|
|
25
|
+
*/
|
|
26
|
+
export type RefreshTokenLifetime = {
|
|
27
|
+
kind: "seconds";
|
|
28
|
+
seconds: number;
|
|
29
|
+
} | {
|
|
30
|
+
kind: "infinite";
|
|
31
|
+
} | {
|
|
32
|
+
kind: "unset";
|
|
33
|
+
};
|
|
34
|
+
/** The subset of a client this module reads. */
|
|
35
|
+
export interface RefreshTokenLifetimeClient {
|
|
36
|
+
refresh_token?: {
|
|
37
|
+
expiration_type?: "expiring" | "non-expiring";
|
|
38
|
+
token_lifetime?: number;
|
|
39
|
+
infinite_token_lifetime?: boolean;
|
|
40
|
+
idle_token_lifetime?: number;
|
|
41
|
+
infinite_idle_token_lifetime?: boolean;
|
|
42
|
+
};
|
|
43
|
+
tenant: {
|
|
44
|
+
session_lifetime?: number;
|
|
45
|
+
idle_session_lifetime?: number;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Absolute ("hard") refresh-token lifetime: how long the token is valid for,
|
|
50
|
+
* regardless of use.
|
|
51
|
+
*/
|
|
52
|
+
export declare function resolveAbsoluteRefreshTokenLifetime(client: RefreshTokenLifetimeClient): RefreshTokenLifetime;
|
|
53
|
+
/**
|
|
54
|
+
* Idle ("sliding") refresh-token lifetime: how long the token survives without
|
|
55
|
+
* being exchanged. Refreshed on every successful exchange.
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveIdleRefreshTokenLifetime(client: RefreshTokenLifetimeClient): RefreshTokenLifetime;
|
|
58
|
+
/**
|
|
59
|
+
* Turn a lifetime into an ISO expiry timestamp measured from `from`.
|
|
60
|
+
* `infinite` and `unset` both yield `undefined` — no expiry column is written.
|
|
61
|
+
*/
|
|
62
|
+
export declare function lifetimeToExpiresAt(lifetime: RefreshTokenLifetime, from?: number): string | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Both expiry timestamps for a freshly minted refresh token.
|
|
65
|
+
*/
|
|
66
|
+
export declare function resolveRefreshTokenExpiry(client: RefreshTokenLifetimeClient, from?: number): {
|
|
67
|
+
expires_at?: string;
|
|
68
|
+
idle_expires_at?: string;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* The idle expiry a token should carry after a successful exchange.
|
|
72
|
+
*
|
|
73
|
+
* Sliding only applies to a token that already had an idle window: a row minted
|
|
74
|
+
* without one is not retro-fitted with an expiry mid-life. The exception is an
|
|
75
|
+
* explicit `infinite` config, which clears an existing window so a client
|
|
76
|
+
* switched to non-expiring stops being cut off by expiries stamped earlier.
|
|
77
|
+
*/
|
|
78
|
+
export declare function slideIdleExpiry(client: RefreshTokenLifetimeClient, currentIdleExpiresAt: string | undefined, from?: number): string | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* The expiry columns an in-place (non-rotating) exchange should write.
|
|
81
|
+
*
|
|
82
|
+
* Three-valued per column, matching the adapter's update contract:
|
|
83
|
+
* `undefined` leaves the stored value alone, a string overwrites it, `null`
|
|
84
|
+
* clears it.
|
|
85
|
+
*
|
|
86
|
+
* Rotation reconciles a changed client config for free — the child row is
|
|
87
|
+
* minted from the current lifetimes — but the non-rotating path keeps handing
|
|
88
|
+
* back the row it was given, so it has to say so explicitly:
|
|
89
|
+
*
|
|
90
|
+
* - Idle window: slides by the resolved lifetime, and is cleared when the
|
|
91
|
+
* client is configured never to idle-expire. A row minted without an idle
|
|
92
|
+
* window is not retro-fitted with one mid-life.
|
|
93
|
+
* - Absolute window: never extended — refreshing must not let a bounded token
|
|
94
|
+
* outlive the expiry stamped at mint — and only cleared when the client is
|
|
95
|
+
* configured never to expire.
|
|
96
|
+
*/
|
|
97
|
+
export declare function resolveExchangeExpiryUpdate(client: RefreshTokenLifetimeClient, current: {
|
|
98
|
+
expires_at?: string;
|
|
99
|
+
idle_expires_at?: string;
|
|
100
|
+
}, from?: number): {
|
|
101
|
+
expires_at?: null;
|
|
102
|
+
idle_expires_at?: string | null;
|
|
103
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DataAdapters } from "@authhero/adapter-interfaces";
|
|
2
|
+
/**
|
|
3
|
+
* The parts of a session this cascade needs: its own id, which refresh tokens
|
|
4
|
+
* point at through `session_id`, and the login session it originated from,
|
|
5
|
+
* which is the only link rows minted before that column existed carry.
|
|
6
|
+
*/
|
|
7
|
+
export interface RevocableSession {
|
|
8
|
+
id: string;
|
|
9
|
+
login_session_id?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Revoke every refresh token issued under a session.
|
|
13
|
+
*
|
|
14
|
+
* Call this only where a session is *deliberately* ended — an admin revoking
|
|
15
|
+
* or deleting it, or a user being blocked. Natural expiry and cleanup must not
|
|
16
|
+
* cascade: a refresh token is designed to outlive its session, and killing
|
|
17
|
+
* tokens on an SSO timeout would log out every long-lived native client on
|
|
18
|
+
* each timeout. Revocation couples; lifetime does not.
|
|
19
|
+
*
|
|
20
|
+
* Two sweeps, run in sequence:
|
|
21
|
+
*
|
|
22
|
+
* 1. `session_id` — the ownership edge, and the one that is actually complete.
|
|
23
|
+
* 2. `login_id` — legacy fallback for rows minted before `session_id` existed.
|
|
24
|
+
* `sessions.login_session_id` records only the session's *originating*
|
|
25
|
+
* authorization transaction and is never repointed on SSO reuse, so on its
|
|
26
|
+
* own it misses every token minted during a later re-authorization. It is
|
|
27
|
+
* retained until pre-Stage-2 rows have aged out (#1259) and then dropped.
|
|
28
|
+
*
|
|
29
|
+
* Sequential rather than parallel because a row can match both predicates, and
|
|
30
|
+
* both adapters guard on `revoked_at IS NULL` — so the second sweep skips what
|
|
31
|
+
* the first already revoked instead of double-counting it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function revokeSessionRefreshTokens(data: DataAdapters, tenant_id: string, session: RevocableSession, revoked_at: string): Promise<number>;
|
|
@@ -10,9 +10,10 @@ import { Bindings, Variables } from "../types";
|
|
|
10
10
|
* dispatch post-event outbox messages. `users.rawCreate` is NOT decorated —
|
|
11
11
|
* commit paths call it directly to bypass the hook layer by design.
|
|
12
12
|
*
|
|
13
|
-
* `email` is lowercased on the way in so the
|
|
14
|
-
* (`preUserSignupHook`, the email→primary linking
|
|
15
|
-
* normalized value that will be stored. Hooks can assign
|
|
13
|
+
* `email` is normalized (trimmed and lowercased) on the way in so the
|
|
14
|
+
* pre-commit hooks and lookups (`preUserSignupHook`, the email→primary linking
|
|
15
|
+
* query) see the same normalized value that will be stored. Hooks can assign
|
|
16
|
+
* `email` themselves
|
|
16
17
|
* after this point, so the decorators normalize again just before their
|
|
17
18
|
* commit — see `createUserHooks` / `createUserUpdateHooks`.
|
|
18
19
|
*/
|