@udibo/oauth2 0.14.1 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -24
- package/{esm → dist}/adapters/hono/_common.d.ts +5 -5
- package/{esm → dist}/adapters/hono/_common.js +1 -1
- package/{esm → dist}/adapters/hono/authorization-server.d.ts +6 -7
- package/{esm → dist}/adapters/hono/authorization-server.js +0 -1
- package/{esm → dist}/adapters/hono/bff/auth-request-store.d.ts +2 -2
- package/{esm → dist}/adapters/hono/bff/auth-request-store.js +2 -2
- package/{esm → dist}/adapters/hono/bff/bff.d.ts +8 -8
- package/{esm → dist}/adapters/hono/bff/bff.js +33 -27
- package/{esm → dist}/adapters/hono/bff/cookie-prefix.js +1 -2
- package/{esm → dist}/adapters/hono/bff/mod.d.ts +5 -6
- package/{esm → dist}/adapters/hono/bff/mod.js +1 -2
- package/{esm → dist}/adapters/hono/bff/proxy.js +2 -1
- package/{esm → dist}/adapters/hono/bff/session-store.d.ts +2 -2
- package/{esm → dist}/adapters/hono/bff/session-store.js +7 -6
- package/{esm → dist}/adapters/hono/bff/testing.d.ts +7 -8
- package/{esm → dist}/adapters/hono/bff/testing.js +19 -22
- package/{esm → dist}/adapters/hono/identity.d.ts +1 -2
- package/{esm → dist}/adapters/hono/identity.js +10 -10
- package/{esm → dist}/adapters/hono/log.d.ts +0 -1
- package/{esm → dist}/adapters/hono/log.js +0 -6
- package/{esm → dist}/adapters/hono/resource-server.d.ts +5 -6
- package/{esm → dist}/adapters/hono/resource-server.js +0 -1
- package/dist/cli/bin.d.ts +2 -0
- package/dist/cli/bin.js +3 -0
- package/dist/cli/idp/config.d.ts +110 -0
- package/dist/cli/idp/config.js +269 -0
- package/dist/cli/idp/mod.d.ts +20 -0
- package/dist/cli/idp/mod.js +175 -0
- package/dist/cli/idp/pages.d.ts +56 -0
- package/dist/cli/idp/pages.js +190 -0
- package/dist/cli/idp/server.d.ts +93 -0
- package/dist/cli/idp/server.js +559 -0
- package/dist/cli/keygen.d.ts +13 -0
- package/dist/cli/keygen.js +30 -0
- package/dist/cli/mod.d.ts +34 -0
- package/dist/cli/mod.js +94 -0
- package/{esm → dist}/client/_http.d.ts +1 -1
- package/{esm → dist}/client/base.d.ts +1 -1
- package/{esm → dist}/client/bff-client.d.ts +1 -1
- package/{esm → dist}/client/bff-client.js +7 -6
- package/{esm → dist}/client/browser-storage.d.ts +1 -1
- package/{esm → dist}/client/check.js +1 -1
- package/{esm → dist}/client/direct-client.d.ts +6 -6
- package/{esm → dist}/client/direct-client.js +11 -13
- package/{esm → dist}/client/discovery-cache.d.ts +1 -1
- package/{esm → dist}/client/discovery-cache.js +2 -2
- package/{esm → dist}/client/events.d.ts +1 -1
- package/{esm → dist}/client/mod.d.ts +11 -12
- package/{esm → dist}/client/mod.js +1 -1
- package/{esm → dist}/errors.d.ts +1 -1
- package/{esm → dist}/errors.js +1 -1
- package/{esm → dist}/identity/events.d.ts +1 -1
- package/{esm → dist}/identity/external/_shared.d.ts +1 -1
- package/{esm → dist}/identity/external/_shared.js +1 -2
- package/{esm → dist}/identity/external/apple-client-secret.d.ts +1 -1
- package/{esm → dist}/identity/external/apple-client-secret.js +6 -7
- package/{esm → dist}/identity/external/apple.d.ts +5 -5
- package/{esm → dist}/identity/external/apple.js +10 -11
- package/{esm → dist}/identity/external/discord.d.ts +3 -3
- package/{esm → dist}/identity/external/discord.js +2 -2
- package/{esm → dist}/identity/external/flow.d.ts +1 -1
- package/{esm → dist}/identity/external/flow.js +2 -2
- package/{esm → dist}/identity/external/github.d.ts +3 -3
- package/{esm → dist}/identity/external/github.js +12 -17
- package/{esm → dist}/identity/external/google.d.ts +5 -5
- package/{esm → dist}/identity/external/google.js +2 -2
- package/{esm → dist}/identity/external/mod.d.ts +12 -13
- package/{esm → dist}/identity/external/mod.js +0 -1
- package/{esm → dist}/identity/external/oauth2.d.ts +1 -1
- package/{esm → dist}/identity/external/oauth2.js +8 -8
- package/{esm → dist}/identity/external/oidc.d.ts +4 -4
- package/{esm → dist}/identity/external/oidc.js +9 -8
- package/{esm → dist}/identity/hibp.d.ts +1 -1
- package/{esm → dist}/identity/hibp.js +1 -1
- package/{esm → dist}/identity/lockout.js +1 -2
- package/{esm → dist}/identity/mfa/mod.d.ts +4 -5
- package/{esm → dist}/identity/mfa/mod.js +1 -2
- package/{esm → dist}/identity/mfa/service.d.ts +3 -3
- package/{esm → dist}/identity/mfa/service.js +4 -3
- package/{esm → dist}/identity/mfa/totp.d.ts +1 -1
- package/{esm → dist}/identity/mfa/totp.js +2 -2
- package/{esm → dist}/identity/migration.d.ts +2 -3
- package/{esm → dist}/identity/migration.js +3 -4
- package/{esm → dist}/identity/mod.d.ts +14 -15
- package/{esm → dist}/identity/mod.js +0 -1
- package/{esm → dist}/identity/otp.d.ts +1 -1
- package/{esm → dist}/identity/otp.js +4 -2
- package/{esm → dist}/identity/password.js +8 -5
- package/{esm → dist}/identity/rate-limit.d.ts +1 -1
- package/{esm → dist}/identity/service.d.ts +10 -10
- package/{esm → dist}/identity/service.js +17 -18
- package/{esm → dist}/identity/session.js +2 -2
- package/{esm → dist}/identity/token-flow.js +3 -2
- package/{esm → dist}/models/authorization-code.d.ts +3 -3
- package/{esm → dist}/models/authorization.d.ts +1 -1
- package/{esm → dist}/models/authorization.js +1 -2
- package/{esm → dist}/models/device-authorization.d.ts +2 -2
- package/{esm → dist}/models/token.d.ts +3 -3
- package/{esm → dist}/react/callback.d.ts +1 -1
- package/{esm → dist}/react/callback.js +0 -1
- package/{esm → dist}/react/components/class-names.d.ts +1 -1
- package/{esm → dist}/react/components/class-names.js +3 -2
- package/{esm → dist}/react/components/internal.d.ts +2 -2
- package/{esm → dist}/react/components/internal.js +5 -11
- package/{esm → dist}/react/components/mfa-challenge-form.d.ts +2 -2
- package/{esm → dist}/react/components/mfa-challenge-form.js +4 -6
- package/{esm → dist}/react/components/mfa-enrollment-form.d.ts +2 -2
- package/{esm → dist}/react/components/mfa-enrollment-form.js +2 -6
- package/{esm → dist}/react/components/mod.d.ts +20 -21
- package/{esm → dist}/react/components/mod.js +1 -2
- package/{esm → dist}/react/components/request-password-reset-form.d.ts +2 -2
- package/{esm → dist}/react/components/request-password-reset-form.js +1 -3
- package/{esm → dist}/react/components/reset-password-form.d.ts +2 -2
- package/{esm → dist}/react/components/reset-password-form.js +2 -2
- package/{esm → dist}/react/components/sign-in-form.d.ts +2 -2
- package/{esm → dist}/react/components/sign-in-form.js +1 -5
- package/{esm → dist}/react/components/sign-up-form.d.ts +2 -2
- package/{esm → dist}/react/components/sign-up-form.js +4 -10
- package/{esm → dist}/react/components/types.d.ts +2 -2
- package/{esm → dist}/react/components/use-auth-form.d.ts +3 -3
- package/{esm → dist}/react/components/use-auth-form.js +4 -7
- package/{esm → dist}/react/components/user-menu.d.ts +2 -2
- package/{esm → dist}/react/components/user-menu.js +9 -14
- package/{esm → dist}/react/context.d.ts +1 -1
- package/{esm → dist}/react/mod.d.ts +6 -7
- package/{esm → dist}/react/mod.js +0 -1
- package/{esm → dist}/react/provider.d.ts +2 -2
- package/{esm → dist}/react/require-auth.js +1 -3
- package/{esm → dist}/react/testing.d.ts +2 -3
- package/{esm → dist}/react/testing.js +1 -2
- package/{esm → dist}/react/use-authorization.d.ts +1 -1
- package/{esm → dist}/react/use-oauth2.d.ts +8 -1
- package/{esm → dist}/react/use-oauth2.js +0 -1
- package/{esm → dist}/server/_clock-skew.js +2 -1
- package/{esm → dist}/server/authorization-server.d.ts +40 -41
- package/{esm → dist}/server/authorization-server.js +32 -42
- package/{esm → dist}/server/client-authentication.d.ts +2 -2
- package/{esm → dist}/server/grants/authorization-code.d.ts +9 -9
- package/{esm → dist}/server/grants/authorization-code.js +5 -6
- package/{esm → dist}/server/grants/client-credentials.d.ts +4 -4
- package/{esm → dist}/server/grants/device-authorization.d.ts +6 -6
- package/{esm → dist}/server/grants/device-authorization.js +4 -4
- package/{esm → dist}/server/grants/grant.d.ts +7 -7
- package/{esm → dist}/server/grants/grant.js +7 -7
- package/{esm → dist}/server/grants/password.d.ts +5 -5
- package/{esm → dist}/server/grants/refresh-token.d.ts +4 -4
- package/{esm → dist}/server/grants/refresh-token.js +5 -6
- package/{esm → dist}/server/introspection-token-reader.d.ts +5 -5
- package/{esm → dist}/server/introspection-token-reader.js +4 -4
- package/{esm → dist}/server/jwks-token-reader.d.ts +5 -5
- package/{esm → dist}/server/jwks-token-reader.js +4 -4
- package/{esm → dist}/server/mod.d.ts +12 -13
- package/{esm → dist}/server/mod.js +0 -1
- package/{esm → dist}/server/public-suffix/mod.d.ts +2 -3
- package/{esm → dist}/server/public-suffix/mod.js +1 -2
- package/{esm → dist}/server/public-suffix/rules.d.ts +1 -1
- package/{esm → dist}/server/public-suffix/rules.js +1 -1
- package/{esm → dist}/server/redirect-uri.js +5 -4
- package/{esm → dist}/server/resource-server.d.ts +11 -12
- package/{esm → dist}/server/resource-server.js +12 -14
- package/{esm → dist}/server/services/authorization-code.d.ts +5 -5
- package/{esm → dist}/server/services/client.d.ts +1 -1
- package/{esm → dist}/server/services/device-authorization.d.ts +3 -3
- package/{esm → dist}/server/services/token.d.ts +6 -6
- package/{esm → dist}/server/services/token.js +3 -1
- package/{esm → dist}/server/services/user.d.ts +1 -1
- package/{esm → dist}/server/signing-keys.d.ts +1 -1
- package/{esm → dist}/server/signing-keys.js +8 -2
- package/{esm → dist}/server/utils/hash.js +1 -1
- package/{esm → dist}/testing/contract/auth-request-storage.d.ts +1 -1
- package/{esm → dist}/testing/contract/auth-request-storage.js +24 -29
- package/{esm → dist}/testing/contract/authorization-code.d.ts +6 -6
- package/{esm → dist}/testing/contract/authorization-code.js +16 -17
- package/{esm → dist}/testing/contract/client.d.ts +4 -4
- package/{esm → dist}/testing/contract/client.js +14 -15
- package/{esm → dist}/testing/contract/device-authorization.d.ts +6 -6
- package/{esm → dist}/testing/contract/device-authorization.js +37 -39
- package/{esm → dist}/testing/contract/identity-session.d.ts +6 -1
- package/{esm → dist}/testing/contract/identity-session.js +44 -36
- package/{esm → dist}/testing/contract/identity-user-store.d.ts +8 -2
- package/{esm → dist}/testing/contract/identity-user-store.js +48 -46
- package/{esm → dist}/testing/contract/lockout-store.d.ts +1 -1
- package/{esm → dist}/testing/contract/lockout-store.js +23 -24
- package/{esm → dist}/testing/contract/mfa-store.d.ts +1 -1
- package/{esm → dist}/testing/contract/mfa-store.js +53 -54
- package/{esm → dist}/testing/contract/mod.d.ts +15 -16
- package/{esm → dist}/testing/contract/mod.js +0 -1
- package/{esm → dist}/testing/contract/otp-store.d.ts +1 -1
- package/{esm → dist}/testing/contract/otp-store.js +33 -34
- package/{esm → dist}/testing/contract/rate-limit-store.d.ts +1 -1
- package/{esm → dist}/testing/contract/rate-limit-store.js +15 -16
- package/{esm → dist}/testing/contract/tenant.js +361 -330
- package/{esm → dist}/testing/contract/token-flow-store.d.ts +1 -1
- package/{esm → dist}/testing/contract/token-flow-store.js +27 -32
- package/{esm → dist}/testing/contract/token-reader.d.ts +3 -3
- package/{esm → dist}/testing/contract/token-reader.js +6 -7
- package/{esm → dist}/testing/contract/token.d.ts +7 -7
- package/{esm → dist}/testing/contract/token.js +48 -53
- package/{esm → dist}/testing/contract/user.d.ts +2 -2
- package/{esm → dist}/testing/contract/user.js +8 -9
- package/{esm → dist}/testing/mod.d.ts +5 -6
- package/{esm → dist}/testing/mod.js +2 -3
- package/{esm → dist}/testing/server.d.ts +7 -6
- package/{esm → dist}/testing/server.js +2 -1
- package/{esm → dist}/testing/services.d.ts +11 -11
- package/{esm → dist}/testing/services.js +8 -8
- package/{esm → dist}/testing/tenant.d.ts +11 -7
- package/{esm → dist}/testing/tenant.js +109 -94
- package/dist/utils/_constant-time.d.ts +12 -0
- package/dist/utils/_constant-time.js +19 -0
- package/{esm → dist}/utils/_default-fetch.js +4 -1
- package/dist/utils/_delay.d.ts +13 -0
- package/dist/utils/_delay.js +28 -0
- package/dist/utils/_encoding.d.ts +39 -0
- package/dist/utils/_encoding.js +126 -0
- package/dist/utils/_inbound-request.d.ts +15 -0
- package/dist/utils/_inbound-request.js +25 -0
- package/{esm → dist}/utils/authentication-context.d.ts +1 -1
- package/{esm → dist}/utils/crypto.d.ts +2 -3
- package/{esm → dist}/utils/crypto.js +3 -4
- package/{esm → dist}/utils/pkce.js +1 -1
- package/{esm → dist}/utils/text.js +1 -1
- package/{esm → dist}/utils/url.d.ts +0 -1
- package/{esm → dist}/utils/url.js +0 -1
- package/package.json +156 -33
- package/esm/_dnt.polyfills.d.ts +0 -31
- package/esm/_dnt.polyfills.js +0 -26
- package/esm/deps/jsr.io/@std/assert/1.0.19/almost_equals.d.ts +0 -29
- package/esm/deps/jsr.io/@std/assert/1.0.19/almost_equals.js +0 -47
- package/esm/deps/jsr.io/@std/assert/1.0.19/array_includes.d.ts +0 -28
- package/esm/deps/jsr.io/@std/assert/1.0.19/array_includes.js +0 -65
- package/esm/deps/jsr.io/@std/assert/1.0.19/assert.d.ts +0 -16
- package/esm/deps/jsr.io/@std/assert/1.0.19/assert.js +0 -23
- package/esm/deps/jsr.io/@std/assert/1.0.19/assertion_error.d.ts +0 -25
- package/esm/deps/jsr.io/@std/assert/1.0.19/assertion_error.js +0 -30
- package/esm/deps/jsr.io/@std/assert/1.0.19/equal.d.ts +0 -24
- package/esm/deps/jsr.io/@std/assert/1.0.19/equal.js +0 -193
- package/esm/deps/jsr.io/@std/assert/1.0.19/equals.d.ts +0 -36
- package/esm/deps/jsr.io/@std/assert/1.0.19/equals.js +0 -61
- package/esm/deps/jsr.io/@std/assert/1.0.19/exists.d.ts +0 -17
- package/esm/deps/jsr.io/@std/assert/1.0.19/exists.js +0 -27
- package/esm/deps/jsr.io/@std/assert/1.0.19/fail.d.ts +0 -14
- package/esm/deps/jsr.io/@std/assert/1.0.19/fail.js +0 -20
- package/esm/deps/jsr.io/@std/assert/1.0.19/false.d.ts +0 -18
- package/esm/deps/jsr.io/@std/assert/1.0.19/false.js +0 -23
- package/esm/deps/jsr.io/@std/assert/1.0.19/greater.d.ts +0 -19
- package/esm/deps/jsr.io/@std/assert/1.0.19/greater.js +0 -29
- package/esm/deps/jsr.io/@std/assert/1.0.19/greater_or_equal.d.ts +0 -19
- package/esm/deps/jsr.io/@std/assert/1.0.19/greater_or_equal.js +0 -29
- package/esm/deps/jsr.io/@std/assert/1.0.19/instance_of.d.ts +0 -22
- package/esm/deps/jsr.io/@std/assert/1.0.19/instance_of.js +0 -52
- package/esm/deps/jsr.io/@std/assert/1.0.19/is_error.d.ts +0 -24
- package/esm/deps/jsr.io/@std/assert/1.0.19/is_error.js +0 -53
- package/esm/deps/jsr.io/@std/assert/1.0.19/less.d.ts +0 -18
- package/esm/deps/jsr.io/@std/assert/1.0.19/less.js +0 -28
- package/esm/deps/jsr.io/@std/assert/1.0.19/less_or_equal.d.ts +0 -19
- package/esm/deps/jsr.io/@std/assert/1.0.19/less_or_equal.js +0 -29
- package/esm/deps/jsr.io/@std/assert/1.0.19/match.d.ts +0 -17
- package/esm/deps/jsr.io/@std/assert/1.0.19/match.js +0 -26
- package/esm/deps/jsr.io/@std/assert/1.0.19/mod.d.ts +0 -43
- package/esm/deps/jsr.io/@std/assert/1.0.19/mod.js +0 -45
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_equals.d.ts +0 -26
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_equals.js +0 -39
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_instance_of.d.ts +0 -19
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_instance_of.js +0 -29
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_match.d.ts +0 -17
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_match.js +0 -26
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_strict_equals.d.ts +0 -22
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_strict_equals.js +0 -32
- package/esm/deps/jsr.io/@std/assert/1.0.19/object_match.d.ts +0 -28
- package/esm/deps/jsr.io/@std/assert/1.0.19/object_match.js +0 -177
- package/esm/deps/jsr.io/@std/assert/1.0.19/rejects.d.ts +0 -41
- package/esm/deps/jsr.io/@std/assert/1.0.19/rejects.js +0 -53
- package/esm/deps/jsr.io/@std/assert/1.0.19/strict_equals.d.ts +0 -23
- package/esm/deps/jsr.io/@std/assert/1.0.19/strict_equals.js +0 -58
- package/esm/deps/jsr.io/@std/assert/1.0.19/string_includes.d.ts +0 -17
- package/esm/deps/jsr.io/@std/assert/1.0.19/string_includes.js +0 -26
- package/esm/deps/jsr.io/@std/assert/1.0.19/throws.d.ts +0 -44
- package/esm/deps/jsr.io/@std/assert/1.0.19/throws.js +0 -44
- package/esm/deps/jsr.io/@std/assert/1.0.19/unimplemented.d.ts +0 -14
- package/esm/deps/jsr.io/@std/assert/1.0.19/unimplemented.js +0 -20
- package/esm/deps/jsr.io/@std/assert/1.0.19/unreachable.d.ts +0 -14
- package/esm/deps/jsr.io/@std/assert/1.0.19/unreachable.js +0 -20
- package/esm/deps/jsr.io/@std/async/1.5.0/delay.d.ts +0 -44
- package/esm/deps/jsr.io/@std/async/1.5.0/delay.js +0 -84
- package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.d.ts +0 -39
- package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.js +0 -61
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common16.d.ts +0 -22
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common16.js +0 -51
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common32.d.ts +0 -34
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common32.js +0 -192
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common64.d.ts +0 -34
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common64.js +0 -113
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common_detach.d.ts +0 -3
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common_detach.js +0 -13
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_types.d.ts +0 -8
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_types.js +0 -2
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_validate_binary_like.d.ts +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_validate_binary_like.js +0 -26
- package/esm/deps/jsr.io/@std/encoding/1.0.11/ascii85.d.ts +0 -60
- package/esm/deps/jsr.io/@std/encoding/1.0.11/ascii85.js +0 -152
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base32.d.ts +0 -39
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base32.js +0 -87
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base58.d.ts +0 -39
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base58.js +0 -131
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base64.d.ts +0 -39
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base64.js +0 -82
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base64url.d.ts +0 -39
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base64url.js +0 -72
- package/esm/deps/jsr.io/@std/encoding/1.0.11/hex.d.ts +0 -38
- package/esm/deps/jsr.io/@std/encoding/1.0.11/hex.js +0 -87
- package/esm/deps/jsr.io/@std/encoding/1.0.11/mod.d.ts +0 -97
- package/esm/deps/jsr.io/@std/encoding/1.0.11/mod.js +0 -99
- package/esm/deps/jsr.io/@std/encoding/1.0.11/varint.d.ts +0 -119
- package/esm/deps/jsr.io/@std/encoding/1.0.11/varint.js +0 -209
- package/esm/deps/jsr.io/@std/http/1.1.3/status.d.ts +0 -343
- package/esm/deps/jsr.io/@std/http/1.1.3/status.js +0 -343
- package/esm/deps/jsr.io/@std/internal/1.0.14/assertion_state.d.ts +0 -159
- package/esm/deps/jsr.io/@std/internal/1.0.14/assertion_state.js +0 -223
- package/esm/deps/jsr.io/@std/internal/1.0.14/build_message.d.ts +0 -79
- package/esm/deps/jsr.io/@std/internal/1.0.14/build_message.js +0 -116
- package/esm/deps/jsr.io/@std/internal/1.0.14/diff.d.ts +0 -139
- package/esm/deps/jsr.io/@std/internal/1.0.14/diff.js +0 -277
- package/esm/deps/jsr.io/@std/internal/1.0.14/diff_str.d.ts +0 -98
- package/esm/deps/jsr.io/@std/internal/1.0.14/diff_str.js +0 -181
- package/esm/deps/jsr.io/@std/internal/1.0.14/format.d.ts +0 -29
- package/esm/deps/jsr.io/@std/internal/1.0.14/format.js +0 -68
- package/esm/deps/jsr.io/@std/internal/1.0.14/styles.d.ts +0 -158
- package/esm/deps/jsr.io/@std/internal/1.0.14/styles.js +0 -206
- package/esm/deps/jsr.io/@std/internal/1.0.14/types.d.ts +0 -24
- package/esm/deps/jsr.io/@std/internal/1.0.14/types.js +0 -3
- package/esm/deps/jsr.io/@std/testing/1.0.20/_test_suite.d.ts +0 -91
- package/esm/deps/jsr.io/@std/testing/1.0.20/_test_suite.js +0 -347
- package/esm/deps/jsr.io/@std/testing/1.0.20/bdd.d.ts +0 -382
- package/esm/deps/jsr.io/@std/testing/1.0.20/bdd.js +0 -1110
- package/esm/deps/jsr.io/@udibo/http-error/0.11.1/mod.d.ts +0 -363
- package/esm/deps/jsr.io/@udibo/http-error/0.11.1/mod.js +0 -616
- package/esm/package.json +0 -3
- /package/{esm → dist}/adapters/hono/bff/cookie-prefix.d.ts +0 -0
- /package/{esm → dist}/adapters/hono/bff/proxy.d.ts +0 -0
- /package/{esm → dist}/client/_http.js +0 -0
- /package/{esm → dist}/client/base.js +0 -0
- /package/{esm → dist}/client/browser-storage.js +0 -0
- /package/{esm → dist}/client/check.d.ts +0 -0
- /package/{esm → dist}/client/events.js +0 -0
- /package/{esm → dist}/client/storage.d.ts +0 -0
- /package/{esm → dist}/client/storage.js +0 -0
- /package/{esm → dist}/identity/captcha.d.ts +0 -0
- /package/{esm → dist}/identity/captcha.js +0 -0
- /package/{esm → dist}/identity/delivery.d.ts +0 -0
- /package/{esm → dist}/identity/delivery.js +0 -0
- /package/{esm → dist}/identity/errors.d.ts +0 -0
- /package/{esm → dist}/identity/errors.js +0 -0
- /package/{esm → dist}/identity/events.js +0 -0
- /package/{esm → dist}/identity/external/_token-exchange.d.ts +0 -0
- /package/{esm → dist}/identity/external/_token-exchange.js +0 -0
- /package/{esm → dist}/identity/external/errors.d.ts +0 -0
- /package/{esm → dist}/identity/external/errors.js +0 -0
- /package/{esm → dist}/identity/external/provider.d.ts +0 -0
- /package/{esm → dist}/identity/external/provider.js +0 -0
- /package/{esm → dist}/identity/identifier.d.ts +0 -0
- /package/{esm → dist}/identity/identifier.js +0 -0
- /package/{esm → dist}/identity/lockout.d.ts +0 -0
- /package/{esm → dist}/identity/mfa/recovery-codes.d.ts +0 -0
- /package/{esm → dist}/identity/mfa/recovery-codes.js +0 -0
- /package/{esm → dist}/identity/password-policy.d.ts +0 -0
- /package/{esm → dist}/identity/password-policy.js +0 -0
- /package/{esm → dist}/identity/password.d.ts +0 -0
- /package/{esm → dist}/identity/rate-limit.js +0 -0
- /package/{esm → dist}/identity/session.d.ts +0 -0
- /package/{esm → dist}/identity/token-flow.d.ts +0 -0
- /package/{esm → dist}/models/authentication.d.ts +0 -0
- /package/{esm → dist}/models/authentication.js +0 -0
- /package/{esm → dist}/models/authorization-code.js +0 -0
- /package/{esm → dist}/models/client.d.ts +0 -0
- /package/{esm → dist}/models/client.js +0 -0
- /package/{esm → dist}/models/device-authorization.js +0 -0
- /package/{esm → dist}/models/responses.d.ts +0 -0
- /package/{esm → dist}/models/responses.js +0 -0
- /package/{esm → dist}/models/scope.d.ts +0 -0
- /package/{esm → dist}/models/scope.js +0 -0
- /package/{esm → dist}/models/token.js +0 -0
- /package/{esm → dist}/react/components/types.js +0 -0
- /package/{esm → dist}/react/context.js +0 -0
- /package/{esm → dist}/react/provider.js +0 -0
- /package/{esm → dist}/react/require-auth.d.ts +0 -0
- /package/{esm → dist}/react/use-authorization.js +0 -0
- /package/{esm → dist}/server/_clock-skew.d.ts +0 -0
- /package/{esm → dist}/server/client-authentication.js +0 -0
- /package/{esm → dist}/server/grants/client-credentials.js +0 -0
- /package/{esm → dist}/server/grants/password.js +0 -0
- /package/{esm → dist}/server/redirect-uri.d.ts +0 -0
- /package/{esm → dist}/server/services/authorization-code.js +0 -0
- /package/{esm → dist}/server/services/client.js +0 -0
- /package/{esm → dist}/server/services/device-authorization.js +0 -0
- /package/{esm → dist}/server/services/user.js +0 -0
- /package/{esm → dist}/server/utils/hash.d.ts +0 -0
- /package/{esm → dist}/testing/contract/_race.d.ts +0 -0
- /package/{esm → dist}/testing/contract/_race.js +0 -0
- /package/{esm → dist}/testing/contract/tenant.d.ts +0 -0
- /package/{esm → dist}/utils/_body.d.ts +0 -0
- /package/{esm → dist}/utils/_body.js +0 -0
- /package/{esm → dist}/utils/_buffer.d.ts +0 -0
- /package/{esm → dist}/utils/_buffer.js +0 -0
- /package/{esm → dist}/utils/_default-fetch.d.ts +0 -0
- /package/{esm → dist}/utils/_timing-safe.d.ts +0 -0
- /package/{esm → dist}/utils/_timing-safe.js +0 -0
- /package/{esm → dist}/utils/authentication-context.js +0 -0
- /package/{esm → dist}/utils/basic-auth.d.ts +0 -0
- /package/{esm → dist}/utils/basic-auth.js +0 -0
- /package/{esm → dist}/utils/pkce.d.ts +0 -0
- /package/{esm → dist}/utils/text.d.ts +0 -0
|
@@ -14,10 +14,8 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @module
|
|
16
16
|
*/
|
|
17
|
-
import "
|
|
18
|
-
import {
|
|
19
|
-
import { delay } from "../../../deps/jsr.io/@std/async/1.5.0/delay.js";
|
|
20
|
-
import { beforeEach, describe, it } from "../../../deps/jsr.io/@std/testing/1.0.20/bdd.js";
|
|
17
|
+
import { assert, beforeEach, describe, expect, it } from "vitest";
|
|
18
|
+
import { delay } from "../../../utils/_delay.js";
|
|
21
19
|
import { sessionStoreMaxAgeMs, } from "./session-store.js";
|
|
22
20
|
/**
|
|
23
21
|
* Seeds a session in `bff.sessionStore` and returns a `Cookie` header
|
|
@@ -53,8 +51,7 @@ export async function createTestSession(bff, options = {}) {
|
|
|
53
51
|
const data = {
|
|
54
52
|
tokens: {
|
|
55
53
|
accessToken: options.tokens?.accessToken ?? crypto.randomUUID(),
|
|
56
|
-
accessTokenExpiresAt: options.tokens?.accessTokenExpiresAt ??
|
|
57
|
-
now + 60 * 60 * 1000,
|
|
54
|
+
accessTokenExpiresAt: options.tokens?.accessTokenExpiresAt ?? now + 60 * 60 * 1000,
|
|
58
55
|
tokenType: options.tokens?.tokenType ?? "Bearer",
|
|
59
56
|
scope: options.tokens?.scope,
|
|
60
57
|
idToken: options.tokens?.idToken,
|
|
@@ -170,7 +167,7 @@ function parseCookieHeader(header, name) {
|
|
|
170
167
|
const BOUND_MS = 1000;
|
|
171
168
|
/**
|
|
172
169
|
* Contract test suite for {@link SessionStore} implementations. Registers
|
|
173
|
-
* `describe`/`it` blocks from
|
|
170
|
+
* `describe`/`it` blocks from Vitest, so call it at a test
|
|
174
171
|
* module's top level. It does not check that a stateful store's `update`
|
|
175
172
|
* rejects a missing or destroyed session, which {@link SessionStore.update}
|
|
176
173
|
* requires — test that yourself.
|
|
@@ -199,28 +196,28 @@ export function runSessionStoreContractTests(options) {
|
|
|
199
196
|
}
|
|
200
197
|
it("create returns a non-empty cookie value", async () => {
|
|
201
198
|
const value = await store.create(sampleSession());
|
|
202
|
-
|
|
199
|
+
expect(typeof value).toStrictEqual("string");
|
|
203
200
|
assert(value.length > 0);
|
|
204
201
|
});
|
|
205
202
|
it("read returns null for an unknown cookie value", async () => {
|
|
206
|
-
|
|
203
|
+
expect(await store.read("no-such-session")).toBe(null);
|
|
207
204
|
});
|
|
208
205
|
it("create + read round-trips the session data", async () => {
|
|
209
206
|
const original = sampleSession();
|
|
210
207
|
const value = await store.create(original);
|
|
211
208
|
const fetched = await store.read(value);
|
|
212
209
|
assert(fetched !== null, "read should return data for a created session");
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
210
|
+
expect(fetched.tokens.accessToken).toStrictEqual(original.tokens.accessToken);
|
|
211
|
+
expect(fetched.refreshToken).toStrictEqual(original.refreshToken);
|
|
212
|
+
expect(fetched.user).toStrictEqual(original.user);
|
|
216
213
|
});
|
|
217
214
|
it("preserves createdAt, which carries the session's absolute age", async () => {
|
|
218
215
|
const original = sampleSession();
|
|
219
216
|
const value = await store.create(original);
|
|
220
217
|
const fetched = await store.read(value);
|
|
221
218
|
assert(fetched !== null, "read should return data for a created session");
|
|
222
|
-
|
|
223
|
-
"HonoBffOptions.sessionMaxAgeMs, so they never age out");
|
|
219
|
+
expect(fetched.createdAt, "a store that drops createdAt silently opts its sessions out of " +
|
|
220
|
+
"HonoBffOptions.sessionMaxAgeMs, so they never age out").toStrictEqual(original.createdAt);
|
|
224
221
|
});
|
|
225
222
|
it("update reflects changes on subsequent read", async () => {
|
|
226
223
|
const value = await store.create(sampleSession());
|
|
@@ -231,34 +228,34 @@ export function runSessionStoreContractTests(options) {
|
|
|
231
228
|
};
|
|
232
229
|
const newValue = await store.update(value, updated);
|
|
233
230
|
const fetched = await store.read(newValue);
|
|
234
|
-
|
|
231
|
+
expect(fetched?.user).toStrictEqual({ sub: "u1", role: "admin" });
|
|
235
232
|
});
|
|
236
233
|
if (destroyClearsRead) {
|
|
237
234
|
it("destroy removes the session", async () => {
|
|
238
235
|
const value = await store.create(sampleSession());
|
|
239
236
|
await store.destroy(value);
|
|
240
|
-
|
|
237
|
+
expect(await store.read(value)).toBe(null);
|
|
241
238
|
});
|
|
242
239
|
}
|
|
243
240
|
it("never advertises a max age without proving it enforces one", () => {
|
|
244
241
|
const advertised = sessionStoreMaxAgeMs(store);
|
|
245
|
-
|
|
242
|
+
expect(advertised !== undefined && makeBoundedStore === undefined, `this store advertises maxAgeMs=${advertised}, which HonoBff trusts ` +
|
|
246
243
|
"when it refuses a session cookie that would expire before the " +
|
|
247
244
|
"session does. Supply makeBoundedStore so the contract can prove " +
|
|
248
|
-
"the bound is real.");
|
|
245
|
+
"the bound is real.").toStrictEqual(false);
|
|
249
246
|
});
|
|
250
247
|
if (makeBoundedStore) {
|
|
251
248
|
it("reports the max age it was built with, so a BFF can outlive it", async () => {
|
|
252
249
|
const bounded = await makeBoundedStore(BOUND_MS);
|
|
253
|
-
|
|
250
|
+
expect(sessionStoreMaxAgeMs(bounded), "a store that hides its bound gets no divergence check from HonoBff").toBe(BOUND_MS);
|
|
254
251
|
});
|
|
255
252
|
it("stops reading a session older than the max age it enforces", async () => {
|
|
256
253
|
const bounded = await makeBoundedStore(BOUND_MS);
|
|
257
254
|
const value = await bounded.create(sampleSession());
|
|
258
|
-
assert(await bounded.read(value) !== null, "a session created moments ago must still read");
|
|
255
|
+
assert((await bounded.read(value)) !== null, "a session created moments ago must still read");
|
|
259
256
|
await delay(BOUND_MS + 500);
|
|
260
|
-
|
|
261
|
-
"captured cookie outlives the window the bound promises");
|
|
257
|
+
expect(await bounded.read(value), "a session past the store's own bound must stop reading, or a " +
|
|
258
|
+
"captured cookie outlives the window the bound promises").toBe(null);
|
|
262
259
|
});
|
|
263
260
|
}
|
|
264
261
|
});
|
|
@@ -39,10 +39,9 @@
|
|
|
39
39
|
*
|
|
40
40
|
* @module
|
|
41
41
|
*/
|
|
42
|
-
import "../../_dnt.polyfills.js";
|
|
43
42
|
import { Hono } from "hono";
|
|
44
43
|
import type { Context } from "hono";
|
|
45
|
-
import type { IdentityService, IdentityUser } from "../../identity/service.
|
|
44
|
+
import type { IdentityService, IdentityUser } from "../../identity/service.ts";
|
|
46
45
|
/** Paths for the routes mounted by {@link honoIdentityRoutes}. */
|
|
47
46
|
export interface HonoIdentityPaths {
|
|
48
47
|
/** `POST` sign-up. Default `/signup`. */
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
*
|
|
40
40
|
* @module
|
|
41
41
|
*/
|
|
42
|
-
import "../../_dnt.polyfills.js";
|
|
43
42
|
import { Hono } from "hono";
|
|
44
43
|
import { identityErrorStatus, isIdentityError, } from "../../identity/errors.js";
|
|
45
44
|
function handle(fn) {
|
|
@@ -68,10 +67,10 @@ async function readBody(c) {
|
|
|
68
67
|
}
|
|
69
68
|
const out = {};
|
|
70
69
|
for (const [key, value] of Object.entries(body)) {
|
|
71
|
-
out[key] =
|
|
72
|
-
value !== undefined
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
out[key] =
|
|
71
|
+
STRING_FIELDS.has(key) && value !== null && value !== undefined
|
|
72
|
+
? String(value)
|
|
73
|
+
: value;
|
|
75
74
|
}
|
|
76
75
|
return out;
|
|
77
76
|
}
|
|
@@ -104,18 +103,19 @@ function isTrustedOrigin(c, allowedOrigins) {
|
|
|
104
103
|
const origin = c.req.header("origin");
|
|
105
104
|
const site = c.req.header("sec-fetch-site");
|
|
106
105
|
if (site) {
|
|
107
|
-
return site === "same-origin" ||
|
|
108
|
-
|
|
106
|
+
return (site === "same-origin" ||
|
|
107
|
+
site === "none" ||
|
|
108
|
+
(!!origin && allowedOrigins.has(origin)));
|
|
109
109
|
}
|
|
110
110
|
if (!origin)
|
|
111
111
|
return true;
|
|
112
|
-
return allowedOrigins.has(origin) ||
|
|
113
|
-
hostOf(origin) === new URL(c.req.url).host;
|
|
112
|
+
return (allowedOrigins.has(origin) || hostOf(origin) === new URL(c.req.url).host);
|
|
114
113
|
}
|
|
115
114
|
function sameOriginGuard(options) {
|
|
116
115
|
const allowedOrigins = new Set(options.allowedOrigins ?? []);
|
|
117
116
|
return async (c, next) => {
|
|
118
|
-
if (!SAFE_METHODS.has(c.req.method) &&
|
|
117
|
+
if (!SAFE_METHODS.has(c.req.method) &&
|
|
118
|
+
!isTrustedOrigin(c, allowedOrigins)) {
|
|
119
119
|
return c.json({ error: FORBIDDEN_ORIGIN }, identityErrorStatus(FORBIDDEN_ORIGIN));
|
|
120
120
|
}
|
|
121
121
|
await next();
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Request logging that removes query values, including OAuth callback credentials.
|
|
3
|
-
*
|
|
4
|
-
* @module hono/log
|
|
5
|
-
*/
|
|
6
|
-
import "../../_dnt.polyfills.js";
|
|
7
1
|
/**
|
|
8
2
|
* Produces a request target with every query value replaced by `[redacted]`.
|
|
9
3
|
* Keeps the pathname and percent-encoded parameter names, including repeats,
|
|
@@ -27,13 +27,12 @@
|
|
|
27
27
|
*
|
|
28
28
|
* @module
|
|
29
29
|
*/
|
|
30
|
-
import "../../_dnt.polyfills.js";
|
|
31
30
|
import type { Context, MiddlewareHandler } from "hono";
|
|
32
|
-
import type { ClientInterface } from "../../models/client.
|
|
33
|
-
import type { AbstractScope, BasicScope } from "../../models/scope.
|
|
34
|
-
import { type AuthenticatedContext, ResourceServer } from "../../server/resource-server.
|
|
35
|
-
import type { RequireConditions } from "../../models/authorization.
|
|
36
|
-
export { type HonoResourceServerVariables, OAUTH2_CONTEXT_KEY, } from "./_common.
|
|
31
|
+
import type { ClientInterface } from "../../models/client.ts";
|
|
32
|
+
import type { AbstractScope, BasicScope } from "../../models/scope.ts";
|
|
33
|
+
import { type AuthenticatedContext, ResourceServer } from "../../server/resource-server.ts";
|
|
34
|
+
import type { RequireConditions } from "../../models/authorization.ts";
|
|
35
|
+
export { type HonoResourceServerVariables, OAUTH2_CONTEXT_KEY, } from "./_common.ts";
|
|
37
36
|
/**
|
|
38
37
|
* Hono-specific wrapper around {@link ResourceServer}. Construction options
|
|
39
38
|
* are identical to the core server; the subclass only adds Hono middleware
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
*
|
|
28
28
|
* @module
|
|
29
29
|
*/
|
|
30
|
-
import "../../_dnt.polyfills.js";
|
|
31
30
|
import { ResourceServer, } from "../../server/resource-server.js";
|
|
32
31
|
import { authenticateHonoRequest, createProtectMiddleware, createRequireMiddleware, createRequireScopeMiddleware, readContext, } from "./_common.js";
|
|
33
32
|
export { OAUTH2_CONTEXT_KEY, } from "./_common.js";
|
package/dist/cli/bin.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the development identity provider: the shape of the JSON
|
|
3
|
+
* file `idp dev` reads, the built-in demo defaults, and the validation that
|
|
4
|
+
* turns untrusted JSON into a {@link DevIdpConfig}.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
/** Grant types the development identity provider will serve. */
|
|
9
|
+
export interface DevIdpGrantsConfig {
|
|
10
|
+
/** Authorization code grant with PKCE. */
|
|
11
|
+
authorization_code: boolean;
|
|
12
|
+
/** Client credentials grant (machine-to-machine). */
|
|
13
|
+
client_credentials: boolean;
|
|
14
|
+
/** Refresh token grant. */
|
|
15
|
+
refresh_token: boolean;
|
|
16
|
+
/** Resource owner password credentials grant. */
|
|
17
|
+
password: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** A user seeded into the development identity provider at startup. */
|
|
20
|
+
export interface DevIdpUserConfig {
|
|
21
|
+
/** Subject identifier: the `sub` claim and the id the admin API takes. */
|
|
22
|
+
id: string;
|
|
23
|
+
/** Login name typed into the sign-in form. */
|
|
24
|
+
username: string;
|
|
25
|
+
/** Password the sign-in form accepts. Plaintext, because this is a dev tool. */
|
|
26
|
+
password: string;
|
|
27
|
+
/** Extra claims merged into this user's id_token and UserInfo response. */
|
|
28
|
+
claims: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
/** A client registered with the development identity provider at startup. */
|
|
31
|
+
export interface DevIdpClientConfig {
|
|
32
|
+
/** The `client_id` the application authenticates with. */
|
|
33
|
+
id: string;
|
|
34
|
+
/** Omit for a public (PKCE-only) client; set for a confidential one. */
|
|
35
|
+
secret?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Redirect URIs, matched exactly — list every one your app sends. An entry
|
|
38
|
+
* on `127.0.0.1` or `[::1]` also matches the same URI on any port.
|
|
39
|
+
*/
|
|
40
|
+
redirectUris: string[];
|
|
41
|
+
/** Grant types this client may use. */
|
|
42
|
+
grants: string[];
|
|
43
|
+
/**
|
|
44
|
+
* User the client-credentials grant puts on the token. Omit it — the
|
|
45
|
+
* default — for a machine token with no user, which introspection reports
|
|
46
|
+
* with a `client_id` and no `sub`. Set it only to model a dedicated
|
|
47
|
+
* service-account user, never a human owner.
|
|
48
|
+
*/
|
|
49
|
+
ownerUserId?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A fully resolved configuration. Every field the server needs is present:
|
|
53
|
+
* {@link parseDevIdpConfig} fills the defaults so nothing downstream has to.
|
|
54
|
+
*/
|
|
55
|
+
export interface DevIdpConfig {
|
|
56
|
+
/**
|
|
57
|
+
* Issuer identifier stamped into tokens and discovery. When omitted it is
|
|
58
|
+
* pinned at startup to the bound address (`localhost` for a wildcard bind
|
|
59
|
+
* such as `0.0.0.0`); set it when clients reach the server under another
|
|
60
|
+
* name, such as a CI service hostname.
|
|
61
|
+
*/
|
|
62
|
+
issuer?: string;
|
|
63
|
+
/** Interface to bind. */
|
|
64
|
+
hostname: string;
|
|
65
|
+
/** Port to bind. `0` asks the OS for a free one. */
|
|
66
|
+
port: number;
|
|
67
|
+
/** `"prompt"` shows a consent screen; `"auto"` grants the requested scope. */
|
|
68
|
+
consent: "auto" | "prompt";
|
|
69
|
+
/** Scope vocabulary advertised in discovery. */
|
|
70
|
+
scopesSupported: string[];
|
|
71
|
+
/** Access token lifetime in seconds — shorten it to test expiry handling. */
|
|
72
|
+
accessTokenLifetime: number;
|
|
73
|
+
/** Grant types the server enables. */
|
|
74
|
+
grants: DevIdpGrantsConfig;
|
|
75
|
+
/**
|
|
76
|
+
* ES256 private JWK, as printed by `oidc keygen`. Pins the signing key so
|
|
77
|
+
* tokens and JWKS survive a restart. `OIDC_SIGNING_KEY` overrides it.
|
|
78
|
+
*/
|
|
79
|
+
signingKey?: JsonWebKey & {
|
|
80
|
+
kid?: string;
|
|
81
|
+
};
|
|
82
|
+
/** Users to seed. */
|
|
83
|
+
users: DevIdpUserConfig[];
|
|
84
|
+
/** Clients to register. */
|
|
85
|
+
clients: DevIdpClientConfig[];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The configuration used when `idp dev` runs without `--config`: one
|
|
89
|
+
* confidential client, one public client, and one user, all on well-known
|
|
90
|
+
* localhost ports.
|
|
91
|
+
*/
|
|
92
|
+
export declare function defaultDevIdpConfig(): DevIdpConfig;
|
|
93
|
+
/**
|
|
94
|
+
* Validates parsed JSON and fills in defaults, so the caller gets a config
|
|
95
|
+
* with no optional plumbing left to resolve.
|
|
96
|
+
*
|
|
97
|
+
* Unknown fields are rejected rather than ignored — a typo in a dev config is
|
|
98
|
+
* otherwise a silent no-op that costs an hour.
|
|
99
|
+
*
|
|
100
|
+
* @throws {Error} When a field is missing, mistyped, or unrecognized. The
|
|
101
|
+
* message names the offending path (e.g. `users[0].password`).
|
|
102
|
+
*/
|
|
103
|
+
export declare function parseDevIdpConfig(value: unknown): DevIdpConfig;
|
|
104
|
+
/**
|
|
105
|
+
* Reads and validates a config file.
|
|
106
|
+
*
|
|
107
|
+
* @throws {Error} When the file is unreadable, is not valid JSON, or fails
|
|
108
|
+
* {@link parseDevIdpConfig}. Every message names the file.
|
|
109
|
+
*/
|
|
110
|
+
export declare function loadDevIdpConfig(path: string): Promise<DevIdpConfig>;
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the development identity provider: the shape of the JSON
|
|
3
|
+
* file `idp dev` reads, the built-in demo defaults, and the validation that
|
|
4
|
+
* turns untrusted JSON into a {@link DevIdpConfig}.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { readFile } from "node:fs/promises";
|
|
9
|
+
const DEFAULT_PORT = 9000;
|
|
10
|
+
const DEFAULT_HOSTNAME = "127.0.0.1";
|
|
11
|
+
const DEFAULT_ACCESS_TOKEN_LIFETIME = 3600;
|
|
12
|
+
const DEFAULT_SCOPES = ["openid", "profile", "email", "offline_access"];
|
|
13
|
+
const DEFAULT_GRANTS = {
|
|
14
|
+
authorization_code: true,
|
|
15
|
+
client_credentials: true,
|
|
16
|
+
refresh_token: true,
|
|
17
|
+
password: false,
|
|
18
|
+
};
|
|
19
|
+
const DEFAULT_REDIRECT_URIS = [
|
|
20
|
+
"http://localhost:3000/callback",
|
|
21
|
+
"http://localhost:5173/callback",
|
|
22
|
+
"http://localhost:8000/callback",
|
|
23
|
+
];
|
|
24
|
+
const DEFAULT_CLIENT_GRANTS = ["authorization_code", "refresh_token"];
|
|
25
|
+
const CONFIG_FIELDS = [
|
|
26
|
+
"issuer",
|
|
27
|
+
"hostname",
|
|
28
|
+
"port",
|
|
29
|
+
"consent",
|
|
30
|
+
"scopesSupported",
|
|
31
|
+
"accessTokenLifetime",
|
|
32
|
+
"grants",
|
|
33
|
+
"signingKey",
|
|
34
|
+
"users",
|
|
35
|
+
"clients",
|
|
36
|
+
];
|
|
37
|
+
const USER_FIELDS = ["id", "username", "password", "claims"];
|
|
38
|
+
const CLIENT_FIELDS = ["id", "secret", "redirectUris", "grants", "ownerUserId"];
|
|
39
|
+
/**
|
|
40
|
+
* The configuration used when `idp dev` runs without `--config`: one
|
|
41
|
+
* confidential client, one public client, and one user, all on well-known
|
|
42
|
+
* localhost ports.
|
|
43
|
+
*/
|
|
44
|
+
export function defaultDevIdpConfig() {
|
|
45
|
+
return {
|
|
46
|
+
hostname: DEFAULT_HOSTNAME,
|
|
47
|
+
port: DEFAULT_PORT,
|
|
48
|
+
consent: "auto",
|
|
49
|
+
scopesSupported: [...DEFAULT_SCOPES],
|
|
50
|
+
accessTokenLifetime: DEFAULT_ACCESS_TOKEN_LIFETIME,
|
|
51
|
+
grants: { ...DEFAULT_GRANTS },
|
|
52
|
+
users: [
|
|
53
|
+
{
|
|
54
|
+
id: "user-alice",
|
|
55
|
+
username: "alice@example.com",
|
|
56
|
+
password: "password",
|
|
57
|
+
claims: {
|
|
58
|
+
name: "Alice Example",
|
|
59
|
+
email: "alice@example.com",
|
|
60
|
+
email_verified: true,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
clients: [
|
|
65
|
+
{
|
|
66
|
+
id: "dev-client",
|
|
67
|
+
secret: "dev-secret",
|
|
68
|
+
redirectUris: [...DEFAULT_REDIRECT_URIS],
|
|
69
|
+
grants: ["authorization_code", "refresh_token", "client_credentials"],
|
|
70
|
+
ownerUserId: "user-alice",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: "dev-public-client",
|
|
74
|
+
redirectUris: [...DEFAULT_REDIRECT_URIS],
|
|
75
|
+
grants: [...DEFAULT_CLIENT_GRANTS],
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function fail(path, expectation) {
|
|
81
|
+
throw new Error(`${path} ${expectation}`);
|
|
82
|
+
}
|
|
83
|
+
function record(value, path) {
|
|
84
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
85
|
+
fail(path, "must be an object");
|
|
86
|
+
}
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
function rejectUnknown(value, path, allowed) {
|
|
90
|
+
for (const key of Object.keys(value)) {
|
|
91
|
+
if (!allowed.includes(key)) {
|
|
92
|
+
fail(`${path}.${key}`, `is not a known option (expected one of: ${allowed.join(", ")})`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function string(value, path) {
|
|
97
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
98
|
+
fail(path, "must be a non-empty string");
|
|
99
|
+
}
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
function optionalString(value, path) {
|
|
103
|
+
return value === undefined ? undefined : string(value, path);
|
|
104
|
+
}
|
|
105
|
+
function stringArray(value, path) {
|
|
106
|
+
if (!Array.isArray(value))
|
|
107
|
+
fail(path, "must be an array of strings");
|
|
108
|
+
return value.map((entry, index) => string(entry, `${path}[${index}]`));
|
|
109
|
+
}
|
|
110
|
+
function integer(value, path, min) {
|
|
111
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < min) {
|
|
112
|
+
fail(path, `must be an integer >= ${min}`);
|
|
113
|
+
}
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
function boolean(value, path) {
|
|
117
|
+
if (typeof value !== "boolean")
|
|
118
|
+
fail(path, "must be true or false");
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
function array(value, path) {
|
|
122
|
+
if (!Array.isArray(value))
|
|
123
|
+
fail(path, "must be an array");
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
function parseGrants(value, path) {
|
|
127
|
+
const source = record(value, path);
|
|
128
|
+
rejectUnknown(source, path, Object.keys(DEFAULT_GRANTS));
|
|
129
|
+
const grants = { ...DEFAULT_GRANTS };
|
|
130
|
+
for (const key of Object.keys(DEFAULT_GRANTS)) {
|
|
131
|
+
if (source[key] !== undefined) {
|
|
132
|
+
grants[key] = boolean(source[key], `${path}.${key}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return grants;
|
|
136
|
+
}
|
|
137
|
+
function parseUser(value, path) {
|
|
138
|
+
const source = record(value, path);
|
|
139
|
+
rejectUnknown(source, path, USER_FIELDS);
|
|
140
|
+
const username = string(source.username, `${path}.username`);
|
|
141
|
+
return {
|
|
142
|
+
id: optionalString(source.id, `${path}.id`) ?? username,
|
|
143
|
+
username,
|
|
144
|
+
password: string(source.password, `${path}.password`),
|
|
145
|
+
claims: source.claims === undefined
|
|
146
|
+
? {}
|
|
147
|
+
: record(source.claims, `${path}.claims`),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function parseClient(value, path) {
|
|
151
|
+
const source = record(value, path);
|
|
152
|
+
rejectUnknown(source, path, CLIENT_FIELDS);
|
|
153
|
+
const grants = source.grants === undefined
|
|
154
|
+
? [...DEFAULT_CLIENT_GRANTS]
|
|
155
|
+
: stringArray(source.grants, `${path}.grants`);
|
|
156
|
+
const redirectUris = source.redirectUris === undefined
|
|
157
|
+
? []
|
|
158
|
+
: stringArray(source.redirectUris, `${path}.redirectUris`);
|
|
159
|
+
if (grants.includes("authorization_code") && redirectUris.length === 0) {
|
|
160
|
+
fail(`${path}.redirectUris`, "must list at least one URI for a client using the authorization_code grant");
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
id: string(source.id, `${path}.id`),
|
|
164
|
+
secret: optionalString(source.secret, `${path}.secret`),
|
|
165
|
+
redirectUris,
|
|
166
|
+
grants,
|
|
167
|
+
ownerUserId: optionalString(source.ownerUserId, `${path}.ownerUserId`),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function parseConsent(value, path) {
|
|
171
|
+
const consent = string(value, path);
|
|
172
|
+
if (consent !== "auto" && consent !== "prompt") {
|
|
173
|
+
fail(path, 'must be "auto" or "prompt"');
|
|
174
|
+
}
|
|
175
|
+
return consent;
|
|
176
|
+
}
|
|
177
|
+
function parseSigningKey(value, path) {
|
|
178
|
+
const jwk = record(value, path);
|
|
179
|
+
string(jwk.kty, `${path}.kty`);
|
|
180
|
+
string(jwk.d, `${path}.d`);
|
|
181
|
+
return jwk;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Validates parsed JSON and fills in defaults, so the caller gets a config
|
|
185
|
+
* with no optional plumbing left to resolve.
|
|
186
|
+
*
|
|
187
|
+
* Unknown fields are rejected rather than ignored — a typo in a dev config is
|
|
188
|
+
* otherwise a silent no-op that costs an hour.
|
|
189
|
+
*
|
|
190
|
+
* @throws {Error} When a field is missing, mistyped, or unrecognized. The
|
|
191
|
+
* message names the offending path (e.g. `users[0].password`).
|
|
192
|
+
*/
|
|
193
|
+
export function parseDevIdpConfig(value) {
|
|
194
|
+
const source = record(value, "config");
|
|
195
|
+
rejectUnknown(source, "config", CONFIG_FIELDS);
|
|
196
|
+
const defaults = defaultDevIdpConfig();
|
|
197
|
+
const users = source.users === undefined
|
|
198
|
+
? defaults.users
|
|
199
|
+
: array(source.users, "config.users").map((entry, index) => parseUser(entry, `users[${index}]`));
|
|
200
|
+
const clients = source.clients === undefined
|
|
201
|
+
? defaults.clients
|
|
202
|
+
: array(source.clients, "config.clients").map((entry, index) => parseClient(entry, `clients[${index}]`));
|
|
203
|
+
const seenUserIds = new Set();
|
|
204
|
+
for (const user of users) {
|
|
205
|
+
if (seenUserIds.has(user.id)) {
|
|
206
|
+
fail(`users`, `contains more than one user with id "${user.id}"`);
|
|
207
|
+
}
|
|
208
|
+
seenUserIds.add(user.id);
|
|
209
|
+
}
|
|
210
|
+
const seenClientIds = new Set();
|
|
211
|
+
for (const client of clients) {
|
|
212
|
+
if (seenClientIds.has(client.id)) {
|
|
213
|
+
fail(`clients`, `contains more than one client with id "${client.id}"`);
|
|
214
|
+
}
|
|
215
|
+
seenClientIds.add(client.id);
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
issuer: optionalString(source.issuer, "config.issuer"),
|
|
219
|
+
hostname: optionalString(source.hostname, "config.hostname") ?? defaults.hostname,
|
|
220
|
+
port: source.port === undefined
|
|
221
|
+
? defaults.port
|
|
222
|
+
: integer(source.port, "config.port", 0),
|
|
223
|
+
consent: source.consent === undefined
|
|
224
|
+
? defaults.consent
|
|
225
|
+
: parseConsent(source.consent, "config.consent"),
|
|
226
|
+
scopesSupported: source.scopesSupported === undefined
|
|
227
|
+
? defaults.scopesSupported
|
|
228
|
+
: stringArray(source.scopesSupported, "config.scopesSupported"),
|
|
229
|
+
accessTokenLifetime: source.accessTokenLifetime === undefined
|
|
230
|
+
? defaults.accessTokenLifetime
|
|
231
|
+
: integer(source.accessTokenLifetime, "config.accessTokenLifetime", 1),
|
|
232
|
+
grants: source.grants === undefined
|
|
233
|
+
? defaults.grants
|
|
234
|
+
: parseGrants(source.grants, "config.grants"),
|
|
235
|
+
signingKey: source.signingKey === undefined
|
|
236
|
+
? undefined
|
|
237
|
+
: parseSigningKey(source.signingKey, "config.signingKey"),
|
|
238
|
+
users,
|
|
239
|
+
clients,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Reads and validates a config file.
|
|
244
|
+
*
|
|
245
|
+
* @throws {Error} When the file is unreadable, is not valid JSON, or fails
|
|
246
|
+
* {@link parseDevIdpConfig}. Every message names the file.
|
|
247
|
+
*/
|
|
248
|
+
export async function loadDevIdpConfig(path) {
|
|
249
|
+
let text;
|
|
250
|
+
try {
|
|
251
|
+
text = await readFile(path, "utf8");
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
throw new Error(`cannot read config ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
255
|
+
}
|
|
256
|
+
let parsed;
|
|
257
|
+
try {
|
|
258
|
+
parsed = JSON.parse(text);
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
throw new Error(`${path} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
return parseDevIdpConfig(parsed);
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
throw new Error(`${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `idp dev` command: runs the development identity provider from a config
|
|
3
|
+
* file (or the built-in demo config) and prints what it seeded.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Runs the development identity provider until the process is stopped.
|
|
9
|
+
*
|
|
10
|
+
* Accepts `--config <path>`, `--port <number>`, `--hostname <host>`,
|
|
11
|
+
* `--issuer <url>`, `--admin-token <token>`, and `--unsafe-remote-access`;
|
|
12
|
+
* flags win over the config file, which wins over the built-in demo config.
|
|
13
|
+
* `IDP_ADMIN_TOKEN` supplies the admin token when the flag is absent.
|
|
14
|
+
*
|
|
15
|
+
* Aborting `signal` shuts the server down and resolves the returned promise.
|
|
16
|
+
*
|
|
17
|
+
* @throws {Error} When an option or the config file is invalid, or when the
|
|
18
|
+
* bind address is not loopback and `--unsafe-remote-access` was not passed.
|
|
19
|
+
*/
|
|
20
|
+
export declare function idpDev(args: string[], signal?: AbortSignal): Promise<void>;
|