@_mustachio/openauth 0.9.2 → 0.11.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/esm/adapters/d1/audit-log.js +15 -0
- package/dist/esm/adapters/d1/config-store.js +45 -0
- package/dist/esm/adapters/d1/index.js +12 -0
- package/dist/esm/adapters/d1/key-store.js +116 -0
- package/dist/esm/adapters/d1/method-store.js +52 -0
- package/dist/esm/adapters/d1/migrations.js +77 -0
- package/dist/esm/adapters/d1/session-store.js +134 -0
- package/dist/esm/adapters/d1/session.js +18 -0
- package/dist/esm/adapters/d1/token-store.js +140 -0
- package/dist/esm/adapters/durable-object/index.js +3 -0
- package/dist/esm/adapters/durable-object/session-store.js +139 -0
- package/dist/esm/adapters/durable-object/types.js +0 -0
- package/dist/esm/adapters/dynamo/audit-log.js +23 -0
- package/dist/esm/adapters/dynamo/client.js +0 -0
- package/dist/esm/adapters/dynamo/config-store.js +57 -0
- package/dist/esm/adapters/dynamo/index.js +10 -0
- package/dist/esm/adapters/dynamo/key-store.js +188 -0
- package/dist/esm/adapters/dynamo/method-store.js +72 -0
- package/dist/esm/adapters/dynamo/passkey-credential-store.js +83 -0
- package/dist/esm/adapters/dynamo/sdk.js +128 -0
- package/dist/esm/adapters/dynamo/session-store.js +173 -0
- package/dist/esm/adapters/dynamo/token-store.js +178 -0
- package/dist/esm/adapters/kms/in-memory-backing.js +28 -0
- package/dist/esm/adapters/kms/index.js +5 -0
- package/dist/esm/adapters/kms/key-store.js +129 -0
- package/dist/esm/adapters/kms/sdk.js +23 -0
- package/dist/esm/adapters/kms/types.js +0 -0
- package/dist/esm/adapters/kv/audit-log.js +21 -0
- package/dist/esm/adapters/kv/config-store.js +43 -0
- package/dist/esm/adapters/kv/index.js +5 -0
- package/dist/esm/adapters/kv/method-store.js +63 -0
- package/dist/esm/adapters/kv/types.js +0 -0
- package/dist/esm/adapters/memory/audit-log.js +16 -0
- package/dist/esm/adapters/memory/clock.js +5 -0
- package/dist/esm/adapters/memory/config-store.js +31 -0
- package/dist/esm/adapters/memory/index.js +10 -0
- package/dist/esm/adapters/memory/key-store.js +78 -0
- package/dist/esm/adapters/memory/method-store.js +43 -0
- package/dist/esm/adapters/memory/passkey-credential-store.js +53 -0
- package/dist/esm/adapters/memory/session-store.js +104 -0
- package/dist/esm/adapters/memory/token-store.js +104 -0
- package/dist/esm/adapters/postgres/audit-log.js +16 -0
- package/dist/esm/adapters/postgres/config-store.js +48 -0
- package/dist/esm/adapters/postgres/executor.js +21 -0
- package/dist/esm/adapters/postgres/index.js +13 -0
- package/dist/esm/adapters/postgres/key-store.js +191 -0
- package/dist/esm/adapters/postgres/method-store.js +61 -0
- package/dist/esm/adapters/postgres/migrations.js +111 -0
- package/dist/esm/adapters/postgres/passkey-credential-store.js +80 -0
- package/dist/esm/adapters/postgres/session-store.js +135 -0
- package/dist/esm/adapters/postgres/token-store.js +151 -0
- package/dist/esm/client.js +35 -12
- package/dist/esm/domain/audit.js +13 -0
- package/dist/esm/domain/authorize.js +217 -0
- package/dist/esm/domain/callback.js +176 -0
- package/dist/esm/domain/client-auth.js +61 -0
- package/dist/esm/domain/client-credentials.js +91 -0
- package/dist/esm/domain/crypto.js +97 -0
- package/dist/esm/domain/discovery.js +83 -0
- package/dist/esm/domain/dpop.js +122 -0
- package/dist/esm/domain/id-token.js +94 -0
- package/dist/esm/domain/introspect.js +55 -0
- package/dist/esm/domain/jwt.js +71 -0
- package/dist/esm/domain/logout.js +75 -0
- package/dist/esm/domain/method-cache.js +136 -0
- package/dist/esm/domain/method-dispatch.js +36 -0
- package/dist/esm/domain/method-route.js +111 -0
- package/dist/esm/domain/par.js +51 -0
- package/dist/esm/domain/pkce.js +16 -0
- package/dist/esm/domain/refresh.js +102 -0
- package/dist/esm/domain/register.js +74 -0
- package/dist/esm/domain/revoke.js +81 -0
- package/dist/esm/domain/state-envelope.js +80 -0
- package/dist/esm/domain/token-exchange.js +102 -0
- package/dist/esm/domain/token.js +246 -0
- package/dist/esm/domain/userinfo.js +62 -0
- package/dist/esm/http/context.js +7 -0
- package/dist/esm/http/cookies.js +98 -0
- package/dist/esm/http/errors.js +71 -0
- package/dist/esm/http/handlers/authorize.js +250 -0
- package/dist/esm/http/handlers/callback.js +53 -0
- package/dist/esm/http/handlers/end-session.js +64 -0
- package/dist/esm/http/handlers/metadata.js +37 -0
- package/dist/esm/http/handlers/method-route.js +87 -0
- package/dist/esm/http/handlers/par.js +53 -0
- package/dist/esm/http/handlers/register.js +46 -0
- package/dist/esm/http/handlers/revocation.js +98 -0
- package/dist/esm/http/handlers/token.js +197 -0
- package/dist/esm/http/handlers/userinfo.js +60 -0
- package/dist/esm/http/middleware/error.js +15 -0
- package/dist/esm/http/middleware/tenant.js +102 -0
- package/dist/esm/http/resolver.js +15 -0
- package/dist/esm/http/router.js +45 -0
- package/dist/esm/http/schemas/authorize.js +30 -0
- package/dist/esm/http/schemas/end-session.js +13 -0
- package/dist/esm/http/schemas/par.js +9 -0
- package/dist/esm/http/schemas/register.js +16 -0
- package/dist/esm/http/schemas/revocation.js +18 -0
- package/dist/esm/http/schemas/token.js +57 -0
- package/dist/esm/index.js +126 -9
- package/dist/esm/methods/code.js +221 -0
- package/dist/esm/methods/m2m.js +41 -0
- package/dist/esm/methods/oauth2-factory.js +84 -0
- package/dist/esm/methods/oauth2-generic.js +196 -0
- package/dist/esm/methods/oidc-generic.js +53 -0
- package/dist/esm/methods/passkey.js +275 -0
- package/dist/esm/methods/password-hash.js +79 -0
- package/dist/esm/methods/password.js +166 -0
- package/dist/esm/methods/providers/apple.js +29 -0
- package/dist/esm/methods/providers/cognito.js +37 -0
- package/dist/esm/methods/providers/discord.js +28 -0
- package/dist/esm/methods/providers/facebook.js +42 -0
- package/dist/esm/methods/providers/github.js +29 -0
- package/dist/esm/methods/providers/google.js +29 -0
- package/dist/esm/methods/providers/index.js +17 -0
- package/dist/esm/methods/providers/jumpcloud.js +27 -0
- package/dist/esm/methods/providers/keycloak.js +32 -0
- package/dist/esm/methods/providers/linkedin.js +28 -0
- package/dist/esm/methods/providers/microsoft.js +28 -0
- package/dist/esm/methods/providers/slack.js +30 -0
- package/dist/esm/methods/providers/spotify.js +28 -0
- package/dist/esm/methods/providers/twitch.js +28 -0
- package/dist/esm/methods/providers/x.js +28 -0
- package/dist/esm/methods/providers/yahoo.js +27 -0
- package/dist/esm/pkce.js +4 -16
- package/dist/esm/ports/audit-log.js +0 -0
- package/dist/esm/ports/config-store.js +0 -0
- package/dist/esm/ports/key-store.js +0 -0
- package/dist/esm/ports/method-store.js +0 -0
- package/dist/esm/ports/session-store.js +0 -0
- package/dist/esm/ports/token-store.js +0 -0
- package/dist/esm/types/authorization.js +0 -0
- package/dist/esm/types/error.js +70 -0
- package/dist/esm/types/flow.js +0 -0
- package/dist/esm/types/idp.js +0 -0
- package/dist/esm/types/method.js +0 -0
- package/dist/esm/types/picker.js +0 -0
- package/dist/esm/types/result.js +11 -0
- package/dist/esm/types/subject.js +0 -0
- package/dist/esm/types/tenant.js +5 -0
- package/dist/esm/types/token.js +0 -0
- package/dist/esm/ui/forms.js +253 -0
- package/dist/esm/ui/index.js +8 -0
- package/dist/esm/ui/picker.js +49 -0
- package/dist/types/adapters/d1/audit-log.d.ts +19 -0
- package/dist/types/adapters/d1/audit-log.d.ts.map +1 -0
- package/dist/types/adapters/d1/config-store.d.ts +20 -0
- package/dist/types/adapters/d1/config-store.d.ts.map +1 -0
- package/dist/types/adapters/d1/index.d.ts +35 -0
- package/dist/types/adapters/d1/index.d.ts.map +1 -0
- package/dist/types/adapters/d1/key-store.d.ts +17 -0
- package/dist/types/adapters/d1/key-store.d.ts.map +1 -0
- package/dist/types/adapters/d1/method-store.d.ts +21 -0
- package/dist/types/adapters/d1/method-store.d.ts.map +1 -0
- package/dist/types/adapters/d1/migrations.d.ts +18 -0
- package/dist/types/adapters/d1/migrations.d.ts.map +1 -0
- package/dist/types/adapters/d1/session-store.d.ts +20 -0
- package/dist/types/adapters/d1/session-store.d.ts.map +1 -0
- package/dist/types/adapters/d1/session.d.ts +18 -0
- package/dist/types/adapters/d1/session.d.ts.map +1 -0
- package/dist/types/adapters/d1/token-store.d.ts +29 -0
- package/dist/types/adapters/d1/token-store.d.ts.map +1 -0
- package/dist/types/adapters/d1/types.d.ts +43 -0
- package/dist/types/adapters/d1/types.d.ts.map +1 -0
- package/dist/types/adapters/durable-object/index.d.ts +17 -0
- package/dist/types/adapters/durable-object/index.d.ts.map +1 -0
- package/dist/types/adapters/durable-object/session-store.d.ts +21 -0
- package/dist/types/adapters/durable-object/session-store.d.ts.map +1 -0
- package/dist/types/adapters/durable-object/types.d.ts +23 -0
- package/dist/types/adapters/durable-object/types.d.ts.map +1 -0
- package/dist/types/adapters/dynamo/audit-log.d.ts +19 -0
- package/dist/types/adapters/dynamo/audit-log.d.ts.map +1 -0
- package/dist/types/adapters/dynamo/client.d.ts +111 -0
- package/dist/types/adapters/dynamo/client.d.ts.map +1 -0
- package/dist/types/adapters/dynamo/config-store.d.ts +21 -0
- package/dist/types/adapters/dynamo/config-store.d.ts.map +1 -0
- package/dist/types/adapters/dynamo/index.d.ts +60 -0
- package/dist/types/adapters/dynamo/index.d.ts.map +1 -0
- package/dist/types/adapters/dynamo/key-store.d.ts +23 -0
- package/dist/types/adapters/dynamo/key-store.d.ts.map +1 -0
- package/dist/types/adapters/dynamo/method-store.d.ts +20 -0
- package/dist/types/adapters/dynamo/method-store.d.ts.map +1 -0
- package/dist/types/adapters/dynamo/passkey-credential-store.d.ts +47 -0
- package/dist/types/adapters/dynamo/passkey-credential-store.d.ts.map +1 -0
- package/dist/types/adapters/dynamo/sdk.d.ts +23 -0
- package/dist/types/adapters/dynamo/sdk.d.ts.map +1 -0
- package/dist/types/adapters/dynamo/session-store.d.ts +20 -0
- package/dist/types/adapters/dynamo/session-store.d.ts.map +1 -0
- package/dist/types/adapters/dynamo/token-store.d.ts +29 -0
- package/dist/types/adapters/dynamo/token-store.d.ts.map +1 -0
- package/dist/types/adapters/kms/in-memory-backing.d.ts +9 -0
- package/dist/types/adapters/kms/in-memory-backing.d.ts.map +1 -0
- package/dist/types/adapters/kms/index.d.ts +35 -0
- package/dist/types/adapters/kms/index.d.ts.map +1 -0
- package/dist/types/adapters/kms/key-store.d.ts +20 -0
- package/dist/types/adapters/kms/key-store.d.ts.map +1 -0
- package/dist/types/adapters/kms/sdk.d.ts +16 -0
- package/dist/types/adapters/kms/sdk.d.ts.map +1 -0
- package/dist/types/adapters/kms/types.d.ts +58 -0
- package/dist/types/adapters/kms/types.d.ts.map +1 -0
- package/dist/types/adapters/kv/audit-log.d.ts +22 -0
- package/dist/types/adapters/kv/audit-log.d.ts.map +1 -0
- package/dist/types/adapters/kv/config-store.d.ts +25 -0
- package/dist/types/adapters/kv/config-store.d.ts.map +1 -0
- package/dist/types/adapters/kv/index.d.ts +21 -0
- package/dist/types/adapters/kv/index.d.ts.map +1 -0
- package/dist/types/adapters/kv/method-store.d.ts +23 -0
- package/dist/types/adapters/kv/method-store.d.ts.map +1 -0
- package/dist/types/adapters/kv/types.d.ts +28 -0
- package/dist/types/adapters/kv/types.d.ts.map +1 -0
- package/dist/types/adapters/memory/audit-log.d.ts +18 -0
- package/dist/types/adapters/memory/audit-log.d.ts.map +1 -0
- package/dist/types/adapters/memory/clock.d.ts +7 -0
- package/dist/types/adapters/memory/clock.d.ts.map +1 -0
- package/dist/types/adapters/memory/config-store.d.ts +19 -0
- package/dist/types/adapters/memory/config-store.d.ts.map +1 -0
- package/dist/types/adapters/memory/index.d.ts +15 -0
- package/dist/types/adapters/memory/index.d.ts.map +1 -0
- package/dist/types/adapters/memory/key-store.d.ts +17 -0
- package/dist/types/adapters/memory/key-store.d.ts.map +1 -0
- package/dist/types/adapters/memory/method-store.d.ts +26 -0
- package/dist/types/adapters/memory/method-store.d.ts.map +1 -0
- package/dist/types/adapters/memory/passkey-credential-store.d.ts +43 -0
- package/dist/types/adapters/memory/passkey-credential-store.d.ts.map +1 -0
- package/dist/types/adapters/memory/session-store.d.ts +21 -0
- package/dist/types/adapters/memory/session-store.d.ts.map +1 -0
- package/dist/types/adapters/memory/token-store.d.ts +29 -0
- package/dist/types/adapters/memory/token-store.d.ts.map +1 -0
- package/dist/types/adapters/postgres/audit-log.d.ts +18 -0
- package/dist/types/adapters/postgres/audit-log.d.ts.map +1 -0
- package/dist/types/adapters/postgres/config-store.d.ts +21 -0
- package/dist/types/adapters/postgres/config-store.d.ts.map +1 -0
- package/dist/types/adapters/postgres/executor.d.ts +48 -0
- package/dist/types/adapters/postgres/executor.d.ts.map +1 -0
- package/dist/types/adapters/postgres/index.d.ts +39 -0
- package/dist/types/adapters/postgres/index.d.ts.map +1 -0
- package/dist/types/adapters/postgres/key-store.d.ts +23 -0
- package/dist/types/adapters/postgres/key-store.d.ts.map +1 -0
- package/dist/types/adapters/postgres/method-store.d.ts +21 -0
- package/dist/types/adapters/postgres/method-store.d.ts.map +1 -0
- package/dist/types/adapters/postgres/migrations.d.ts +22 -0
- package/dist/types/adapters/postgres/migrations.d.ts.map +1 -0
- package/dist/types/adapters/postgres/passkey-credential-store.d.ts +48 -0
- package/dist/types/adapters/postgres/passkey-credential-store.d.ts.map +1 -0
- package/dist/types/adapters/postgres/session-store.d.ts +20 -0
- package/dist/types/adapters/postgres/session-store.d.ts.map +1 -0
- package/dist/types/adapters/postgres/token-store.d.ts +30 -0
- package/dist/types/adapters/postgres/token-store.d.ts.map +1 -0
- package/dist/types/client.d.ts +20 -1
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/domain/audit.d.ts +17 -0
- package/dist/types/domain/audit.d.ts.map +1 -0
- package/dist/types/domain/authorize.d.ts +125 -0
- package/dist/types/domain/authorize.d.ts.map +1 -0
- package/dist/types/domain/callback.d.ts +70 -0
- package/dist/types/domain/callback.d.ts.map +1 -0
- package/dist/types/domain/client-auth.d.ts +57 -0
- package/dist/types/domain/client-auth.d.ts.map +1 -0
- package/dist/types/domain/client-credentials.d.ts +54 -0
- package/dist/types/domain/client-credentials.d.ts.map +1 -0
- package/dist/types/domain/crypto.d.ts +53 -0
- package/dist/types/domain/crypto.d.ts.map +1 -0
- package/dist/types/domain/discovery.d.ts +81 -0
- package/dist/types/domain/discovery.d.ts.map +1 -0
- package/dist/types/domain/dpop.d.ts +61 -0
- package/dist/types/domain/dpop.d.ts.map +1 -0
- package/dist/types/domain/id-token.d.ts +83 -0
- package/dist/types/domain/id-token.d.ts.map +1 -0
- package/dist/types/domain/introspect.d.ts +79 -0
- package/dist/types/domain/introspect.d.ts.map +1 -0
- package/dist/types/domain/jwt.d.ts +74 -0
- package/dist/types/domain/jwt.d.ts.map +1 -0
- package/dist/types/domain/logout.d.ts +69 -0
- package/dist/types/domain/logout.d.ts.map +1 -0
- package/dist/types/domain/method-cache.d.ts +42 -0
- package/dist/types/domain/method-cache.d.ts.map +1 -0
- package/dist/types/domain/method-dispatch.d.ts +37 -0
- package/dist/types/domain/method-dispatch.d.ts.map +1 -0
- package/dist/types/domain/method-route.d.ts +77 -0
- package/dist/types/domain/method-route.d.ts.map +1 -0
- package/dist/types/domain/par.d.ts +62 -0
- package/dist/types/domain/par.d.ts.map +1 -0
- package/dist/types/domain/pkce.d.ts +15 -0
- package/dist/types/domain/pkce.d.ts.map +1 -0
- package/dist/types/domain/refresh.d.ts +52 -0
- package/dist/types/domain/refresh.d.ts.map +1 -0
- package/dist/types/domain/register.d.ts +33 -0
- package/dist/types/domain/register.d.ts.map +1 -0
- package/dist/types/domain/revoke.d.ts +61 -0
- package/dist/types/domain/revoke.d.ts.map +1 -0
- package/dist/types/domain/state-envelope.d.ts +30 -0
- package/dist/types/domain/state-envelope.d.ts.map +1 -0
- package/dist/types/domain/token-exchange.d.ts +69 -0
- package/dist/types/domain/token-exchange.d.ts.map +1 -0
- package/dist/types/domain/token.d.ts +140 -0
- package/dist/types/domain/token.d.ts.map +1 -0
- package/dist/types/domain/userinfo.d.ts +61 -0
- package/dist/types/domain/userinfo.d.ts.map +1 -0
- package/dist/types/http/context.d.ts +66 -0
- package/dist/types/http/context.d.ts.map +1 -0
- package/dist/types/http/cookies.d.ts +45 -0
- package/dist/types/http/cookies.d.ts.map +1 -0
- package/dist/types/http/errors.d.ts +36 -0
- package/dist/types/http/errors.d.ts.map +1 -0
- package/dist/types/http/handlers/authorize.d.ts +3 -0
- package/dist/types/http/handlers/authorize.d.ts.map +1 -0
- package/dist/types/http/handlers/callback.d.ts +3 -0
- package/dist/types/http/handlers/callback.d.ts.map +1 -0
- package/dist/types/http/handlers/end-session.d.ts +3 -0
- package/dist/types/http/handlers/end-session.d.ts.map +1 -0
- package/dist/types/http/handlers/metadata.d.ts +4 -0
- package/dist/types/http/handlers/metadata.d.ts.map +1 -0
- package/dist/types/http/handlers/method-route.d.ts +3 -0
- package/dist/types/http/handlers/method-route.d.ts.map +1 -0
- package/dist/types/http/handlers/par.d.ts +3 -0
- package/dist/types/http/handlers/par.d.ts.map +1 -0
- package/dist/types/http/handlers/register.d.ts +3 -0
- package/dist/types/http/handlers/register.d.ts.map +1 -0
- package/dist/types/http/handlers/revocation.d.ts +4 -0
- package/dist/types/http/handlers/revocation.d.ts.map +1 -0
- package/dist/types/http/handlers/token.d.ts +3 -0
- package/dist/types/http/handlers/token.d.ts.map +1 -0
- package/dist/types/http/handlers/userinfo.d.ts +3 -0
- package/dist/types/http/handlers/userinfo.d.ts.map +1 -0
- package/dist/types/http/middleware/error.d.ts +9 -0
- package/dist/types/http/middleware/error.d.ts.map +1 -0
- package/dist/types/http/middleware/tenant.d.ts +30 -0
- package/dist/types/http/middleware/tenant.d.ts.map +1 -0
- package/dist/types/http/resolver.d.ts +22 -0
- package/dist/types/http/resolver.d.ts.map +1 -0
- package/dist/types/http/router.d.ts +21 -0
- package/dist/types/http/router.d.ts.map +1 -0
- package/dist/types/http/schemas/authorize.d.ts +92 -0
- package/dist/types/http/schemas/authorize.d.ts.map +1 -0
- package/dist/types/http/schemas/end-session.d.ts +31 -0
- package/dist/types/http/schemas/end-session.d.ts.map +1 -0
- package/dist/types/http/schemas/par.d.ts +20 -0
- package/dist/types/http/schemas/par.d.ts.map +1 -0
- package/dist/types/http/schemas/register.d.ts +42 -0
- package/dist/types/http/schemas/register.d.ts.map +1 -0
- package/dist/types/http/schemas/revocation.d.ts +41 -0
- package/dist/types/http/schemas/revocation.d.ts.map +1 -0
- package/dist/types/http/schemas/token.d.ts +227 -0
- package/dist/types/http/schemas/token.d.ts.map +1 -0
- package/dist/types/index.d.ts +63 -13
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/methods/code.d.ts +96 -0
- package/dist/types/methods/code.d.ts.map +1 -0
- package/dist/types/methods/m2m.d.ts +41 -0
- package/dist/types/methods/m2m.d.ts.map +1 -0
- package/dist/types/methods/oauth2-factory.d.ts +133 -0
- package/dist/types/methods/oauth2-factory.d.ts.map +1 -0
- package/dist/types/methods/oauth2-generic.d.ts +75 -0
- package/dist/types/methods/oauth2-generic.d.ts.map +1 -0
- package/dist/types/methods/oidc-generic.d.ts +26 -0
- package/dist/types/methods/oidc-generic.d.ts.map +1 -0
- package/dist/types/methods/passkey.d.ts +106 -0
- package/dist/types/methods/passkey.d.ts.map +1 -0
- package/dist/types/methods/password-hash.d.ts +25 -0
- package/dist/types/methods/password-hash.d.ts.map +1 -0
- package/dist/types/methods/password.d.ts +70 -0
- package/dist/types/methods/password.d.ts.map +1 -0
- package/dist/types/methods/providers/apple.d.ts +29 -0
- package/dist/types/methods/providers/apple.d.ts.map +1 -0
- package/dist/types/methods/providers/cognito.d.ts +36 -0
- package/dist/types/methods/providers/cognito.d.ts.map +1 -0
- package/dist/types/methods/providers/discord.d.ts +22 -0
- package/dist/types/methods/providers/discord.d.ts.map +1 -0
- package/dist/types/methods/providers/facebook.d.ts +29 -0
- package/dist/types/methods/providers/facebook.d.ts.map +1 -0
- package/dist/types/methods/providers/github.d.ts +25 -0
- package/dist/types/methods/providers/github.d.ts.map +1 -0
- package/dist/types/methods/providers/google.d.ts +28 -0
- package/dist/types/methods/providers/google.d.ts.map +1 -0
- package/dist/types/methods/providers/index.d.ts +24 -0
- package/dist/types/methods/providers/index.d.ts.map +1 -0
- package/dist/types/methods/providers/jumpcloud.d.ts +22 -0
- package/dist/types/methods/providers/jumpcloud.d.ts.map +1 -0
- package/dist/types/methods/providers/keycloak.d.ts +30 -0
- package/dist/types/methods/providers/keycloak.d.ts.map +1 -0
- package/dist/types/methods/providers/linkedin.d.ts +22 -0
- package/dist/types/methods/providers/linkedin.d.ts.map +1 -0
- package/dist/types/methods/providers/microsoft.d.ts +30 -0
- package/dist/types/methods/providers/microsoft.d.ts.map +1 -0
- package/dist/types/methods/providers/slack.d.ts +25 -0
- package/dist/types/methods/providers/slack.d.ts.map +1 -0
- package/dist/types/methods/providers/spotify.d.ts +22 -0
- package/dist/types/methods/providers/spotify.d.ts.map +1 -0
- package/dist/types/methods/providers/twitch.d.ts +23 -0
- package/dist/types/methods/providers/twitch.d.ts.map +1 -0
- package/dist/types/methods/providers/x.d.ts +25 -0
- package/dist/types/methods/providers/x.d.ts.map +1 -0
- package/dist/types/methods/providers/yahoo.d.ts +22 -0
- package/dist/types/methods/providers/yahoo.d.ts.map +1 -0
- package/dist/types/pkce.d.ts +1 -2
- package/dist/types/pkce.d.ts.map +1 -1
- package/dist/types/ports/audit-log.d.ts +166 -0
- package/dist/types/ports/audit-log.d.ts.map +1 -0
- package/dist/types/ports/config-store.d.ts +32 -0
- package/dist/types/ports/config-store.d.ts.map +1 -0
- package/dist/types/ports/key-store.d.ts +98 -0
- package/dist/types/ports/key-store.d.ts.map +1 -0
- package/dist/types/ports/method-store.d.ts +29 -0
- package/dist/types/ports/method-store.d.ts.map +1 -0
- package/dist/types/ports/session-store.d.ts +109 -0
- package/dist/types/ports/session-store.d.ts.map +1 -0
- package/dist/types/ports/token-store.d.ts +105 -0
- package/dist/types/ports/token-store.d.ts.map +1 -0
- package/dist/types/types/authorization.d.ts +75 -0
- package/dist/types/types/authorization.d.ts.map +1 -0
- package/dist/types/types/error.d.ts +101 -0
- package/dist/types/types/error.d.ts.map +1 -0
- package/dist/types/types/flow.d.ts +97 -0
- package/dist/types/types/flow.d.ts.map +1 -0
- package/dist/types/types/idp.d.ts +324 -0
- package/dist/types/types/idp.d.ts.map +1 -0
- package/dist/types/types/method.d.ts +256 -0
- package/dist/types/types/method.d.ts.map +1 -0
- package/dist/types/types/picker.d.ts +31 -0
- package/dist/types/types/picker.d.ts.map +1 -0
- package/dist/types/types/result.d.ts +29 -0
- package/dist/types/types/result.d.ts.map +1 -0
- package/dist/types/types/subject.d.ts +47 -0
- package/dist/types/types/subject.d.ts.map +1 -0
- package/dist/types/types/tenant.d.ts +276 -0
- package/dist/types/types/tenant.d.ts.map +1 -0
- package/dist/types/types/token.d.ts +231 -0
- package/dist/types/types/token.d.ts.map +1 -0
- package/dist/types/ui/forms.d.ts +35 -0
- package/dist/types/ui/forms.d.ts.map +1 -0
- package/dist/types/ui/index.d.ts +14 -0
- package/dist/types/ui/index.d.ts.map +1 -0
- package/dist/types/ui/picker.d.ts +18 -0
- package/dist/types/ui/picker.d.ts.map +1 -0
- package/package.json +41 -6
- package/src/adapters/d1/audit-log.ts +32 -0
- package/src/adapters/d1/config-store.ts +67 -0
- package/src/adapters/d1/index.ts +41 -0
- package/src/adapters/d1/key-store.ts +218 -0
- package/src/adapters/d1/method-store.ts +103 -0
- package/src/adapters/d1/migrations.ts +89 -0
- package/src/adapters/d1/session-store.ts +230 -0
- package/src/adapters/d1/session.ts +38 -0
- package/src/adapters/d1/token-store.ts +251 -0
- package/src/adapters/d1/types.ts +53 -0
- package/src/adapters/durable-object/index.ts +23 -0
- package/src/adapters/durable-object/session-store.ts +227 -0
- package/src/adapters/durable-object/types.ts +25 -0
- package/src/adapters/dynamo/audit-log.ts +35 -0
- package/src/adapters/dynamo/client.ts +118 -0
- package/src/adapters/dynamo/config-store.ts +72 -0
- package/src/adapters/dynamo/index.ts +81 -0
- package/src/adapters/dynamo/key-store.ts +267 -0
- package/src/adapters/dynamo/method-store.ts +105 -0
- package/src/adapters/dynamo/passkey-credential-store.ts +132 -0
- package/src/adapters/dynamo/sdk.ts +189 -0
- package/src/adapters/dynamo/session-store.ts +229 -0
- package/src/adapters/dynamo/token-store.ts +248 -0
- package/src/adapters/kms/in-memory-backing.ts +36 -0
- package/src/adapters/kms/index.ts +39 -0
- package/src/adapters/kms/key-store.ts +176 -0
- package/src/adapters/kms/sdk.ts +39 -0
- package/src/adapters/kms/types.ts +61 -0
- package/src/adapters/kv/audit-log.ts +40 -0
- package/src/adapters/kv/config-store.ts +63 -0
- package/src/adapters/kv/index.ts +20 -0
- package/src/adapters/kv/method-store.ts +98 -0
- package/src/adapters/kv/types.ts +26 -0
- package/src/adapters/memory/audit-log.ts +28 -0
- package/src/adapters/memory/clock.ts +7 -0
- package/src/adapters/memory/config-store.ts +41 -0
- package/src/adapters/memory/index.ts +26 -0
- package/src/adapters/memory/key-store.ts +102 -0
- package/src/adapters/memory/method-store.ts +75 -0
- package/src/adapters/memory/passkey-credential-store.ts +97 -0
- package/src/adapters/memory/session-store.ts +171 -0
- package/src/adapters/memory/token-store.ts +181 -0
- package/src/adapters/postgres/audit-log.ts +34 -0
- package/src/adapters/postgres/config-store.ts +72 -0
- package/src/adapters/postgres/executor.ts +76 -0
- package/src/adapters/postgres/index.ts +60 -0
- package/src/adapters/postgres/key-store.ts +334 -0
- package/src/adapters/postgres/method-store.ts +104 -0
- package/src/adapters/postgres/migrations.ts +131 -0
- package/src/adapters/postgres/passkey-credential-store.ts +150 -0
- package/src/adapters/postgres/session-store.ts +216 -0
- package/src/adapters/postgres/token-store.ts +263 -0
- package/src/client.ts +82 -16
- package/src/domain/audit.ts +28 -0
- package/src/domain/authorize.ts +414 -0
- package/src/domain/callback.ts +268 -0
- package/src/domain/client-auth.ts +116 -0
- package/src/domain/client-credentials.ts +180 -0
- package/src/domain/crypto.ts +168 -0
- package/src/domain/discovery.ts +161 -0
- package/src/domain/dpop.ts +293 -0
- package/src/domain/id-token.ts +213 -0
- package/src/domain/introspect.ts +155 -0
- package/src/domain/jwt.ts +185 -0
- package/src/domain/logout.ts +180 -0
- package/src/domain/method-cache.ts +220 -0
- package/src/domain/method-dispatch.ts +95 -0
- package/src/domain/method-route.ts +213 -0
- package/src/domain/par.ts +141 -0
- package/src/domain/pkce.ts +37 -0
- package/src/domain/refresh.ts +210 -0
- package/src/domain/register.ts +168 -0
- package/src/domain/revoke.ts +161 -0
- package/src/domain/state-envelope.ts +142 -0
- package/src/domain/token-exchange.ts +243 -0
- package/src/domain/token.ts +483 -0
- package/src/domain/userinfo.ts +171 -0
- package/src/http/context.ts +90 -0
- package/src/http/cookies.ts +167 -0
- package/src/http/errors.ts +98 -0
- package/src/http/handlers/authorize.ts +362 -0
- package/src/http/handlers/callback.ts +77 -0
- package/src/http/handlers/end-session.ts +106 -0
- package/src/http/handlers/metadata.ts +49 -0
- package/src/http/handlers/method-route.ts +115 -0
- package/src/http/handlers/par.ts +84 -0
- package/src/http/handlers/register.ts +70 -0
- package/src/http/handlers/revocation.ts +151 -0
- package/src/http/handlers/token.ts +300 -0
- package/src/http/handlers/userinfo.ts +90 -0
- package/src/http/middleware/error.ts +26 -0
- package/src/http/middleware/tenant.ts +165 -0
- package/src/http/resolver.ts +34 -0
- package/src/http/router.ts +85 -0
- package/src/http/schemas/authorize.ts +85 -0
- package/src/http/schemas/end-session.ts +23 -0
- package/src/http/schemas/par.ts +23 -0
- package/src/http/schemas/register.ts +29 -0
- package/src/http/schemas/revocation.ts +23 -0
- package/src/http/schemas/token.ts +85 -0
- package/src/index.ts +283 -20
- package/src/methods/code.ts +359 -0
- package/src/methods/m2m.ts +82 -0
- package/src/methods/oauth2-factory.ts +151 -0
- package/src/methods/oauth2-generic.ts +360 -0
- package/src/methods/oidc-generic.ts +109 -0
- package/src/methods/passkey.ts +419 -0
- package/src/methods/password-hash.ts +134 -0
- package/src/methods/password.ts +298 -0
- package/src/methods/providers/apple.ts +42 -0
- package/src/methods/providers/cognito.ts +55 -0
- package/src/methods/providers/discord.ts +37 -0
- package/src/methods/providers/facebook.ts +54 -0
- package/src/methods/providers/github.ts +42 -0
- package/src/methods/providers/google.ts +43 -0
- package/src/methods/providers/index.ts +23 -0
- package/src/methods/providers/jumpcloud.ts +36 -0
- package/src/methods/providers/keycloak.ts +42 -0
- package/src/methods/providers/linkedin.ts +37 -0
- package/src/methods/providers/microsoft.ts +42 -0
- package/src/methods/providers/slack.ts +42 -0
- package/src/methods/providers/spotify.ts +37 -0
- package/src/methods/providers/twitch.ts +38 -0
- package/src/methods/providers/x.ts +40 -0
- package/src/methods/providers/yahoo.ts +36 -0
- package/src/pkce.ts +20 -21
- package/src/ports/CONSISTENCY.md +119 -0
- package/src/ports/audit-log.ts +177 -0
- package/src/ports/config-store.ts +34 -0
- package/src/ports/key-store.ts +106 -0
- package/src/ports/method-store.ts +41 -0
- package/src/ports/session-store.ts +131 -0
- package/src/ports/token-store.ts +116 -0
- package/src/types/authorization.ts +78 -0
- package/src/types/error.ts +146 -0
- package/src/types/flow.ts +99 -0
- package/src/types/idp.ts +365 -0
- package/src/types/method.ts +270 -0
- package/src/types/picker.ts +32 -0
- package/src/types/result.ts +23 -0
- package/src/types/subject.ts +50 -0
- package/src/types/tenant.ts +285 -0
- package/src/types/token.ts +236 -0
- package/src/ui/forms.ts +289 -0
- package/src/ui/index.ts +14 -0
- package/src/ui/picker.ts +63 -0
- package/dist/esm/issuer.js +0 -691
- package/dist/esm/jwt.js +0 -16
- package/dist/esm/keys.js +0 -113
- package/dist/esm/provider/apple.js +0 -28
- package/dist/esm/provider/arctic.js +0 -43
- package/dist/esm/provider/code.js +0 -58
- package/dist/esm/provider/cognito.js +0 -16
- package/dist/esm/provider/discord.js +0 -15
- package/dist/esm/provider/facebook.js +0 -24
- package/dist/esm/provider/github.js +0 -15
- package/dist/esm/provider/google.js +0 -25
- package/dist/esm/provider/index.js +0 -3
- package/dist/esm/provider/jumpcloud.js +0 -15
- package/dist/esm/provider/keycloak.js +0 -15
- package/dist/esm/provider/linkedin.js +0 -15
- package/dist/esm/provider/m2m.js +0 -16
- package/dist/esm/provider/microsoft.js +0 -24
- package/dist/esm/provider/oauth2.js +0 -119
- package/dist/esm/provider/oidc.js +0 -69
- package/dist/esm/provider/passkey.js +0 -315
- package/dist/esm/provider/password.js +0 -306
- package/dist/esm/provider/provider.js +0 -10
- package/dist/esm/provider/slack.js +0 -15
- package/dist/esm/provider/spotify.js +0 -15
- package/dist/esm/provider/twitch.js +0 -15
- package/dist/esm/provider/x.js +0 -16
- package/dist/esm/provider/yahoo.js +0 -15
- package/dist/esm/random.js +0 -27
- package/dist/esm/storage/aws.js +0 -39
- package/dist/esm/storage/cloudflare.js +0 -42
- package/dist/esm/storage/dynamo.js +0 -116
- package/dist/esm/storage/memory.js +0 -88
- package/dist/esm/storage/storage.js +0 -36
- package/dist/esm/subject.js +0 -7
- package/dist/esm/ui/base.js +0 -407
- package/dist/esm/ui/code.js +0 -151
- package/dist/esm/ui/form.js +0 -43
- package/dist/esm/ui/icon.js +0 -92
- package/dist/esm/ui/passkey.js +0 -329
- package/dist/esm/ui/password.js +0 -338
- package/dist/esm/ui/select.js +0 -187
- package/dist/esm/ui/theme.js +0 -115
- package/dist/esm/util.js +0 -54
- package/dist/types/issuer.d.ts +0 -607
- package/dist/types/issuer.d.ts.map +0 -1
- package/dist/types/jwt.d.ts +0 -6
- package/dist/types/jwt.d.ts.map +0 -1
- package/dist/types/keys.d.ts +0 -18
- package/dist/types/keys.d.ts.map +0 -1
- package/dist/types/provider/apple.d.ts +0 -108
- package/dist/types/provider/apple.d.ts.map +0 -1
- package/dist/types/provider/arctic.d.ts +0 -16
- package/dist/types/provider/arctic.d.ts.map +0 -1
- package/dist/types/provider/code.d.ts +0 -74
- package/dist/types/provider/code.d.ts.map +0 -1
- package/dist/types/provider/cognito.d.ts +0 -64
- package/dist/types/provider/cognito.d.ts.map +0 -1
- package/dist/types/provider/discord.d.ts +0 -38
- package/dist/types/provider/discord.d.ts.map +0 -1
- package/dist/types/provider/facebook.d.ts +0 -74
- package/dist/types/provider/facebook.d.ts.map +0 -1
- package/dist/types/provider/github.d.ts +0 -38
- package/dist/types/provider/github.d.ts.map +0 -1
- package/dist/types/provider/google.d.ts +0 -74
- package/dist/types/provider/google.d.ts.map +0 -1
- package/dist/types/provider/index.d.ts +0 -4
- package/dist/types/provider/index.d.ts.map +0 -1
- package/dist/types/provider/jumpcloud.d.ts +0 -38
- package/dist/types/provider/jumpcloud.d.ts.map +0 -1
- package/dist/types/provider/keycloak.d.ts +0 -67
- package/dist/types/provider/keycloak.d.ts.map +0 -1
- package/dist/types/provider/linkedin.d.ts +0 -6
- package/dist/types/provider/linkedin.d.ts.map +0 -1
- package/dist/types/provider/m2m.d.ts +0 -34
- package/dist/types/provider/m2m.d.ts.map +0 -1
- package/dist/types/provider/microsoft.d.ts +0 -89
- package/dist/types/provider/microsoft.d.ts.map +0 -1
- package/dist/types/provider/oauth2.d.ts +0 -133
- package/dist/types/provider/oauth2.d.ts.map +0 -1
- package/dist/types/provider/oidc.d.ts +0 -91
- package/dist/types/provider/oidc.d.ts.map +0 -1
- package/dist/types/provider/passkey.d.ts +0 -143
- package/dist/types/provider/passkey.d.ts.map +0 -1
- package/dist/types/provider/password.d.ts +0 -210
- package/dist/types/provider/password.d.ts.map +0 -1
- package/dist/types/provider/provider.d.ts +0 -29
- package/dist/types/provider/provider.d.ts.map +0 -1
- package/dist/types/provider/slack.d.ts +0 -59
- package/dist/types/provider/slack.d.ts.map +0 -1
- package/dist/types/provider/spotify.d.ts +0 -38
- package/dist/types/provider/spotify.d.ts.map +0 -1
- package/dist/types/provider/twitch.d.ts +0 -38
- package/dist/types/provider/twitch.d.ts.map +0 -1
- package/dist/types/provider/x.d.ts +0 -38
- package/dist/types/provider/x.d.ts.map +0 -1
- package/dist/types/provider/yahoo.d.ts +0 -38
- package/dist/types/provider/yahoo.d.ts.map +0 -1
- package/dist/types/random.d.ts +0 -3
- package/dist/types/random.d.ts.map +0 -1
- package/dist/types/storage/aws.d.ts +0 -4
- package/dist/types/storage/aws.d.ts.map +0 -1
- package/dist/types/storage/cloudflare.d.ts +0 -34
- package/dist/types/storage/cloudflare.d.ts.map +0 -1
- package/dist/types/storage/dynamo.d.ts +0 -65
- package/dist/types/storage/dynamo.d.ts.map +0 -1
- package/dist/types/storage/memory.d.ts +0 -49
- package/dist/types/storage/memory.d.ts.map +0 -1
- package/dist/types/storage/storage.d.ts +0 -15
- package/dist/types/storage/storage.d.ts.map +0 -1
- package/dist/types/subject.d.ts +0 -122
- package/dist/types/subject.d.ts.map +0 -1
- package/dist/types/ui/base.d.ts +0 -5
- package/dist/types/ui/base.d.ts.map +0 -1
- package/dist/types/ui/code.d.ts +0 -104
- package/dist/types/ui/code.d.ts.map +0 -1
- package/dist/types/ui/form.d.ts +0 -6
- package/dist/types/ui/form.d.ts.map +0 -1
- package/dist/types/ui/icon.d.ts +0 -6
- package/dist/types/ui/icon.d.ts.map +0 -1
- package/dist/types/ui/passkey.d.ts +0 -5
- package/dist/types/ui/passkey.d.ts.map +0 -1
- package/dist/types/ui/password.d.ts +0 -139
- package/dist/types/ui/password.d.ts.map +0 -1
- package/dist/types/ui/select.d.ts +0 -55
- package/dist/types/ui/select.d.ts.map +0 -1
- package/dist/types/ui/theme.d.ts +0 -207
- package/dist/types/ui/theme.d.ts.map +0 -1
- package/dist/types/util.d.ts +0 -8
- package/dist/types/util.d.ts.map +0 -1
- package/src/css.d.ts +0 -4
- package/src/issuer.ts +0 -1628
- package/src/jwt.ts +0 -17
- package/src/keys.ts +0 -139
- package/src/provider/apple.ts +0 -127
- package/src/provider/arctic.ts +0 -66
- package/src/provider/code.ts +0 -227
- package/src/provider/cognito.ts +0 -74
- package/src/provider/discord.ts +0 -45
- package/src/provider/facebook.ts +0 -84
- package/src/provider/github.ts +0 -45
- package/src/provider/google.ts +0 -85
- package/src/provider/index.ts +0 -3
- package/src/provider/jumpcloud.ts +0 -45
- package/src/provider/keycloak.ts +0 -75
- package/src/provider/linkedin.ts +0 -12
- package/src/provider/m2m.ts +0 -56
- package/src/provider/microsoft.ts +0 -100
- package/src/provider/oauth2.ts +0 -297
- package/src/provider/oidc.ts +0 -179
- package/src/provider/passkey.ts +0 -655
- package/src/provider/password.ts +0 -672
- package/src/provider/provider.ts +0 -33
- package/src/provider/slack.ts +0 -67
- package/src/provider/spotify.ts +0 -45
- package/src/provider/twitch.ts +0 -45
- package/src/provider/x.ts +0 -46
- package/src/provider/yahoo.ts +0 -45
- package/src/random.ts +0 -24
- package/src/storage/aws.ts +0 -59
- package/src/storage/cloudflare.ts +0 -77
- package/src/storage/dynamo.ts +0 -193
- package/src/storage/memory.ts +0 -135
- package/src/storage/storage.ts +0 -46
- package/src/subject.ts +0 -130
- package/src/ui/base.tsx +0 -118
- package/src/ui/code.tsx +0 -215
- package/src/ui/form.tsx +0 -40
- package/src/ui/icon.tsx +0 -95
- package/src/ui/passkey.tsx +0 -321
- package/src/ui/password.tsx +0 -405
- package/src/ui/select.tsx +0 -221
- package/src/ui/theme.ts +0 -319
- package/src/ui/ui.css +0 -252
- package/src/util.ts +0 -58
- /package/dist/esm/{css.d.js → adapters/d1/types.js} +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT signing + verification for access tokens, plus the JWKS document
|
|
3
|
+
* builder consumed by `/.well-known/jwks.json`.
|
|
4
|
+
*
|
|
5
|
+
* Per AD9 / AD11, access tokens are JWTs (ES256 default; Ed25519 supported).
|
|
6
|
+
* Refresh tokens are opaque server-side records — they do NOT pass through
|
|
7
|
+
* this module.
|
|
8
|
+
*/
|
|
9
|
+
import type { JWK, KeyLike } from "jose"
|
|
10
|
+
import { importJWK, jwtVerify, SignJWT } from "jose"
|
|
11
|
+
|
|
12
|
+
import type { AccessTokenClaims, IdTokenClaims } from "../types/token"
|
|
13
|
+
import type { SigningKey } from "../ports/key-store"
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Sign an access-token claim set under the supplied private key. `kid` is
|
|
17
|
+
* stamped into the JWT header so verifiers can look up the right public
|
|
18
|
+
* key from JWKS.
|
|
19
|
+
*/
|
|
20
|
+
export async function signAccessToken(
|
|
21
|
+
claims: AccessTokenClaims,
|
|
22
|
+
privateKey: KeyLike,
|
|
23
|
+
alg: string,
|
|
24
|
+
kid: string,
|
|
25
|
+
): Promise<string> {
|
|
26
|
+
return new SignJWT(claims as unknown as Record<string, unknown>)
|
|
27
|
+
.setProtectedHeader({ alg, typ: "JWT", kid })
|
|
28
|
+
.sign(privateKey)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Sign an OIDC `id_token` claim set (OIDC Core §2). Header `typ` is
|
|
33
|
+
* `"JWT"` per common practice; OIDC Core does not mandate `"id_token"`.
|
|
34
|
+
* The claims object is verified by the caller to include `iss`, `sub`,
|
|
35
|
+
* `aud`, `exp`, `iat` (REQUIRED per §2).
|
|
36
|
+
*/
|
|
37
|
+
export async function signIdToken(
|
|
38
|
+
claims: IdTokenClaims,
|
|
39
|
+
privateKey: KeyLike,
|
|
40
|
+
alg: string,
|
|
41
|
+
kid: string,
|
|
42
|
+
): Promise<string> {
|
|
43
|
+
return new SignJWT(claims as unknown as Record<string, unknown>)
|
|
44
|
+
.setProtectedHeader({ alg, typ: "JWT", kid })
|
|
45
|
+
.sign(privateKey)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Verify an OIDC `id_token` against the IdP's published signing keys.
|
|
50
|
+
* Used at `/end_session` to validate `id_token_hint` and by adjacent
|
|
51
|
+
* domain code that needs to introspect a previously-issued id_token.
|
|
52
|
+
*
|
|
53
|
+
* Same algorithm-confusion defenses as `verifyAccessToken`: only the
|
|
54
|
+
* asymmetric allow-list (`ES256`, `EdDSA`) accepted; `alg: "none"`
|
|
55
|
+
* rejected explicitly.
|
|
56
|
+
*
|
|
57
|
+
* `acceptExpired` relaxes the `exp` check — required at `/end_session`
|
|
58
|
+
* per OIDC RP-Initiated Logout 1.0 §2, where logout often follows token
|
|
59
|
+
* expiry and the spec permits accepting an expired hint. The signature
|
|
60
|
+
* + issuer + audience checks remain strict.
|
|
61
|
+
*/
|
|
62
|
+
export async function verifyIdToken(
|
|
63
|
+
token: string,
|
|
64
|
+
keys: ReadonlyArray<SigningKey>,
|
|
65
|
+
options: {
|
|
66
|
+
issuer?: string
|
|
67
|
+
audience?: string
|
|
68
|
+
acceptExpired?: boolean
|
|
69
|
+
} = {},
|
|
70
|
+
): Promise<IdTokenClaims> {
|
|
71
|
+
const algorithms = Array.from(
|
|
72
|
+
new Set(keys.map((k) => k.alg).filter((a) => ASYMMETRIC_ALGS.has(a))),
|
|
73
|
+
)
|
|
74
|
+
const { payload } = await jwtVerify<IdTokenClaims>(
|
|
75
|
+
token,
|
|
76
|
+
async (header) => {
|
|
77
|
+
if (!header.alg || header.alg === "none") {
|
|
78
|
+
throw new Error(`verifyIdToken: refusing alg "${header.alg ?? ""}"`)
|
|
79
|
+
}
|
|
80
|
+
const match = keys.find((k) => k.kid === header.kid)
|
|
81
|
+
if (!match) {
|
|
82
|
+
throw new Error(`verifyIdToken: unknown kid "${header.kid}"`)
|
|
83
|
+
}
|
|
84
|
+
if (match.alg !== header.alg) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`verifyIdToken: header.alg "${header.alg}" does not match key alg "${match.alg}"`,
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
const imported = await importJWK(
|
|
90
|
+
match.publicJwk as unknown as JWK,
|
|
91
|
+
match.alg,
|
|
92
|
+
)
|
|
93
|
+
return imported as KeyLike
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
algorithms,
|
|
97
|
+
...(options.issuer ? { issuer: options.issuer } : {}),
|
|
98
|
+
...(options.audience ? { audience: options.audience } : {}),
|
|
99
|
+
// jose checks `exp` against `currentDate + clockTolerance`. A huge
|
|
100
|
+
// tolerance effectively disables the expiry check while preserving
|
|
101
|
+
// signature + issuer + audience validation.
|
|
102
|
+
...(options.acceptExpired
|
|
103
|
+
? { clockTolerance: Number.MAX_SAFE_INTEGER }
|
|
104
|
+
: {}),
|
|
105
|
+
},
|
|
106
|
+
)
|
|
107
|
+
return payload
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Allow-list of asymmetric `alg` values the IdP issues + accepts. */
|
|
111
|
+
const ASYMMETRIC_ALGS: ReadonlySet<string> = new Set(["ES256", "EdDSA"])
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Verify a JWT access token using a list of trusted signing keys (from
|
|
115
|
+
* `KeyStore.signingKeys()`). Looks up by `kid` in the JWT header.
|
|
116
|
+
*
|
|
117
|
+
* Algorithm enforcement: the allow-list is derived from the loaded
|
|
118
|
+
* `SigningKey.alg` values, intersected with the asymmetric allow-list
|
|
119
|
+
* (`ES256`, `EdDSA`). Symmetric (`HS*`) and `none` are filtered out, so a
|
|
120
|
+
* symmetric key accidentally landing in the store does not open an
|
|
121
|
+
* alg-confusion path. The kid resolver also rejects `alg: "none"`
|
|
122
|
+
* explicitly as defense in depth — `jose` already refuses tokens whose
|
|
123
|
+
* header `alg` is outside `algorithms`, but a future call site that
|
|
124
|
+
* dropped the option would still be safe.
|
|
125
|
+
*
|
|
126
|
+
* Returns the typed claims on success. Throws (via `jose`) on any
|
|
127
|
+
* signature, expiry, or alg-mismatch failure — callers wrap in `try` and
|
|
128
|
+
* convert to `Result`.
|
|
129
|
+
*/
|
|
130
|
+
export async function verifyAccessToken(
|
|
131
|
+
token: string,
|
|
132
|
+
keys: ReadonlyArray<SigningKey>,
|
|
133
|
+
options: { issuer?: string; audience?: string } = {},
|
|
134
|
+
): Promise<AccessTokenClaims> {
|
|
135
|
+
const algorithms = Array.from(
|
|
136
|
+
new Set(keys.map((k) => k.alg).filter((a) => ASYMMETRIC_ALGS.has(a))),
|
|
137
|
+
)
|
|
138
|
+
const { payload } = await jwtVerify<AccessTokenClaims>(
|
|
139
|
+
token,
|
|
140
|
+
async (header) => {
|
|
141
|
+
if (!header.alg || header.alg === "none") {
|
|
142
|
+
throw new Error(`verifyAccessToken: refusing alg "${header.alg ?? ""}"`)
|
|
143
|
+
}
|
|
144
|
+
const match = keys.find((k) => k.kid === header.kid)
|
|
145
|
+
if (!match) {
|
|
146
|
+
throw new Error(`verifyAccessToken: unknown kid "${header.kid}"`)
|
|
147
|
+
}
|
|
148
|
+
if (match.alg !== header.alg) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`verifyAccessToken: header.alg "${header.alg}" does not match key alg "${match.alg}"`,
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
const imported = await importJWK(
|
|
154
|
+
match.publicJwk as unknown as JWK,
|
|
155
|
+
match.alg,
|
|
156
|
+
)
|
|
157
|
+
return imported as KeyLike
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
algorithms,
|
|
161
|
+
...(options.issuer ? { issuer: options.issuer } : {}),
|
|
162
|
+
...(options.audience ? { audience: options.audience } : {}),
|
|
163
|
+
},
|
|
164
|
+
)
|
|
165
|
+
return payload
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Build the JWKS document for `/.well-known/jwks.json`. Includes active +
|
|
170
|
+
* recently-rotated keys (the overlap window) so consumers caching JWKS
|
|
171
|
+
* continue to verify tokens signed under a just-retired key until they
|
|
172
|
+
* refresh.
|
|
173
|
+
*/
|
|
174
|
+
export function buildJwksDocument(keys: ReadonlyArray<SigningKey>): {
|
|
175
|
+
keys: JWK[]
|
|
176
|
+
} {
|
|
177
|
+
return {
|
|
178
|
+
keys: keys.map((k) => ({
|
|
179
|
+
...k.publicJwk,
|
|
180
|
+
kid: k.kid,
|
|
181
|
+
alg: k.alg,
|
|
182
|
+
use: "sig",
|
|
183
|
+
})) as JWK[],
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/end_session` endpoint logic — OIDC RP-Initiated Logout 1.0.
|
|
3
|
+
*
|
|
4
|
+
* The OP validates the optional `id_token_hint`, validates the optional
|
|
5
|
+
* `post_logout_redirect_uri` against the client's registered list,
|
|
6
|
+
* revokes the subject's refresh tokens (when a subject is identified),
|
|
7
|
+
* and either redirects the user-agent back to the RP with `state` echoed
|
|
8
|
+
* or returns a generic "logged out" acknowledgement.
|
|
9
|
+
*
|
|
10
|
+
* Per §2:
|
|
11
|
+
* - `id_token_hint` (RECOMMENDED): a previously-issued id_token. The
|
|
12
|
+
* OP MUST verify the signature; expiry MAY be tolerated because
|
|
13
|
+
* logout commonly follows token expiry. We accept expired hints but
|
|
14
|
+
* enforce signature + issuer.
|
|
15
|
+
* - `client_id` (OPTIONAL): when both this and `id_token_hint` are
|
|
16
|
+
* present, the OP MUST verify the client_id matches the hint's `aud`.
|
|
17
|
+
* - `post_logout_redirect_uri` (OPTIONAL): MUST be exact-match against
|
|
18
|
+
* the resolved client's `postLogoutRedirectUris`. If the URI is not
|
|
19
|
+
* registered, the OP MUST NOT redirect — surface a non-redirecting
|
|
20
|
+
* error instead, otherwise the endpoint becomes an open redirector.
|
|
21
|
+
* - `state` (OPTIONAL): echoed back in the redirect.
|
|
22
|
+
*
|
|
23
|
+
* Front-channel / back-channel logout (RP notification of OP-initiated
|
|
24
|
+
* logout) is out of scope for this minimal endpoint. Hosts that need it
|
|
25
|
+
* can layer their own notification fan-out on top of `session_logout`
|
|
26
|
+
* audit events.
|
|
27
|
+
*/
|
|
28
|
+
import type { AuditLog } from "../ports/audit-log"
|
|
29
|
+
import type { ConfigStore } from "../ports/config-store"
|
|
30
|
+
import type { KeyStore } from "../ports/key-store"
|
|
31
|
+
import type { TokenStore } from "../ports/token-store"
|
|
32
|
+
import { authError, type AuthError } from "../types/error"
|
|
33
|
+
import type { Result } from "../types/result"
|
|
34
|
+
import { err, isErr, ok } from "../types/result"
|
|
35
|
+
import type { ClientConfig, TenantContext } from "../types/tenant"
|
|
36
|
+
|
|
37
|
+
import { safeAudit } from "./audit"
|
|
38
|
+
import { verifyIdToken } from "./jwt"
|
|
39
|
+
import { revokeAllForSubject } from "./revoke"
|
|
40
|
+
|
|
41
|
+
export type EndSessionRequest = {
|
|
42
|
+
idTokenHint?: string
|
|
43
|
+
clientId?: string
|
|
44
|
+
postLogoutRedirectUri?: string
|
|
45
|
+
state?: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type EndSessionDeps = {
|
|
49
|
+
configStore: ConfigStore
|
|
50
|
+
tokenStore: TokenStore
|
|
51
|
+
keyStore: KeyStore
|
|
52
|
+
auditLog?: AuditLog
|
|
53
|
+
issuerUrl: string
|
|
54
|
+
clock: () => number
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type EndSessionOutput =
|
|
58
|
+
/** Redirect the user-agent back to the RP. */
|
|
59
|
+
| { kind: "redirect"; url: string }
|
|
60
|
+
/**
|
|
61
|
+
* No `post_logout_redirect_uri` was supplied (or it wasn't registered).
|
|
62
|
+
* Caller should render a minimal "logged out" page or return 200.
|
|
63
|
+
*/
|
|
64
|
+
| { kind: "ok"; subjectId?: string }
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Process an `/end_session` request and return an outcome the HTTP
|
|
68
|
+
* adapter can translate into a `Response`. Pure domain — no Hono types,
|
|
69
|
+
* no `Response` construction here.
|
|
70
|
+
*/
|
|
71
|
+
export async function endSession(
|
|
72
|
+
req: EndSessionRequest,
|
|
73
|
+
tenant: TenantContext,
|
|
74
|
+
deps: EndSessionDeps,
|
|
75
|
+
): Promise<Result<EndSessionOutput, AuthError>> {
|
|
76
|
+
// 1. Verify the id_token_hint (if present). Tolerate expiry per §2.
|
|
77
|
+
let hintSubject: string | undefined
|
|
78
|
+
let hintAud: string | undefined
|
|
79
|
+
if (req.idTokenHint) {
|
|
80
|
+
const keysRes = await deps.keyStore.signingKeys()
|
|
81
|
+
if (isErr(keysRes)) return err(keysRes.error)
|
|
82
|
+
try {
|
|
83
|
+
const claims = await verifyIdToken(req.idTokenHint, keysRes.value, {
|
|
84
|
+
issuer: deps.issuerUrl,
|
|
85
|
+
acceptExpired: true,
|
|
86
|
+
})
|
|
87
|
+
hintSubject = claims.sub
|
|
88
|
+
hintAud = claims.aud
|
|
89
|
+
} catch (e) {
|
|
90
|
+
const reason = e instanceof Error ? e.message : String(e)
|
|
91
|
+
return err(
|
|
92
|
+
authError.invalidRequest(
|
|
93
|
+
`id_token_hint failed signature/issuer verification: ${reason}`,
|
|
94
|
+
"id_token_hint",
|
|
95
|
+
),
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 2. If both client_id and id_token_hint are present, they MUST agree
|
|
101
|
+
// (§2). Disagreement is `invalid_request` — never a redirect.
|
|
102
|
+
if (req.clientId && hintAud && req.clientId !== hintAud) {
|
|
103
|
+
return err(
|
|
104
|
+
authError.invalidRequest(
|
|
105
|
+
"client_id does not match id_token_hint.aud",
|
|
106
|
+
"client_id",
|
|
107
|
+
),
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 3. Resolve the client for redirect-URI validation. Prefer explicit
|
|
112
|
+
// client_id, fall back to the hint's aud.
|
|
113
|
+
const resolvedClientId = req.clientId ?? hintAud
|
|
114
|
+
let client: ClientConfig | undefined
|
|
115
|
+
if (resolvedClientId) {
|
|
116
|
+
client = tenant.config.clients.find((c) => c.id === resolvedClientId)
|
|
117
|
+
if (!client) {
|
|
118
|
+
return err(
|
|
119
|
+
authError.invalidRequest(
|
|
120
|
+
`unknown client "${resolvedClientId}"`,
|
|
121
|
+
"client_id",
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 4. Validate post_logout_redirect_uri. MUST be exact-match against
|
|
128
|
+
// the client's registered list (§2). No client → no validatable URI.
|
|
129
|
+
if (req.postLogoutRedirectUri) {
|
|
130
|
+
if (!client) {
|
|
131
|
+
return err(
|
|
132
|
+
authError.invalidRequest(
|
|
133
|
+
"post_logout_redirect_uri requires identifying the client via client_id or id_token_hint",
|
|
134
|
+
"post_logout_redirect_uri",
|
|
135
|
+
),
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
const registered = client.postLogoutRedirectUris ?? []
|
|
139
|
+
if (!registered.includes(req.postLogoutRedirectUri)) {
|
|
140
|
+
return err(
|
|
141
|
+
authError.invalidRequest(
|
|
142
|
+
"post_logout_redirect_uri is not registered for this client",
|
|
143
|
+
"post_logout_redirect_uri",
|
|
144
|
+
),
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 5. Revoke the subject's tokens. Only possible when an id_token_hint
|
|
150
|
+
// identified a subject. Without a hint, /end_session is essentially
|
|
151
|
+
// a session-cookie clear (which the framework doesn't yet own); we
|
|
152
|
+
// still return a successful redirect/ok so RPs can complete UX.
|
|
153
|
+
if (hintSubject) {
|
|
154
|
+
const revoked = await revokeAllForSubject(tenant.id, hintSubject, {
|
|
155
|
+
tokenStore: deps.tokenStore,
|
|
156
|
+
...(deps.auditLog ? { auditLog: deps.auditLog } : {}),
|
|
157
|
+
clock: deps.clock,
|
|
158
|
+
})
|
|
159
|
+
if (isErr(revoked)) return err(revoked.error)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
await safeAudit(deps, {
|
|
163
|
+
kind: "session_logout",
|
|
164
|
+
tenantId: tenant.id,
|
|
165
|
+
...(resolvedClientId ? { clientId: resolvedClientId } : {}),
|
|
166
|
+
...(hintSubject ? { subjectId: hintSubject } : {}),
|
|
167
|
+
timestamp: deps.clock(),
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
// 6. Build the redirect or signal "ok" for the caller to render.
|
|
171
|
+
if (req.postLogoutRedirectUri) {
|
|
172
|
+
const url = new URL(req.postLogoutRedirectUri)
|
|
173
|
+
if (req.state !== undefined) url.searchParams.set("state", req.state)
|
|
174
|
+
return ok({ kind: "redirect", url: url.toString() })
|
|
175
|
+
}
|
|
176
|
+
return ok({
|
|
177
|
+
kind: "ok",
|
|
178
|
+
...(hintSubject ? { subjectId: hintSubject } : {}),
|
|
179
|
+
})
|
|
180
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `MethodCache` — loads `AuthMethodFactory` builds per
|
|
3
|
+
* `(tenantId, MethodConfig.id)` and caches the result.
|
|
4
|
+
*
|
|
5
|
+
* Responsibilities per plan §"Per-tenant config → typed method config":
|
|
6
|
+
* 1. Look up the factory by `MethodConfig.kind`. Unknown kind → audit
|
|
7
|
+
* `unknown_method_kind`, treat instance as disabled.
|
|
8
|
+
* 2. Validate `MethodConfig.config` against `factory.configSchema`.
|
|
9
|
+
* Failure → audit `invalid_method_config`, treat instance as disabled.
|
|
10
|
+
* 3. Call `factory.build({ id, kind, tenantId, config })`. Verify the
|
|
11
|
+
* returned `AuthMethod` has `id` / `kind` matching the inputs. Mismatch
|
|
12
|
+
* → audit `factory_id_mismatch`, fail the load.
|
|
13
|
+
* 4. Cache per `(tenantId, MethodConfig.id)`. The cache is in-process —
|
|
14
|
+
* TTL is governed by the `ConfigStore` invalidation hook in Phase 3+;
|
|
15
|
+
* in Phase 2 / tests, manual `invalidate(tenantId)` is sufficient.
|
|
16
|
+
*/
|
|
17
|
+
import type { AuditLog } from "../ports/audit-log"
|
|
18
|
+
import { authError, type AuthError } from "../types/error"
|
|
19
|
+
import type { AnyAuthMethodFactory, AuthMethod } from "../types/method"
|
|
20
|
+
import type { Result } from "../types/result"
|
|
21
|
+
import { err, ok } from "../types/result"
|
|
22
|
+
import type { MethodConfig, TenantConfig, TenantId } from "../types/tenant"
|
|
23
|
+
|
|
24
|
+
export type MethodCacheOptions = {
|
|
25
|
+
factories: Record<string, AnyAuthMethodFactory>
|
|
26
|
+
auditLog?: AuditLog
|
|
27
|
+
/** Injectable clock for audit timestamps. */
|
|
28
|
+
now: () => number
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class MethodCache {
|
|
32
|
+
#factories: Record<string, AnyAuthMethodFactory>
|
|
33
|
+
#auditLog?: AuditLog
|
|
34
|
+
#now: () => number
|
|
35
|
+
#cache = new Map<string, AuthMethod>()
|
|
36
|
+
/** Negative-cache: instances we know are disabled (config invalid / unknown kind). */
|
|
37
|
+
#disabled = new Set<string>()
|
|
38
|
+
|
|
39
|
+
constructor(opts: MethodCacheOptions) {
|
|
40
|
+
this.#factories = opts.factories
|
|
41
|
+
this.#auditLog = opts.auditLog
|
|
42
|
+
this.#now = opts.now
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Load (or fetch from cache) the `AuthMethod` for the given tenant +
|
|
47
|
+
* tenant-local method instance id. Returns `method_not_found` for any
|
|
48
|
+
* disabled / unknown / invalid-config path.
|
|
49
|
+
*/
|
|
50
|
+
async resolve(
|
|
51
|
+
tenant: TenantConfig,
|
|
52
|
+
methodId: string,
|
|
53
|
+
): Promise<Result<AuthMethod, AuthError>> {
|
|
54
|
+
const cacheKey = this.#key(tenant.id, methodId)
|
|
55
|
+
const hit = this.#cache.get(cacheKey)
|
|
56
|
+
if (hit) return ok(hit)
|
|
57
|
+
if (this.#disabled.has(cacheKey)) {
|
|
58
|
+
return err(
|
|
59
|
+
authError.methodNotFound(
|
|
60
|
+
`method "${methodId}" is disabled or has invalid config`,
|
|
61
|
+
{ methodId },
|
|
62
|
+
),
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const cfg = tenant.methods.find((m) => m.id === methodId)
|
|
67
|
+
if (!cfg) {
|
|
68
|
+
return err(
|
|
69
|
+
authError.methodNotFound(`method "${methodId}" not configured`, {
|
|
70
|
+
methodId,
|
|
71
|
+
}),
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
if (!cfg.enabled) {
|
|
75
|
+
return err(
|
|
76
|
+
authError.methodNotFound(`method "${methodId}" is disabled`, {
|
|
77
|
+
methodId,
|
|
78
|
+
}),
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const built = await this.#build(tenant.id, cfg)
|
|
83
|
+
if (built.ok) {
|
|
84
|
+
this.#cache.set(cacheKey, built.value)
|
|
85
|
+
} else {
|
|
86
|
+
this.#disabled.add(cacheKey)
|
|
87
|
+
}
|
|
88
|
+
return built
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Drop cached instances for a tenant. Called on config invalidation. */
|
|
92
|
+
invalidate(tenantId: TenantId, methodId?: string): void {
|
|
93
|
+
if (methodId !== undefined) {
|
|
94
|
+
const key = this.#key(tenantId, methodId)
|
|
95
|
+
this.#cache.delete(key)
|
|
96
|
+
this.#disabled.delete(key)
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
for (const k of [...this.#cache.keys()]) {
|
|
100
|
+
if (k.startsWith(`${tenantId}\0`)) this.#cache.delete(k)
|
|
101
|
+
}
|
|
102
|
+
for (const k of [...this.#disabled]) {
|
|
103
|
+
if (k.startsWith(`${tenantId}\0`)) this.#disabled.delete(k)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** List all enabled methods for a tenant — used by method-selection UI. */
|
|
108
|
+
async listAvailable(tenant: TenantConfig): Promise<AuthMethod[]> {
|
|
109
|
+
const results: AuthMethod[] = []
|
|
110
|
+
for (const cfg of tenant.methods) {
|
|
111
|
+
if (!cfg.enabled) continue
|
|
112
|
+
const m = await this.resolve(tenant, cfg.id)
|
|
113
|
+
if (m.ok) results.push(m.value)
|
|
114
|
+
}
|
|
115
|
+
return results
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async #build(
|
|
119
|
+
tenantId: TenantId,
|
|
120
|
+
cfg: MethodConfig,
|
|
121
|
+
): Promise<Result<AuthMethod, AuthError>> {
|
|
122
|
+
const factory = this.#factories[cfg.kind]
|
|
123
|
+
if (!factory) {
|
|
124
|
+
await this.#audit({
|
|
125
|
+
kind: "unknown_method_kind",
|
|
126
|
+
tenantId,
|
|
127
|
+
methodId: cfg.id,
|
|
128
|
+
methodKind: cfg.kind,
|
|
129
|
+
timestamp: this.#now(),
|
|
130
|
+
})
|
|
131
|
+
return err(
|
|
132
|
+
authError.methodNotFound(
|
|
133
|
+
`no factory registered for kind "${cfg.kind}"`,
|
|
134
|
+
{
|
|
135
|
+
methodId: cfg.id,
|
|
136
|
+
methodKind: cfg.kind,
|
|
137
|
+
},
|
|
138
|
+
),
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Standard Schema v1: `validate` may return a Result or a Promise<Result>.
|
|
143
|
+
// Successful Result has `{ value }`; failure has `{ issues }`.
|
|
144
|
+
let parsed = factory.configSchema["~standard"].validate(cfg.config)
|
|
145
|
+
if (parsed instanceof Promise) parsed = await parsed
|
|
146
|
+
if ("issues" in parsed && parsed.issues) {
|
|
147
|
+
await this.#audit({
|
|
148
|
+
kind: "invalid_method_config",
|
|
149
|
+
tenantId,
|
|
150
|
+
methodId: cfg.id,
|
|
151
|
+
methodKind: cfg.kind,
|
|
152
|
+
errorPath: parsed.issues
|
|
153
|
+
.map((issue) =>
|
|
154
|
+
(issue.path ?? [])
|
|
155
|
+
.map((segment) =>
|
|
156
|
+
typeof segment === "object"
|
|
157
|
+
? String(segment.key)
|
|
158
|
+
: String(segment),
|
|
159
|
+
)
|
|
160
|
+
.join("."),
|
|
161
|
+
)
|
|
162
|
+
.join(","),
|
|
163
|
+
timestamp: this.#now(),
|
|
164
|
+
})
|
|
165
|
+
return err(
|
|
166
|
+
authError.methodNotFound(
|
|
167
|
+
`invalid method config for "${cfg.id}" (kind "${cfg.kind}")`,
|
|
168
|
+
{ methodId: cfg.id, methodKind: cfg.kind },
|
|
169
|
+
),
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let method: AuthMethod
|
|
174
|
+
try {
|
|
175
|
+
method = await factory.build({
|
|
176
|
+
id: cfg.id,
|
|
177
|
+
kind: cfg.kind,
|
|
178
|
+
tenantId,
|
|
179
|
+
config: parsed.value,
|
|
180
|
+
})
|
|
181
|
+
} catch (e) {
|
|
182
|
+
return err(
|
|
183
|
+
authError.internalError(
|
|
184
|
+
`factory "${cfg.kind}" build threw for instance "${cfg.id}"`,
|
|
185
|
+
e,
|
|
186
|
+
),
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (method.id !== cfg.id || method.kind !== cfg.kind) {
|
|
191
|
+
await this.#audit({
|
|
192
|
+
kind: "factory_id_mismatch",
|
|
193
|
+
tenantId,
|
|
194
|
+
methodId: cfg.id,
|
|
195
|
+
expectedKind: cfg.kind,
|
|
196
|
+
actualKind: method.kind,
|
|
197
|
+
timestamp: this.#now(),
|
|
198
|
+
})
|
|
199
|
+
return err(
|
|
200
|
+
authError.internalError(
|
|
201
|
+
`factory "${cfg.kind}" returned AuthMethod with id/kind ${method.id}/${method.kind}; expected ${cfg.id}/${cfg.kind}`,
|
|
202
|
+
),
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
return ok(method)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
#key(tenantId: TenantId, methodId: string): string {
|
|
209
|
+
return `${tenantId}\0${methodId}`
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async #audit(event: Parameters<AuditLog["log"]>[0]): Promise<void> {
|
|
213
|
+
if (!this.#auditLog) return
|
|
214
|
+
try {
|
|
215
|
+
await this.#auditLog.log(event)
|
|
216
|
+
} catch {
|
|
217
|
+
// Audit failure must not break the hot path.
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Method dispatch — invoke a method's route handler, then enforce the
|
|
3
|
+
* `saveMethodState` durability contract.
|
|
4
|
+
*
|
|
5
|
+
* Per `ARCHITECTURE.md`: when a method handler returns
|
|
6
|
+
* `{ kind: "challenge", saveMethodState }`, the framework MUST persist
|
|
7
|
+
* `methodState` via `SessionStore.updateFlowMethodState` **before**
|
|
8
|
+
* surfacing the response. Centralizing that here keeps the
|
|
9
|
+
* happens-before contract uniform across every call site.
|
|
10
|
+
*/
|
|
11
|
+
import type { SessionStore } from "../ports/session-store"
|
|
12
|
+
import { authError, type AuthError } from "../types/error"
|
|
13
|
+
import type { FlowRecord } from "../types/flow"
|
|
14
|
+
import type {
|
|
15
|
+
AuthMethod,
|
|
16
|
+
MethodContext,
|
|
17
|
+
MethodDispatchData,
|
|
18
|
+
MethodResult,
|
|
19
|
+
} from "../types/method"
|
|
20
|
+
import type { Result } from "../types/result"
|
|
21
|
+
import { err, isErr, ok } from "../types/result"
|
|
22
|
+
import type { TenantContext } from "../types/tenant"
|
|
23
|
+
|
|
24
|
+
export type RouteKey = `${"GET" | "POST"} ${string}`
|
|
25
|
+
|
|
26
|
+
export type DispatchInput = {
|
|
27
|
+
method: AuthMethod
|
|
28
|
+
route: RouteKey
|
|
29
|
+
tenant: TenantContext
|
|
30
|
+
request: Request
|
|
31
|
+
subPath: string
|
|
32
|
+
flow: FlowRecord | null
|
|
33
|
+
cookies: ReadonlyMap<string, string>
|
|
34
|
+
sessionStore: SessionStore
|
|
35
|
+
/** Populated at `GET /authorize`; null on callbacks. */
|
|
36
|
+
dispatch: MethodDispatchData | null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Invoke the named route on the method. If the result is a challenge with
|
|
41
|
+
* `saveMethodState`, persist it to `SessionStore` and only then return.
|
|
42
|
+
* The framework owns this happens-before guarantee so methods cannot
|
|
43
|
+
* accidentally surface a redirect before the upstream verifier is durable.
|
|
44
|
+
*/
|
|
45
|
+
export async function dispatchMethod(
|
|
46
|
+
input: DispatchInput,
|
|
47
|
+
): Promise<Result<MethodResult<unknown, unknown>, AuthError>> {
|
|
48
|
+
const handler = input.method.routes[input.route]
|
|
49
|
+
if (!handler) {
|
|
50
|
+
return err(
|
|
51
|
+
authError.invalidRequest(
|
|
52
|
+
`method "${input.method.id}" has no handler for route "${input.route}"`,
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const ctx: MethodContext<unknown> = {
|
|
58
|
+
request: input.request,
|
|
59
|
+
subPath: input.subPath,
|
|
60
|
+
tenant: input.tenant,
|
|
61
|
+
flow: input.flow,
|
|
62
|
+
methodState: input.flow?.methodState ?? null,
|
|
63
|
+
cookies: input.cookies,
|
|
64
|
+
dispatch: input.dispatch,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let result: MethodResult<unknown, unknown>
|
|
68
|
+
try {
|
|
69
|
+
result = await handler(ctx)
|
|
70
|
+
} catch (e) {
|
|
71
|
+
return err(
|
|
72
|
+
authError.serverError(
|
|
73
|
+
`method "${input.method.id}" handler threw on route "${input.route}"`,
|
|
74
|
+
e,
|
|
75
|
+
),
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (result.kind === "challenge" && result.saveMethodState !== undefined) {
|
|
80
|
+
if (!input.flow) {
|
|
81
|
+
return err(
|
|
82
|
+
authError.internalError(
|
|
83
|
+
`method "${input.method.id}" returned saveMethodState without an active flow`,
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
const persisted = await input.sessionStore.updateFlowMethodState(
|
|
88
|
+
input.flow.flowId,
|
|
89
|
+
result.saveMethodState,
|
|
90
|
+
)
|
|
91
|
+
if (isErr(persisted)) return err(persisted.error)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return ok(result)
|
|
95
|
+
}
|