@_mustachio/openauth 0.9.2 → 0.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/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 +82 -0
- package/dist/esm/adapters/memory/token-store.js +91 -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 +26 -10
- package/dist/esm/domain/audit.js +13 -0
- package/dist/esm/domain/authorize.js +212 -0
- package/dist/esm/domain/callback.js +173 -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 +41 -0
- package/dist/esm/domain/introspect.js +51 -0
- package/dist/esm/domain/jwt.js +43 -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 +108 -0
- package/dist/esm/domain/pkce.js +16 -0
- package/dist/esm/domain/refresh.js +91 -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 +101 -0
- package/dist/esm/domain/token.js +205 -0
- package/dist/esm/domain/userinfo.js +27 -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 +163 -0
- package/dist/esm/http/handlers/callback.js +53 -0
- package/dist/esm/http/handlers/metadata.js +34 -0
- package/dist/esm/http/handlers/method-route.js +87 -0
- package/dist/esm/http/handlers/revocation.js +98 -0
- package/dist/esm/http/handlers/token.js +167 -0
- package/dist/esm/http/handlers/userinfo.js +54 -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 +35 -0
- package/dist/esm/http/schemas/authorize.js +24 -0
- package/dist/esm/http/schemas/revocation.js +18 -0
- package/dist/esm/http/schemas/token.js +57 -0
- package/dist/esm/index.js +121 -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 +65 -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 +19 -0
- package/dist/types/adapters/memory/session-store.d.ts.map +1 -0
- package/dist/types/adapters/memory/token-store.d.ts +28 -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 +1 -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 +52 -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 +44 -0
- package/dist/types/domain/discovery.d.ts.map +1 -0
- package/dist/types/domain/introspect.d.ts +71 -0
- package/dist/types/domain/introspect.d.ts.map +1 -0
- package/dist/types/domain/jwt.d.ts +48 -0
- package/dist/types/domain/jwt.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/pkce.d.ts +15 -0
- package/dist/types/domain/pkce.d.ts.map +1 -0
- package/dist/types/domain/refresh.d.ts +43 -0
- package/dist/types/domain/refresh.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 +67 -0
- package/dist/types/domain/token-exchange.d.ts.map +1 -0
- package/dist/types/domain/token.d.ts +100 -0
- package/dist/types/domain/token.d.ts.map +1 -0
- package/dist/types/domain/userinfo.d.ts +22 -0
- package/dist/types/domain/userinfo.d.ts.map +1 -0
- package/dist/types/http/context.d.ts +63 -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/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/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 +52 -0
- package/dist/types/http/schemas/authorize.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 +139 -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 +82 -0
- package/dist/types/ports/session-store.d.ts.map +1 -0
- package/dist/types/ports/token-store.d.ts +93 -0
- package/dist/types/ports/token-store.d.ts.map +1 -0
- package/dist/types/types/authorization.d.ts +52 -0
- package/dist/types/types/authorization.d.ts.map +1 -0
- package/dist/types/types/error.d.ts +92 -0
- package/dist/types/types/error.d.ts.map +1 -0
- package/dist/types/types/flow.d.ts +87 -0
- package/dist/types/types/flow.d.ts.map +1 -0
- package/dist/types/types/idp.d.ts +234 -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 +239 -0
- package/dist/types/types/tenant.d.ts.map +1 -0
- package/dist/types/types/token.d.ts +103 -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 +128 -0
- package/src/adapters/memory/token-store.ts +165 -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 +50 -16
- package/src/domain/audit.ts +28 -0
- package/src/domain/authorize.ts +405 -0
- package/src/domain/callback.ts +263 -0
- package/src/domain/client-auth.ts +116 -0
- package/src/domain/client-credentials.ts +178 -0
- package/src/domain/crypto.ts +168 -0
- package/src/domain/discovery.ts +83 -0
- package/src/domain/introspect.ts +145 -0
- package/src/domain/jwt.ts +106 -0
- package/src/domain/method-cache.ts +220 -0
- package/src/domain/method-dispatch.ts +95 -0
- package/src/domain/method-route.ts +208 -0
- package/src/domain/pkce.ts +37 -0
- package/src/domain/refresh.ts +169 -0
- package/src/domain/revoke.ts +161 -0
- package/src/domain/state-envelope.ts +142 -0
- package/src/domain/token-exchange.ts +232 -0
- package/src/domain/token.ts +357 -0
- package/src/domain/userinfo.ts +56 -0
- package/src/http/context.ts +86 -0
- package/src/http/cookies.ts +167 -0
- package/src/http/errors.ts +98 -0
- package/src/http/handlers/authorize.ts +221 -0
- package/src/http/handlers/callback.ts +77 -0
- package/src/http/handlers/metadata.ts +44 -0
- package/src/http/handlers/method-route.ts +115 -0
- package/src/http/handlers/revocation.ts +151 -0
- package/src/http/handlers/token.ts +244 -0
- package/src/http/handlers/userinfo.ts +66 -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 +66 -0
- package/src/http/schemas/authorize.ts +58 -0
- package/src/http/schemas/revocation.ts +23 -0
- package/src/http/schemas/token.ts +85 -0
- package/src/index.ts +266 -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 +88 -0
- package/src/ports/audit-log.ts +148 -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 +98 -0
- package/src/ports/token-store.ts +103 -0
- package/src/types/authorization.ts +53 -0
- package/src/types/error.ts +123 -0
- package/src/types/flow.ts +89 -0
- package/src/types/idp.ts +269 -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 +248 -0
- package/src/types/token.ts +101 -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,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 7009 `/revoke` and RFC 7662 `/introspect` HTTP shims.
|
|
3
|
+
*
|
|
4
|
+
* Both accept `application/x-www-form-urlencoded`. Client credentials
|
|
5
|
+
* may ride in the form body (`client_id`, `client_secret`) or in an
|
|
6
|
+
* `Authorization: Basic` header (RFC 6749 §2.3.1); the header wins when
|
|
7
|
+
* both are present.
|
|
8
|
+
*
|
|
9
|
+
* Revoke: anonymous calls are permitted for tokens issued to public
|
|
10
|
+
* clients (RFC 7009 §2.1). Confidential-client tokens require auth.
|
|
11
|
+
*
|
|
12
|
+
* Introspect: client auth is REQUIRED (RFC 7662 §2.1). Anonymous calls
|
|
13
|
+
* are rejected at this layer with `invalid_client`.
|
|
14
|
+
*/
|
|
15
|
+
import { resolveClientCredentials } from "../../domain/client-auth"
|
|
16
|
+
import { introspect } from "../../domain/introspect"
|
|
17
|
+
import { revokeToken } from "../../domain/revoke"
|
|
18
|
+
import { authError } from "../../types/error"
|
|
19
|
+
import { isErr } from "../../types/result"
|
|
20
|
+
|
|
21
|
+
import type { HttpContext, HttpDeps } from "../context"
|
|
22
|
+
import { tokenEndpointErrorResponse } from "../errors"
|
|
23
|
+
import { injectResolverHints } from "../resolver"
|
|
24
|
+
import { introspectBodySchema, revokeBodySchema } from "../schemas/revocation"
|
|
25
|
+
|
|
26
|
+
export function makeRevokeHandler(deps: HttpDeps) {
|
|
27
|
+
return async (c: HttpContext): Promise<Response> => {
|
|
28
|
+
const body = await readForm(c.req.raw)
|
|
29
|
+
if (!body) {
|
|
30
|
+
return tokenEndpointErrorResponse(
|
|
31
|
+
authError.invalidRequest(
|
|
32
|
+
"body must be application/x-www-form-urlencoded",
|
|
33
|
+
),
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
const parsed = revokeBodySchema.safeParse(
|
|
37
|
+
Object.fromEntries(body.entries()),
|
|
38
|
+
)
|
|
39
|
+
if (!parsed.success) {
|
|
40
|
+
return tokenEndpointErrorResponse(
|
|
41
|
+
authError.invalidRequest(parsed.error.issues[0]?.message ?? "invalid"),
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
const creds = resolveClientCredentials({
|
|
45
|
+
authorizationHeader: c.req.header("authorization") ?? null,
|
|
46
|
+
bodyClientId: parsed.data.client_id,
|
|
47
|
+
bodyClientSecret: parsed.data.client_secret,
|
|
48
|
+
})
|
|
49
|
+
const res = await revokeToken(
|
|
50
|
+
{
|
|
51
|
+
token: parsed.data.token,
|
|
52
|
+
...(parsed.data.token_type_hint
|
|
53
|
+
? { tokenTypeHint: parsed.data.token_type_hint }
|
|
54
|
+
: {}),
|
|
55
|
+
...(creds ? { clientId: creds.clientId } : {}),
|
|
56
|
+
...(creds?.clientSecret !== undefined
|
|
57
|
+
? { clientSecret: creds.clientSecret }
|
|
58
|
+
: {}),
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
tokenStore: deps.tokenStore,
|
|
62
|
+
configStore: deps.configStore,
|
|
63
|
+
...(deps.auditLog ? { auditLog: deps.auditLog } : {}),
|
|
64
|
+
clock: deps.clock,
|
|
65
|
+
},
|
|
66
|
+
)
|
|
67
|
+
if (isErr(res)) return tokenEndpointErrorResponse(res.error)
|
|
68
|
+
// RFC 7009 §2.2: success returns 200 with empty body.
|
|
69
|
+
return new Response(null, {
|
|
70
|
+
status: 200,
|
|
71
|
+
headers: { "cache-control": "no-store" },
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function makeIntrospectHandler(deps: HttpDeps) {
|
|
77
|
+
return async (c: HttpContext): Promise<Response> => {
|
|
78
|
+
const body = await readForm(c.req.raw)
|
|
79
|
+
if (!body) {
|
|
80
|
+
return tokenEndpointErrorResponse(
|
|
81
|
+
authError.invalidRequest(
|
|
82
|
+
"body must be application/x-www-form-urlencoded",
|
|
83
|
+
),
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
const parsed = introspectBodySchema.safeParse(
|
|
87
|
+
Object.fromEntries(body.entries()),
|
|
88
|
+
)
|
|
89
|
+
if (!parsed.success) {
|
|
90
|
+
return tokenEndpointErrorResponse(
|
|
91
|
+
authError.invalidRequest(parsed.error.issues[0]?.message ?? "invalid"),
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
const creds = resolveClientCredentials({
|
|
95
|
+
authorizationHeader: c.req.header("authorization") ?? null,
|
|
96
|
+
bodyClientId: parsed.data.client_id,
|
|
97
|
+
bodyClientSecret: parsed.data.client_secret,
|
|
98
|
+
})
|
|
99
|
+
if (!creds) {
|
|
100
|
+
// RFC 7662 §2.1 — endpoint MUST require some form of auth.
|
|
101
|
+
return tokenEndpointErrorResponse(
|
|
102
|
+
authError.invalidClient("introspection requires client authentication"),
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
// Resolve the presenter's tenant from the request the same way the
|
|
106
|
+
// m2m grant does — by injecting client_id into the URL so a
|
|
107
|
+
// canonical search-param resolver works for introspect too.
|
|
108
|
+
const tenantRes = await deps.resolveTenant(
|
|
109
|
+
injectResolverHints(c.req.raw, { client_id: creds.clientId }),
|
|
110
|
+
)
|
|
111
|
+
if (isErr(tenantRes)) {
|
|
112
|
+
return tokenEndpointErrorResponse(
|
|
113
|
+
authError.invalidClient(`unknown client "${creds.clientId}"`),
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
const res = await introspect(
|
|
117
|
+
{
|
|
118
|
+
token: parsed.data.token,
|
|
119
|
+
...(parsed.data.token_type_hint
|
|
120
|
+
? { tokenTypeHint: parsed.data.token_type_hint }
|
|
121
|
+
: {}),
|
|
122
|
+
clientId: creds.clientId,
|
|
123
|
+
...(creds.clientSecret !== undefined
|
|
124
|
+
? { clientSecret: creds.clientSecret }
|
|
125
|
+
: {}),
|
|
126
|
+
presenterTenantId: tenantRes.value,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
keyStore: deps.keyStore,
|
|
130
|
+
configStore: deps.configStore,
|
|
131
|
+
issuerUrl: c.get("issuerUrl"),
|
|
132
|
+
},
|
|
133
|
+
)
|
|
134
|
+
if (isErr(res)) return tokenEndpointErrorResponse(res.error)
|
|
135
|
+
return new Response(JSON.stringify(res.value), {
|
|
136
|
+
status: 200,
|
|
137
|
+
headers: {
|
|
138
|
+
"content-type": "application/json",
|
|
139
|
+
"cache-control": "no-store",
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function readForm(req: Request): Promise<URLSearchParams | null> {
|
|
146
|
+
const ct = req.headers.get("content-type") ?? ""
|
|
147
|
+
if (!ct.toLowerCase().startsWith("application/x-www-form-urlencoded")) {
|
|
148
|
+
return null
|
|
149
|
+
}
|
|
150
|
+
return new URLSearchParams(await req.text())
|
|
151
|
+
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `POST /token` handler.
|
|
3
|
+
*
|
|
4
|
+
* Accepts `application/x-www-form-urlencoded` (RFC 6749 §3.2). Discriminates
|
|
5
|
+
* on `grant_type`:
|
|
6
|
+
* - `authorization_code` → `exchangeCode`
|
|
7
|
+
* - `refresh_token` → `refreshTokens`
|
|
8
|
+
*
|
|
9
|
+
* `client_credentials` arrives in Phase 5 alongside the m2m method.
|
|
10
|
+
*
|
|
11
|
+
* Client authentication: secrets can ride either in the form body
|
|
12
|
+
* (`client_secret`) or in the `Authorization: Basic` header. Both are
|
|
13
|
+
* accepted; the header takes precedence.
|
|
14
|
+
*
|
|
15
|
+
* The token endpoint does NOT consult the tenant middleware — every code /
|
|
16
|
+
* refresh token carries its tenant on its payload, so the auth-code or
|
|
17
|
+
* refresh-token snapshot is authoritative.
|
|
18
|
+
*/
|
|
19
|
+
import { clientCredentialsGrant } from "../../domain/client-credentials"
|
|
20
|
+
import { exchangeCode } from "../../domain/token"
|
|
21
|
+
import { exchangeToken } from "../../domain/token-exchange"
|
|
22
|
+
import { refreshTokens } from "../../domain/refresh"
|
|
23
|
+
import { isErr } from "../../types/result"
|
|
24
|
+
import { authError } from "../../types/error"
|
|
25
|
+
|
|
26
|
+
import type { HttpContext, HttpDeps } from "../context"
|
|
27
|
+
import { tokenEndpointErrorResponse } from "../errors"
|
|
28
|
+
import { injectResolverHints } from "../resolver"
|
|
29
|
+
import { tokenRequestSchema } from "../schemas/token"
|
|
30
|
+
|
|
31
|
+
export function makeTokenHandler(deps: HttpDeps) {
|
|
32
|
+
return async (c: HttpContext): Promise<Response> => {
|
|
33
|
+
const body = await readFormBody(c.req.raw)
|
|
34
|
+
if (!body) {
|
|
35
|
+
return tokenEndpointErrorResponse(
|
|
36
|
+
authError.invalidRequest(
|
|
37
|
+
"body must be application/x-www-form-urlencoded",
|
|
38
|
+
),
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const basic = parseBasicAuth(c.req.header("authorization") ?? null)
|
|
43
|
+
if (basic) {
|
|
44
|
+
body.set("client_id", basic.id)
|
|
45
|
+
body.set("client_secret", basic.secret)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const parsed = tokenRequestSchema.safeParse(
|
|
49
|
+
Object.fromEntries(body.entries()),
|
|
50
|
+
)
|
|
51
|
+
if (!parsed.success) {
|
|
52
|
+
const first = parsed.error.issues[0]
|
|
53
|
+
// RFC 6749 §5.2 maps grant_type problems to `unsupported_grant_type`.
|
|
54
|
+
if (first?.path[0] === "grant_type") {
|
|
55
|
+
return tokenEndpointErrorResponse(
|
|
56
|
+
authError.unsupportedGrantType(
|
|
57
|
+
first.message ?? "unsupported grant_type",
|
|
58
|
+
),
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
return tokenEndpointErrorResponse(
|
|
62
|
+
authError.invalidRequest(first?.message ?? "invalid request"),
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
const req = parsed.data
|
|
66
|
+
|
|
67
|
+
if (req.grant_type === "authorization_code") {
|
|
68
|
+
const result = await exchangeCode(
|
|
69
|
+
{
|
|
70
|
+
grantType: "authorization_code",
|
|
71
|
+
code: req.code,
|
|
72
|
+
redirectUri: req.redirect_uri,
|
|
73
|
+
clientId: req.client_id,
|
|
74
|
+
...(req.client_secret !== undefined
|
|
75
|
+
? { clientSecret: req.client_secret }
|
|
76
|
+
: {}),
|
|
77
|
+
...(req.code_verifier !== undefined
|
|
78
|
+
? { codeVerifier: req.code_verifier }
|
|
79
|
+
: {}),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
configStore: deps.configStore,
|
|
83
|
+
tokenStore: deps.tokenStore,
|
|
84
|
+
keyStore: deps.keyStore,
|
|
85
|
+
...(deps.auditLog ? { auditLog: deps.auditLog } : {}),
|
|
86
|
+
success: deps.success,
|
|
87
|
+
...(deps.persistUpstreamTokens
|
|
88
|
+
? { persistUpstreamTokens: deps.persistUpstreamTokens }
|
|
89
|
+
: {}),
|
|
90
|
+
issuerUrl: c.get("issuerUrl"),
|
|
91
|
+
clock: deps.clock,
|
|
92
|
+
},
|
|
93
|
+
)
|
|
94
|
+
if (isErr(result)) return tokenEndpointErrorResponse(result.error)
|
|
95
|
+
return jsonResponse(result.value)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (req.grant_type === "client_credentials") {
|
|
99
|
+
// Resolve tenant — client_credentials carries no auth code, so we
|
|
100
|
+
// call the user-supplied resolver against the /token request. The
|
|
101
|
+
// canonical resolver pattern (INTEGRATION.md §5.1) reads `client_id`
|
|
102
|
+
// from URL search params, but the m2m grant carries client_id in the
|
|
103
|
+
// form body / Basic auth — never the URL. Inject the parsed
|
|
104
|
+
// `client_id` into a synthesized request so resolvers using the
|
|
105
|
+
// canonical pattern work for m2m without an extra hook.
|
|
106
|
+
const tenantRes = await deps.resolveTenant(
|
|
107
|
+
injectResolverHints(c.req.raw, { client_id: req.client_id }),
|
|
108
|
+
)
|
|
109
|
+
if (isErr(tenantRes)) {
|
|
110
|
+
return tokenEndpointErrorResponse(tenantRes.error)
|
|
111
|
+
}
|
|
112
|
+
const params: Record<string, string> = {}
|
|
113
|
+
for (const [k, v] of body.entries()) {
|
|
114
|
+
if (typeof v === "string") params[k] = v
|
|
115
|
+
}
|
|
116
|
+
const result = await clientCredentialsGrant(
|
|
117
|
+
{
|
|
118
|
+
grantType: "client_credentials",
|
|
119
|
+
clientId: req.client_id,
|
|
120
|
+
clientSecret: req.client_secret,
|
|
121
|
+
...(req.scope !== undefined ? { scope: req.scope } : {}),
|
|
122
|
+
params,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
configStore: deps.configStore,
|
|
126
|
+
tokenStore: deps.tokenStore,
|
|
127
|
+
keyStore: deps.keyStore,
|
|
128
|
+
...(deps.auditLog ? { auditLog: deps.auditLog } : {}),
|
|
129
|
+
methodCache: deps.methodCache,
|
|
130
|
+
success: deps.success,
|
|
131
|
+
...(deps.persistUpstreamTokens
|
|
132
|
+
? { persistUpstreamTokens: deps.persistUpstreamTokens }
|
|
133
|
+
: {}),
|
|
134
|
+
issuerUrl: c.get("issuerUrl"),
|
|
135
|
+
clock: deps.clock,
|
|
136
|
+
},
|
|
137
|
+
tenantRes.value,
|
|
138
|
+
)
|
|
139
|
+
if (isErr(result)) return tokenEndpointErrorResponse(result.error)
|
|
140
|
+
return jsonResponse(result.value)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (req.grant_type === "refresh_token") {
|
|
144
|
+
const refreshResult = await refreshTokens(
|
|
145
|
+
{
|
|
146
|
+
grantType: "refresh_token",
|
|
147
|
+
refreshToken: req.refresh_token,
|
|
148
|
+
...(req.scope !== undefined ? { scope: req.scope } : {}),
|
|
149
|
+
...(req.client_id !== undefined ? { clientId: req.client_id } : {}),
|
|
150
|
+
...(req.client_secret !== undefined
|
|
151
|
+
? { clientSecret: req.client_secret }
|
|
152
|
+
: {}),
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
configStore: deps.configStore,
|
|
156
|
+
tokenStore: deps.tokenStore,
|
|
157
|
+
keyStore: deps.keyStore,
|
|
158
|
+
...(deps.auditLog ? { auditLog: deps.auditLog } : {}),
|
|
159
|
+
issuerUrl: c.get("issuerUrl"),
|
|
160
|
+
clock: deps.clock,
|
|
161
|
+
},
|
|
162
|
+
)
|
|
163
|
+
if (isErr(refreshResult))
|
|
164
|
+
return tokenEndpointErrorResponse(refreshResult.error)
|
|
165
|
+
return jsonResponse(refreshResult.value)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// RFC 8693 token-exchange. Delegation (actor_token) is out of scope;
|
|
169
|
+
// reject up front so we don't silently accept an actor and ignore it.
|
|
170
|
+
if (req.actor_token !== undefined) {
|
|
171
|
+
return tokenEndpointErrorResponse(
|
|
172
|
+
authError.invalidRequest(
|
|
173
|
+
"actor_token (delegation) is not supported; only impersonation / audience-switch is in scope",
|
|
174
|
+
),
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
const exchangeResult = await exchangeToken(
|
|
178
|
+
{
|
|
179
|
+
grantType: req.grant_type,
|
|
180
|
+
subjectToken: req.subject_token,
|
|
181
|
+
audience: req.audience,
|
|
182
|
+
...(req.scope !== undefined ? { scope: req.scope } : {}),
|
|
183
|
+
...(req.client_id !== undefined ? { clientId: req.client_id } : {}),
|
|
184
|
+
...(req.client_secret !== undefined
|
|
185
|
+
? { clientSecret: req.client_secret }
|
|
186
|
+
: {}),
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
configStore: deps.configStore,
|
|
190
|
+
tokenStore: deps.tokenStore,
|
|
191
|
+
keyStore: deps.keyStore,
|
|
192
|
+
...(deps.auditLog ? { auditLog: deps.auditLog } : {}),
|
|
193
|
+
...(deps.exchangeAudience
|
|
194
|
+
? { exchangeAudience: deps.exchangeAudience }
|
|
195
|
+
: {}),
|
|
196
|
+
issuerUrl: c.get("issuerUrl"),
|
|
197
|
+
clock: deps.clock,
|
|
198
|
+
},
|
|
199
|
+
)
|
|
200
|
+
if (isErr(exchangeResult)) {
|
|
201
|
+
return tokenEndpointErrorResponse(exchangeResult.error)
|
|
202
|
+
}
|
|
203
|
+
return jsonResponse(exchangeResult.value)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function jsonResponse(body: unknown): Response {
|
|
208
|
+
return new Response(JSON.stringify(body), {
|
|
209
|
+
status: 200,
|
|
210
|
+
headers: {
|
|
211
|
+
"content-type": "application/json",
|
|
212
|
+
"cache-control": "no-store",
|
|
213
|
+
pragma: "no-cache",
|
|
214
|
+
},
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function readFormBody(req: Request): Promise<URLSearchParams | null> {
|
|
219
|
+
const ct = req.headers.get("content-type") ?? ""
|
|
220
|
+
if (!ct.toLowerCase().startsWith("application/x-www-form-urlencoded")) {
|
|
221
|
+
return null
|
|
222
|
+
}
|
|
223
|
+
const text = await req.text()
|
|
224
|
+
return new URLSearchParams(text)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function parseBasicAuth(
|
|
228
|
+
header: string | null,
|
|
229
|
+
): { id: string; secret: string } | null {
|
|
230
|
+
if (!header) return null
|
|
231
|
+
const m = /^Basic\s+(.+)$/i.exec(header)
|
|
232
|
+
if (!m || !m[1]) return null
|
|
233
|
+
try {
|
|
234
|
+
const decoded = atob(m[1])
|
|
235
|
+
const colon = decoded.indexOf(":")
|
|
236
|
+
if (colon === -1) return null
|
|
237
|
+
return {
|
|
238
|
+
id: decodeURIComponent(decoded.slice(0, colon)),
|
|
239
|
+
secret: decodeURIComponent(decoded.slice(colon + 1)),
|
|
240
|
+
}
|
|
241
|
+
} catch {
|
|
242
|
+
return null
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OIDC `/userinfo` handler (OIDC Core §5.3). Accepts `GET` or `POST` per
|
|
3
|
+
* the spec.
|
|
4
|
+
*/
|
|
5
|
+
import { userinfo } from "../../domain/userinfo"
|
|
6
|
+
import { isErr } from "../../types/result"
|
|
7
|
+
|
|
8
|
+
import type { HttpContext, HttpDeps } from "../context"
|
|
9
|
+
|
|
10
|
+
export function makeUserinfoHandler(deps: HttpDeps) {
|
|
11
|
+
return async (c: HttpContext): Promise<Response> => {
|
|
12
|
+
const bearer = extractBearer(c.req.header("authorization") ?? null)
|
|
13
|
+
if (!bearer) {
|
|
14
|
+
const r = new Response(
|
|
15
|
+
JSON.stringify({
|
|
16
|
+
error: "invalid_token",
|
|
17
|
+
error_description: "missing bearer token",
|
|
18
|
+
}),
|
|
19
|
+
{
|
|
20
|
+
status: 401,
|
|
21
|
+
headers: {
|
|
22
|
+
"content-type": "application/json",
|
|
23
|
+
"www-authenticate": 'Bearer realm="userinfo"',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
)
|
|
27
|
+
return r
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const res = await userinfo(bearer, {
|
|
31
|
+
keyStore: deps.keyStore,
|
|
32
|
+
issuerUrl: c.get("issuerUrl"),
|
|
33
|
+
})
|
|
34
|
+
if (isErr(res)) {
|
|
35
|
+
// OIDC userinfo returns 401 on invalid token (vs. 400 elsewhere).
|
|
36
|
+
const err = res.error
|
|
37
|
+
return new Response(
|
|
38
|
+
JSON.stringify({
|
|
39
|
+
error: "invalid_token",
|
|
40
|
+
error_description: err.description,
|
|
41
|
+
}),
|
|
42
|
+
{
|
|
43
|
+
status: 401,
|
|
44
|
+
headers: {
|
|
45
|
+
"content-type": "application/json",
|
|
46
|
+
"www-authenticate": `Bearer error="invalid_token"`,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return new Response(JSON.stringify(res.value), {
|
|
53
|
+
status: 200,
|
|
54
|
+
headers: {
|
|
55
|
+
"content-type": "application/json",
|
|
56
|
+
"cache-control": "no-store",
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function extractBearer(header: string | null): string | null {
|
|
63
|
+
if (!header) return null
|
|
64
|
+
const m = /^Bearer\s+(.+)$/i.exec(header)
|
|
65
|
+
return m?.[1] ?? null
|
|
66
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global error middleware. Catches thrown values and serializes them as
|
|
3
|
+
* OAuth-compliant responses. Inside handlers we route through `Result<T,
|
|
4
|
+
* AuthError>` instead — this is the last-resort net for unexpected throws.
|
|
5
|
+
*/
|
|
6
|
+
import type { MiddlewareHandler } from "hono"
|
|
7
|
+
|
|
8
|
+
import { authError } from "../../types/error"
|
|
9
|
+
|
|
10
|
+
import type { HttpDeps, HttpEnv } from "../context"
|
|
11
|
+
import { tokenEndpointErrorResponse } from "../errors"
|
|
12
|
+
|
|
13
|
+
export function errorMiddleware(_deps: HttpDeps): MiddlewareHandler<HttpEnv> {
|
|
14
|
+
return async (_c, next) => {
|
|
15
|
+
try {
|
|
16
|
+
await next()
|
|
17
|
+
} catch (e) {
|
|
18
|
+
return tokenEndpointErrorResponse(
|
|
19
|
+
authError.serverError(
|
|
20
|
+
e instanceof Error ? e.message : "unexpected error",
|
|
21
|
+
e,
|
|
22
|
+
),
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant resolution + callback-recovery middleware.
|
|
3
|
+
*
|
|
4
|
+
* Phase 3 ships the mac-state recovery path. Mechanisms #2 (partitioned
|
|
5
|
+
* host) and #3 (`flowId`-in-URI) are scaffolded but not yet plumbed end-to-
|
|
6
|
+
* end (per plan §"Phase 2 — Deferred"); the framework currently falls back
|
|
7
|
+
* to `resolveTenant` when the state envelope is absent or invalid, so users
|
|
8
|
+
* who want partitioned-host deployments can implement the lookup inside
|
|
9
|
+
* their own `resolveTenant`.
|
|
10
|
+
*
|
|
11
|
+
* Order on `/cb/*`:
|
|
12
|
+
* 1. If `state` MAC-verifies → `mac-state`. `resolveTenant` is NOT called.
|
|
13
|
+
* 2. Else fall through to `resolveTenant` (host-plus-* deployments do the
|
|
14
|
+
* host inspection there).
|
|
15
|
+
*
|
|
16
|
+
* Order on all other paths: `resolveTenant` directly.
|
|
17
|
+
*/
|
|
18
|
+
import type { MiddlewareHandler } from "hono"
|
|
19
|
+
|
|
20
|
+
import { verifyStateEnvelope } from "../../domain/state-envelope"
|
|
21
|
+
import { isErr } from "../../types/result"
|
|
22
|
+
import type {
|
|
23
|
+
TenantConfig,
|
|
24
|
+
TenantContext,
|
|
25
|
+
TenantId,
|
|
26
|
+
TenantRecovery,
|
|
27
|
+
} from "../../types/tenant"
|
|
28
|
+
|
|
29
|
+
import { parseCookieHeader } from "../cookies"
|
|
30
|
+
import type { HttpDeps, HttpEnv } from "../context"
|
|
31
|
+
import {
|
|
32
|
+
authorizeDirectErrorResponse,
|
|
33
|
+
tokenEndpointErrorResponse,
|
|
34
|
+
} from "../errors"
|
|
35
|
+
import { authError } from "../../types/error"
|
|
36
|
+
|
|
37
|
+
function isCallbackPath(pathname: string): boolean {
|
|
38
|
+
return pathname.startsWith("/cb/")
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Initial pass — parse cookies + resolve issuer URL. Runs unconditionally.
|
|
43
|
+
*/
|
|
44
|
+
export function bootstrapMiddleware(
|
|
45
|
+
deps: HttpDeps,
|
|
46
|
+
): MiddlewareHandler<HttpEnv> {
|
|
47
|
+
return async (c, next) => {
|
|
48
|
+
const cookies = parseCookieHeader(c.req.header("cookie") ?? null)
|
|
49
|
+
c.set("cookies", cookies)
|
|
50
|
+
c.set("issuerUrl", deps.resolveIssuer(c.req.raw))
|
|
51
|
+
c.set("tenant", null)
|
|
52
|
+
c.set("recovery", null)
|
|
53
|
+
await next()
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Tenant + recovery resolution middleware. Mount on routes that need a
|
|
59
|
+
* tenant in scope (`/authorize`, method dispatch, `/cb/*`). Token endpoints
|
|
60
|
+
* derive tenant from the auth code's snapshot — they skip this middleware.
|
|
61
|
+
*/
|
|
62
|
+
export function tenantMiddleware(deps: HttpDeps): MiddlewareHandler<HttpEnv> {
|
|
63
|
+
return async (c, next) => {
|
|
64
|
+
const url = new URL(c.req.url)
|
|
65
|
+
|
|
66
|
+
if (isCallbackPath(url.pathname)) {
|
|
67
|
+
const recovery = await runCallbackRecovery(c.req.raw, deps)
|
|
68
|
+
c.set("recovery", recovery)
|
|
69
|
+
if (recovery.kind !== "fresh-request") {
|
|
70
|
+
const cfg = await deps.configStore.getTenantConfig(recovery.tenantId)
|
|
71
|
+
if (isErr(cfg)) {
|
|
72
|
+
return tokenEndpointErrorResponse(cfg.error)
|
|
73
|
+
}
|
|
74
|
+
const customCb = deps.buildCustomContext
|
|
75
|
+
? await deps.buildCustomContext(c.req.raw)
|
|
76
|
+
: {}
|
|
77
|
+
c.set(
|
|
78
|
+
"tenant",
|
|
79
|
+
buildTenantContext(c.req.raw, recovery.tenantId, cfg.value, customCb),
|
|
80
|
+
)
|
|
81
|
+
return next()
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const resolved = await deps.resolveTenant(c.req.raw)
|
|
86
|
+
if (isErr(resolved)) {
|
|
87
|
+
// For /authorize, surface as plain text (open-redirector defense — we
|
|
88
|
+
// don't have a verified RP yet). For other paths, JSON suffices.
|
|
89
|
+
if (url.pathname === "/authorize") {
|
|
90
|
+
return authorizeDirectErrorResponse(resolved.error)
|
|
91
|
+
}
|
|
92
|
+
return tokenEndpointErrorResponse(resolved.error)
|
|
93
|
+
}
|
|
94
|
+
const tenantId = resolved.value
|
|
95
|
+
const cfg = await deps.configStore.getTenantConfig(tenantId)
|
|
96
|
+
if (isErr(cfg)) {
|
|
97
|
+
const err =
|
|
98
|
+
cfg.error.code === "tenant_not_found"
|
|
99
|
+
? authError.invalidRequest(cfg.error.description, "tenant")
|
|
100
|
+
: cfg.error
|
|
101
|
+
if (url.pathname === "/authorize") {
|
|
102
|
+
return authorizeDirectErrorResponse(err)
|
|
103
|
+
}
|
|
104
|
+
return tokenEndpointErrorResponse(err)
|
|
105
|
+
}
|
|
106
|
+
const custom = deps.buildCustomContext
|
|
107
|
+
? await deps.buildCustomContext(c.req.raw)
|
|
108
|
+
: {}
|
|
109
|
+
c.set("tenant", buildTenantContext(c.req.raw, tenantId, cfg.value, custom))
|
|
110
|
+
await next()
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function buildTenantContext(
|
|
115
|
+
req: Request,
|
|
116
|
+
id: TenantId,
|
|
117
|
+
config: TenantConfig,
|
|
118
|
+
custom: Record<string, unknown>,
|
|
119
|
+
): TenantContext {
|
|
120
|
+
return {
|
|
121
|
+
id,
|
|
122
|
+
config,
|
|
123
|
+
request: { raw: req, custom },
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function runCallbackRecovery(
|
|
128
|
+
req: Request,
|
|
129
|
+
deps: HttpDeps,
|
|
130
|
+
): Promise<TenantRecovery> {
|
|
131
|
+
const state = await extractStateParam(req)
|
|
132
|
+
if (state) {
|
|
133
|
+
const env = await verifyStateEnvelope(state, deps.stateKeys)
|
|
134
|
+
if (env.ok) {
|
|
135
|
+
return {
|
|
136
|
+
kind: "mac-state",
|
|
137
|
+
tenantId: env.value.tenantId,
|
|
138
|
+
flowId: env.value.flowId,
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { kind: "fresh-request" }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Pull `state` from the query for GET callbacks, or from a form body for
|
|
147
|
+
* POST callbacks (Apple's `response_mode=form_post`). The body is cloned
|
|
148
|
+
* so the handler can still read it.
|
|
149
|
+
*/
|
|
150
|
+
async function extractStateParam(req: Request): Promise<string | null> {
|
|
151
|
+
const url = new URL(req.url)
|
|
152
|
+
const fromQuery = url.searchParams.get("state")
|
|
153
|
+
if (fromQuery) return fromQuery
|
|
154
|
+
if (req.method !== "POST") return null
|
|
155
|
+
const ct = req.headers.get("content-type") ?? ""
|
|
156
|
+
if (!ct.toLowerCase().startsWith("application/x-www-form-urlencoded")) {
|
|
157
|
+
return null
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const text = await req.clone().text()
|
|
161
|
+
return new URLSearchParams(text).get("state")
|
|
162
|
+
} catch {
|
|
163
|
+
return null
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers that prepare a `Request` for the host-supplied
|
|
3
|
+
* `IdPOptions.resolveTenant` hook.
|
|
4
|
+
*
|
|
5
|
+
* The canonical resolver reads `client_id` from URL search params
|
|
6
|
+
* (INTEGRATION.md §5.1). On endpoints where `client_id` is carried in
|
|
7
|
+
* the form body / Basic-auth header rather than the URL (m2m at
|
|
8
|
+
* `/token`, introspect at `/introspect`, revoke at `/revoke`) the
|
|
9
|
+
* framework parses the body first and then injects the parsed
|
|
10
|
+
* `client_id` into a synthesized request so the resolver still sees
|
|
11
|
+
* what it expects.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Build a new `Request` whose URL search params carry the supplied
|
|
16
|
+
* resolver hints. Existing query params win — hosts can still override
|
|
17
|
+
* via the URL. Headers are copied so Basic-auth-based resolvers still
|
|
18
|
+
* see the original `Authorization`. The body is intentionally dropped:
|
|
19
|
+
* the original is already consumed by the handler and resolvers must
|
|
20
|
+
* not depend on body state.
|
|
21
|
+
*/
|
|
22
|
+
export function injectResolverHints(
|
|
23
|
+
original: Request,
|
|
24
|
+
hints: Record<string, string>,
|
|
25
|
+
): Request {
|
|
26
|
+
const url = new URL(original.url)
|
|
27
|
+
for (const [k, v] of Object.entries(hints)) {
|
|
28
|
+
if (!url.searchParams.has(k)) url.searchParams.set(k, v)
|
|
29
|
+
}
|
|
30
|
+
return new Request(url.toString(), {
|
|
31
|
+
method: original.method,
|
|
32
|
+
headers: original.headers,
|
|
33
|
+
})
|
|
34
|
+
}
|