authhero 9.9.0 → 9.10.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.
- package/dist/assets/u/widget/index.esm.js +1 -1
- package/dist/authhero.cjs +537 -338
- package/dist/authhero.d.ts +297 -124
- package/dist/authhero.mjs +14879 -14098
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/authentication-flows/authorization-code.d.ts +2 -1
- package/dist/types/authentication-flows/client-credentials.d.ts +2 -1
- package/dist/types/authentication-flows/grant-tokens.d.ts +16 -0
- package/dist/types/authentication-flows/passwordless.d.ts +6 -5
- package/dist/types/authentication-flows/refresh-token.d.ts +2 -1
- package/dist/types/authentication-flows/token-exchange.d.ts +2 -1
- package/dist/types/helpers/client-assertion-replay.d.ts +21 -0
- package/dist/types/helpers/client-assertion.d.ts +24 -2
- package/dist/types/helpers/default-destinations.d.ts +7 -1
- package/dist/types/helpers/outbox-destinations/index.d.ts +1 -0
- package/dist/types/helpers/outbox-destinations/pipeline.d.ts +63 -0
- package/dist/types/helpers/outbox-relay.d.ts +3 -0
- package/dist/types/helpers/refresh-token-lifetime.d.ts +103 -0
- package/dist/types/helpers/reserved-claims.d.ts +64 -0
- package/dist/types/helpers/run-outbox-relay.d.ts +8 -0
- package/dist/types/hooks/addDataHooks.d.ts +4 -3
- package/dist/types/index.d.ts +134 -121
- package/dist/types/routes/auth-api/index.d.ts +16 -16
- package/dist/types/routes/auth-api/passwordless.d.ts +14 -14
- package/dist/types/routes/auth-api/register/index.d.ts +2 -2
- package/dist/types/routes/management-api/action-triggers.d.ts +0 -2
- package/dist/types/routes/management-api/actions.d.ts +0 -7
- package/dist/types/routes/management-api/authentication-methods.d.ts +1 -1
- package/dist/types/routes/management-api/branding.d.ts +9 -9
- package/dist/types/routes/management-api/clients.d.ts +8 -8
- 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/email-templates.d.ts +18 -18
- package/dist/types/routes/management-api/failed-events.d.ts +21 -1
- 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 +107 -96
- package/dist/types/routes/management-api/keys.d.ts +12 -12
- package/dist/types/routes/management-api/logs.d.ts +4 -4
- package/dist/types/routes/management-api/migration-sources.d.ts +6 -6
- 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 +11 -11
- package/dist/types/routes/management-api/users.d.ts +15 -15
- package/dist/types/routes/universal-login/common.d.ts +2 -2
- package/dist/types/routes/universal-login/flow-api.d.ts +8 -8
- 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/types/AuthHeroConfig.d.ts +27 -0
- package/dist/types/types/Bindings.d.ts +12 -0
- package/dist/types/types/OutboxMetrics.d.ts +47 -0
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/utils/email.d.ts +21 -9
- package/package.json +8 -8
|
@@ -3,6 +3,7 @@ import { z } from "@hono/zod-openapi";
|
|
|
3
3
|
import { Bindings, Variables } from "../types";
|
|
4
4
|
import { TokenResponse } from "@authhero/adapter-interfaces";
|
|
5
5
|
import { GrantFlowUserResult } from "src/types/GrantFlowResult";
|
|
6
|
+
import { EnrichedClient } from "../helpers/client";
|
|
6
7
|
export declare const authorizationCodeGrantParamsSchema: z.ZodObject<{
|
|
7
8
|
grant_type: z.ZodLiteral<"authorization_code">;
|
|
8
9
|
client_id: z.ZodString;
|
|
@@ -16,7 +17,7 @@ export type AuthorizationCodeGrantTypeParams = z.infer<typeof authorizationCodeG
|
|
|
16
17
|
export declare function authorizationCodeGrantUser(ctx: Context<{
|
|
17
18
|
Bindings: Bindings;
|
|
18
19
|
Variables: Variables;
|
|
19
|
-
}>, params: AuthorizationCodeGrantTypeParams): Promise<GrantFlowUserResult>;
|
|
20
|
+
}>, params: AuthorizationCodeGrantTypeParams, preloadedClient?: EnrichedClient): Promise<GrantFlowUserResult>;
|
|
20
21
|
export declare function authorizationCodeGrant(ctx: Context<{
|
|
21
22
|
Bindings: Bindings;
|
|
22
23
|
Variables: Variables;
|
|
@@ -2,6 +2,7 @@ import { Context } from "hono";
|
|
|
2
2
|
import { z } from "@hono/zod-openapi";
|
|
3
3
|
import { Bindings, Variables } from "../types";
|
|
4
4
|
import { GrantFlowResult } from "../types/GrantFlowResult";
|
|
5
|
+
import { EnrichedClient } from "../helpers/client";
|
|
5
6
|
export declare const clientCredentialGrantParamsSchema: z.ZodObject<{
|
|
6
7
|
grant_type: z.ZodLiteral<"client_credentials">;
|
|
7
8
|
scope: z.ZodOptional<z.ZodString>;
|
|
@@ -13,4 +14,4 @@ export declare const clientCredentialGrantParamsSchema: z.ZodObject<{
|
|
|
13
14
|
export declare function clientCredentialsGrant(ctx: Context<{
|
|
14
15
|
Bindings: Bindings;
|
|
15
16
|
Variables: Variables;
|
|
16
|
-
}>, params: z.infer<typeof clientCredentialGrantParamsSchema
|
|
17
|
+
}>, params: z.infer<typeof clientCredentialGrantParamsSchema>, preloadedClient?: EnrichedClient): Promise<GrantFlowResult>;
|
|
@@ -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,6 +1,7 @@
|
|
|
1
1
|
import { Context } from "hono";
|
|
2
2
|
import { z } from "@hono/zod-openapi";
|
|
3
3
|
import { Bindings, Variables } from "../types";
|
|
4
|
+
import { EnrichedClient } from "../helpers/client";
|
|
4
5
|
import { GrantFlowUserResult } from "../types/GrantFlowResult";
|
|
5
6
|
export declare const passwordlessGrantParamsSchema: z.ZodObject<{
|
|
6
7
|
client_id: z.ZodString;
|
|
@@ -45,7 +46,7 @@ export declare const passwordlessGrantParamsSchema: z.ZodObject<{
|
|
|
45
46
|
export declare function passwordlessGrantUser(ctx: Context<{
|
|
46
47
|
Bindings: Bindings;
|
|
47
48
|
Variables: Variables;
|
|
48
|
-
}>, { client_id, username, otp, scope, audience, authParams, enforceIpCheck, }: z.input<typeof passwordlessGrantParamsSchema
|
|
49
|
+
}>, { client_id, username, otp, scope, audience, authParams, enforceIpCheck, }: z.input<typeof passwordlessGrantParamsSchema>, preloadedClient?: EnrichedClient): Promise<{
|
|
49
50
|
user: {
|
|
50
51
|
connection: string;
|
|
51
52
|
email_verified: boolean;
|
|
@@ -474,7 +475,7 @@ export declare function passwordlessGrantUser(ctx: Context<{
|
|
|
474
475
|
custom_login_page_preview?: string | undefined;
|
|
475
476
|
form_template?: string | undefined;
|
|
476
477
|
addons?: Record<string, any> | undefined;
|
|
477
|
-
token_endpoint_auth_method?: "
|
|
478
|
+
token_endpoint_auth_method?: "client_secret_post" | "client_secret_basic" | "none" | "client_secret_jwt" | "private_key_jwt" | undefined;
|
|
478
479
|
client_metadata?: Record<string, string> | undefined;
|
|
479
480
|
hide_sign_up_disabled_error?: boolean | undefined;
|
|
480
481
|
mobile?: Record<string, any> | undefined;
|
|
@@ -557,8 +558,8 @@ export declare function passwordlessGrantUser(ctx: Context<{
|
|
|
557
558
|
} | undefined;
|
|
558
559
|
authenticated_at?: string | undefined;
|
|
559
560
|
};
|
|
560
|
-
connectionType: "
|
|
561
|
-
authConnection: "
|
|
561
|
+
connectionType: "email" | "username" | "sms";
|
|
562
|
+
authConnection: "email" | "username" | "sms";
|
|
562
563
|
session_id: string | undefined;
|
|
563
564
|
authParams: {
|
|
564
565
|
audience?: string | undefined;
|
|
@@ -612,7 +613,7 @@ export declare function passwordlessGrantUser(ctx: Context<{
|
|
|
612
613
|
export declare function passwordlessOtpGrant(ctx: Context<{
|
|
613
614
|
Bindings: Bindings;
|
|
614
615
|
Variables: Variables;
|
|
615
|
-
}>, params: z.input<typeof passwordlessGrantParamsSchema
|
|
616
|
+
}>, params: z.input<typeof passwordlessGrantParamsSchema>, preloadedClient?: EnrichedClient): Promise<GrantFlowUserResult>;
|
|
616
617
|
export declare function passwordlessGrant(ctx: Context<{
|
|
617
618
|
Bindings: Bindings;
|
|
618
619
|
Variables: Variables;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Context } from "hono";
|
|
2
2
|
import { Bindings, Variables, GrantFlowUserResult } from "../types";
|
|
3
3
|
import { z } from "@hono/zod-openapi";
|
|
4
|
+
import { EnrichedClient } from "../helpers/client";
|
|
4
5
|
export declare const refreshTokenParamsSchema: z.ZodObject<{
|
|
5
6
|
grant_type: z.ZodLiteral<"refresh_token">;
|
|
6
7
|
client_id: z.ZodString;
|
|
@@ -12,4 +13,4 @@ export declare const refreshTokenParamsSchema: z.ZodObject<{
|
|
|
12
13
|
export declare function refreshTokenGrant(ctx: Context<{
|
|
13
14
|
Bindings: Bindings;
|
|
14
15
|
Variables: Variables;
|
|
15
|
-
}>, params: z.infer<typeof refreshTokenParamsSchema
|
|
16
|
+
}>, params: z.infer<typeof refreshTokenParamsSchema>, preloadedClient?: EnrichedClient): Promise<GrantFlowUserResult>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Context } from "hono";
|
|
2
2
|
import { z } from "@hono/zod-openapi";
|
|
3
3
|
import { Bindings, Variables, GrantFlowUserResult } from "../types";
|
|
4
|
+
import { EnrichedClient } from "../helpers/client";
|
|
4
5
|
export declare const TOKEN_EXCHANGE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange";
|
|
5
6
|
export declare const tokenExchangeParamsSchema: z.ZodObject<{
|
|
6
7
|
grant_type: z.ZodLiteral<"urn:ietf:params:oauth:grant-type:token-exchange">;
|
|
@@ -16,4 +17,4 @@ export type TokenExchangeParams = z.infer<typeof tokenExchangeParamsSchema>;
|
|
|
16
17
|
export declare function tokenExchangeGrant(ctx: Context<{
|
|
17
18
|
Bindings: Bindings;
|
|
18
19
|
Variables: Variables;
|
|
19
|
-
}>, params: TokenExchangeParams): Promise<GrantFlowUserResult>;
|
|
20
|
+
}>, params: TokenExchangeParams, preloadedClient?: EnrichedClient): Promise<GrantFlowUserResult>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Context } from "hono";
|
|
2
|
+
import { Bindings, Variables } from "../types";
|
|
3
|
+
export interface ConsumeClientAssertionJtiParams {
|
|
4
|
+
clientId: string;
|
|
5
|
+
/** The assertion's `jti`. When absent there is nothing to spend. */
|
|
6
|
+
jti?: string;
|
|
7
|
+
/** The assertion's `exp`, in seconds — when the marker becomes collectable. */
|
|
8
|
+
exp: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Spend a client assertion's `jti`.
|
|
12
|
+
*
|
|
13
|
+
* @returns false when this assertion has already been presented (the caller
|
|
14
|
+
* must reject it as `invalid_client`), true otherwise. An assertion carrying
|
|
15
|
+
* no `jti` cannot be tracked, so it returns true — its replay window is
|
|
16
|
+
* bounded only by the assertion lifetime cap.
|
|
17
|
+
*/
|
|
18
|
+
export declare function consumeClientAssertionJti(ctx: Context<{
|
|
19
|
+
Bindings: Bindings;
|
|
20
|
+
Variables: Variables;
|
|
21
|
+
}>, tenantId: string, params: ConsumeClientAssertionJtiParams): Promise<boolean>;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { LoadClientKeysOptions, ClientWithKeys } from "./client-keys";
|
|
2
2
|
declare const ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
|
|
3
|
+
/**
|
|
4
|
+
* Default upper bound on a client assertion's lifetime. RFC 7523 gives no
|
|
5
|
+
* limit, so without one a client can mint an assertion valid for a year and a
|
|
6
|
+
* captured assertion stays usable for that whole window. 300s matches the
|
|
7
|
+
* usual guidance for a single-use token presented directly to the endpoint.
|
|
8
|
+
*/
|
|
9
|
+
declare const DEFAULT_MAX_LIFETIME_SECONDS = 300;
|
|
3
10
|
export type ClientAssertionMethod = "private_key_jwt" | "client_secret_jwt";
|
|
4
11
|
export declare class ClientAssertionError extends Error {
|
|
5
12
|
code: "invalid_client" | "invalid_request" | "unsupported_alg" | "missing_keys";
|
|
@@ -18,6 +25,14 @@ export interface VerifyClientAssertionOptions extends LoadClientKeysOptions {
|
|
|
18
25
|
acceptedAudiences: string[];
|
|
19
26
|
/** Clock-skew leeway in seconds. Defaults to 30. */
|
|
20
27
|
leewaySeconds?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Maximum accepted assertion lifetime in seconds. Rejects an assertion whose
|
|
30
|
+
* `exp - iat` exceeds this, and caps the absolute `exp` at `now + max` so an
|
|
31
|
+
* assertion that omits `iat` cannot sidestep the bound. Defaults to
|
|
32
|
+
* DEFAULT_MAX_LIFETIME_SECONDS (300) — the window a captured assertion stays
|
|
33
|
+
* replayable in is bounded by this, so keep it short.
|
|
34
|
+
*/
|
|
35
|
+
maxLifetimeSeconds?: number;
|
|
21
36
|
/** Override Date.now() for tests. */
|
|
22
37
|
now?: () => number;
|
|
23
38
|
}
|
|
@@ -26,8 +41,15 @@ export interface VerifiedClientAssertion {
|
|
|
26
41
|
clientId: string;
|
|
27
42
|
/** Which authentication method was actually used. */
|
|
28
43
|
method: ClientAssertionMethod;
|
|
29
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* The `jti` claim, when present. `consumeClientAssertionJti`
|
|
46
|
+
* (helpers/client-assertion-replay.ts) spends it so an assertion cannot be
|
|
47
|
+
* presented twice; the token endpoint calls that after this verifier
|
|
48
|
+
* returns.
|
|
49
|
+
*/
|
|
30
50
|
jti?: string;
|
|
51
|
+
/** The `exp` claim, in seconds. Bounds how long the `jti` must be remembered. */
|
|
52
|
+
exp: number;
|
|
31
53
|
/** The full verified payload, in case callers need other claims. */
|
|
32
54
|
payload: Record<string, unknown>;
|
|
33
55
|
}
|
|
@@ -46,4 +68,4 @@ export interface VerifiedClientAssertion {
|
|
|
46
68
|
* any of the iss/sub/aud/exp checks.
|
|
47
69
|
*/
|
|
48
70
|
export declare function verifyClientAssertion(assertion: string, client: ClientAssertionClient, opts: VerifyClientAssertionOptions): Promise<VerifiedClientAssertion>;
|
|
49
|
-
export { ASSERTION_TYPE as CLIENT_ASSERTION_TYPE };
|
|
71
|
+
export { ASSERTION_TYPE as CLIENT_ASSERTION_TYPE, DEFAULT_MAX_LIFETIME_SECONDS as CLIENT_ASSERTION_DEFAULT_MAX_LIFETIME_SECONDS, };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CodeExecutor, DataAdapters } from "@authhero/adapter-interfaces";
|
|
2
2
|
import { EventDestination } from "./outbox-relay";
|
|
3
3
|
import { type GetServiceToken } from "./outbox-destinations/webhooks";
|
|
4
|
-
import type { WebhookInvoker } from "../types/AuthHeroConfig";
|
|
4
|
+
import type { OutboxPipelineConfig, WebhookInvoker } from "../types/AuthHeroConfig";
|
|
5
5
|
export interface CreateDefaultDestinationsConfig {
|
|
6
6
|
/**
|
|
7
7
|
* Data adapter — the `logs`, `hooks`, `users`, and `logStreams` adapters are
|
|
@@ -47,6 +47,12 @@ export interface CreateDefaultDestinationsConfig {
|
|
|
47
47
|
* failed per-request delivery would be silently skipped on retry.
|
|
48
48
|
*/
|
|
49
49
|
codeExecutor?: CodeExecutor;
|
|
50
|
+
/**
|
|
51
|
+
* Same shape as `init({ outbox: { pipeline } })`. When set, cron-drained
|
|
52
|
+
* events are also archived to the Cloudflare Pipelines stream, matching the
|
|
53
|
+
* per-request destination list. Omit to leave the archive out entirely.
|
|
54
|
+
*/
|
|
55
|
+
pipeline?: OutboxPipelineConfig;
|
|
50
56
|
}
|
|
51
57
|
/**
|
|
52
58
|
* Build the same array of outbox destinations that authhero's per-request
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { AuditEvent, AuditCategory } from "@authhero/adapter-interfaces";
|
|
2
|
+
import { EventDestination } from "../outbox-relay";
|
|
3
|
+
/**
|
|
4
|
+
* One row of the archive table. The promoted columns are the query and
|
|
5
|
+
* erasure keys (`actor_id` / `target_id`); `event` carries the untouched
|
|
6
|
+
* `AuditEvent` so nothing is lost and the promoted set can grow later
|
|
7
|
+
* without a backfill.
|
|
8
|
+
*
|
|
9
|
+
* `actor_id` is emitted as `null` rather than omitted when the actor is
|
|
10
|
+
* anonymous, so every record has the same key set — Pipelines stream
|
|
11
|
+
* schemas are fixed once created.
|
|
12
|
+
*/
|
|
13
|
+
export interface PipelineRecord {
|
|
14
|
+
id: string;
|
|
15
|
+
timestamp: string;
|
|
16
|
+
tenant_id: string;
|
|
17
|
+
event_type: string;
|
|
18
|
+
log_type: string;
|
|
19
|
+
category: AuditCategory;
|
|
20
|
+
actor_id: string | null;
|
|
21
|
+
target_type: string;
|
|
22
|
+
target_id: string;
|
|
23
|
+
event: AuditEvent;
|
|
24
|
+
}
|
|
25
|
+
export interface PipelineDestinationOptions {
|
|
26
|
+
/** Stream HTTP ingest endpoint, e.g. `https://<stream-id>.ingest.cloudflare.com`. */
|
|
27
|
+
endpoint: string;
|
|
28
|
+
/** Stream ingest token, sent as `Authorization: Bearer`. */
|
|
29
|
+
token: string;
|
|
30
|
+
/** Per-request timeout (default: 10s). */
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
/** Override for tests. */
|
|
33
|
+
fetchImpl?: typeof fetch;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Archives audit events to a Cloudflare Pipelines stream, which lands them in
|
|
37
|
+
* R2 as an Iceberg table. See `apps/docs/architecture/audit-archive.md`.
|
|
38
|
+
*
|
|
39
|
+
* HTTP ingest is used rather than the Worker binding so the destination works
|
|
40
|
+
* in every deployment (Node included) and stays symmetric with the
|
|
41
|
+
* log-streams destination.
|
|
42
|
+
*
|
|
43
|
+
* Duplicates are expected and by design: the relay retries per event, not per
|
|
44
|
+
* destination, so a failure in a later destination re-delivers this one, and
|
|
45
|
+
* the Iceberg sink is append-only. Consumers dedup on `id` at query time.
|
|
46
|
+
*/
|
|
47
|
+
export declare class PipelineDestination implements EventDestination {
|
|
48
|
+
name: string;
|
|
49
|
+
private endpoint;
|
|
50
|
+
private token;
|
|
51
|
+
private timeoutMs;
|
|
52
|
+
private fetchImpl;
|
|
53
|
+
constructor(options: PipelineDestinationOptions);
|
|
54
|
+
/**
|
|
55
|
+
* Archives the audit trail, not the delivery plumbing: `hook.*` and
|
|
56
|
+
* `controlplane.sync.*` are instructions to other destinations rather than
|
|
57
|
+
* records of something a tenant did. Same filter as the log-streams
|
|
58
|
+
* destination.
|
|
59
|
+
*/
|
|
60
|
+
accepts(event: AuditEvent): boolean;
|
|
61
|
+
transform(event: AuditEvent): PipelineRecord;
|
|
62
|
+
deliver(records: PipelineRecord[]): Promise<void>;
|
|
63
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { OutboxAdapter, AuditEvent } from "@authhero/adapter-interfaces";
|
|
2
|
+
import type { OutboxMetricsSink } from "../types/OutboxMetrics";
|
|
2
3
|
/**
|
|
3
4
|
* Interface for outbox event destinations.
|
|
4
5
|
* Each destination transforms audit events into its own format and delivers them.
|
|
@@ -21,6 +22,7 @@ export interface EventDestination {
|
|
|
21
22
|
*/
|
|
22
23
|
export declare function processOutboxEvents(outbox: OutboxAdapter, ids: string[], destinations: EventDestination[], options?: {
|
|
23
24
|
maxRetries?: number;
|
|
25
|
+
metrics?: OutboxMetricsSink;
|
|
24
26
|
}): Promise<void>;
|
|
25
27
|
/**
|
|
26
28
|
* Drain unprocessed events from the outbox and deliver to all destinations.
|
|
@@ -31,4 +33,5 @@ export declare function drainOutbox(outbox: OutboxAdapter, destinations: EventDe
|
|
|
31
33
|
batchSize?: number;
|
|
32
34
|
maxRetries?: number;
|
|
33
35
|
retentionDays?: number;
|
|
36
|
+
metrics?: OutboxMetricsSink;
|
|
34
37
|
}): Promise<void>;
|
|
@@ -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,64 @@
|
|
|
1
|
+
import { Context } from "hono";
|
|
2
|
+
import { Bindings, Variables } from "../types";
|
|
3
|
+
/** RFC 9068 §2.2 + AuthHero-owned access-token claims. */
|
|
4
|
+
export declare const ACCESS_TOKEN_RESERVED_CLAIMS: readonly ["iss", "sub", "aud", "exp", "nbf", "iat", "jti", "client_id", "azp", "scope", "auth_time", "acr", "amr", "act", "sid", "permissions", "tenant_id", "org_id", "org_name", "requested_userinfo_claims", "gty"];
|
|
5
|
+
/** OIDC Core ID-token claims: the access-token set plus the ID-token-only ones. */
|
|
6
|
+
export declare const ID_TOKEN_RESERVED_CLAIMS: readonly ["iss", "sub", "aud", "exp", "nbf", "iat", "jti", "client_id", "azp", "scope", "auth_time", "acr", "amr", "act", "sid", "permissions", "tenant_id", "org_id", "org_name", "requested_userinfo_claims", "gty", "nonce", "at_hash", "c_hash", "s_hash"];
|
|
7
|
+
/**
|
|
8
|
+
* /userinfo response. The identity set only — the response body is otherwise
|
|
9
|
+
* made up of user profile claims, which hooks are expected to extend.
|
|
10
|
+
*/
|
|
11
|
+
export declare const USERINFO_RESERVED_CLAIMS: readonly ["iss", "sub", "aud", "exp", "nbf", "iat", "jti"];
|
|
12
|
+
/**
|
|
13
|
+
* Internal `auth-service` mints. Same set as an access token except `azp`:
|
|
14
|
+
* trusted internal hook code overrides it to attribute the call to a
|
|
15
|
+
* vendor/tenant for downstream APIs while `sub` stays `auth-service`.
|
|
16
|
+
* Client-bound mints keep `azp` locked (see below).
|
|
17
|
+
*/
|
|
18
|
+
export declare const SERVICE_TOKEN_RESERVED_CLAIMS: ("client_id" | "scope" | "sid" | "tenant_id" | "org_id" | "org_name" | "sub" | "permissions" | "iat" | "exp" | "iss" | "aud" | "auth_time" | "acr" | "amr" | "nbf" | "jti" | "act" | "requested_userinfo_claims" | "gty")[];
|
|
19
|
+
/** Client-bound mints: `azp` must stay the registered client id. */
|
|
20
|
+
export declare const CLIENT_SERVICE_TOKEN_RESERVED_CLAIMS: ("client_id" | "scope" | "sid" | "tenant_id" | "org_id" | "org_name" | "sub" | "permissions" | "iat" | "exp" | "iss" | "aud" | "auth_time" | "acr" | "amr" | "azp" | "nbf" | "jti" | "act" | "requested_userinfo_claims" | "gty")[];
|
|
21
|
+
export type AccessTokenReservedClaim = (typeof ACCESS_TOKEN_RESERVED_CLAIMS)[number];
|
|
22
|
+
export type IdTokenReservedClaim = (typeof ID_TOKEN_RESERVED_CLAIMS)[number];
|
|
23
|
+
/**
|
|
24
|
+
* The server-owned half of an access-token payload. Typing the payload literal
|
|
25
|
+
* as this makes TypeScript's excess-property check reject any claim name that
|
|
26
|
+
* isn't in `ACCESS_TOKEN_RESERVED_CLAIMS`, so a new server-owned claim cannot
|
|
27
|
+
* be added to the mint without also being reserved.
|
|
28
|
+
*/
|
|
29
|
+
export type ServerOwnedAccessTokenClaims = Partial<Record<AccessTokenReservedClaim, unknown>>;
|
|
30
|
+
/** As `ServerOwnedAccessTokenClaims`, for the ID token. */
|
|
31
|
+
export type ServerOwnedIdTokenClaims = Partial<Record<IdTokenReservedClaim, unknown>>;
|
|
32
|
+
/** Which payload a custom claim is being written to. */
|
|
33
|
+
export type ClaimPayloadKind = "access_token" | "id_token" | "userinfo" | "service_token" | "client_service_token";
|
|
34
|
+
export declare function isReservedClaim(claim: string, kind: ClaimPayloadKind): boolean;
|
|
35
|
+
export interface ApplyCustomClaimOptions {
|
|
36
|
+
/** Which payload is being written to — selects the reserved set. */
|
|
37
|
+
kind: ClaimPayloadKind;
|
|
38
|
+
/**
|
|
39
|
+
* Who is writing. Used in the warning so an operator can tell which hook
|
|
40
|
+
* dropped a claim (e.g. `onExecuteCredentialsExchange`,
|
|
41
|
+
* `template-hook:add-roles`, `createServiceToken`).
|
|
42
|
+
*/
|
|
43
|
+
source: string;
|
|
44
|
+
/** Request context, when there is one — the warning goes to the tenant log. */
|
|
45
|
+
ctx?: Context<{
|
|
46
|
+
Bindings: Bindings;
|
|
47
|
+
Variables: Variables;
|
|
48
|
+
}>;
|
|
49
|
+
/** Tenant to log against. Defaults to `ctx.var.tenant_id`. */
|
|
50
|
+
tenantId?: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Write a caller-supplied claim onto a payload unless the authorization server
|
|
54
|
+
* owns that claim name.
|
|
55
|
+
*
|
|
56
|
+
* @returns true when the claim was written, false when it was dropped.
|
|
57
|
+
*/
|
|
58
|
+
export declare function applyCustomClaim(payload: Record<string, unknown>, claim: string, value: unknown, options: ApplyCustomClaimOptions): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Bulk variant of `applyCustomClaim`. Returns a new object holding only the
|
|
61
|
+
* claims that are safe to merge, so callers can keep spreading them into a
|
|
62
|
+
* payload literal.
|
|
63
|
+
*/
|
|
64
|
+
export declare function applyCustomClaims(claims: Record<string, unknown> | undefined, options: ApplyCustomClaimOptions): Record<string, unknown> | undefined;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CodeExecutor, DataAdapters } from "@authhero/adapter-interfaces";
|
|
2
2
|
import type { WebhookInvoker } from "../types/AuthHeroConfig";
|
|
3
|
+
import type { OutboxMetricsSink } from "../types/OutboxMetrics";
|
|
3
4
|
export interface RunOutboxRelayConfig {
|
|
4
5
|
/** Same `DataAdapters` passed to `init()`. Must include `outbox` to drain. */
|
|
5
6
|
dataAdapter: DataAdapters;
|
|
@@ -31,6 +32,13 @@ export interface RunOutboxRelayConfig {
|
|
|
31
32
|
* silently skipped.
|
|
32
33
|
*/
|
|
33
34
|
codeExecutor?: CodeExecutor;
|
|
35
|
+
/**
|
|
36
|
+
* Optional metrics sink — same shape as `init({ outbox: { metrics } })`.
|
|
37
|
+
* Receives `outbox_events_processed_total`,
|
|
38
|
+
* `outbox_events_dead_lettered_total` and `outbox_retry_delay_seconds` for
|
|
39
|
+
* the events this cron drain handles, tagged `source: "cron"`.
|
|
40
|
+
*/
|
|
41
|
+
metrics?: OutboxMetricsSink;
|
|
34
42
|
}
|
|
35
43
|
/**
|
|
36
44
|
* One-call outbox relay for cron / scheduled handlers.
|
|
@@ -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
|
*/
|