@udibo/oauth2 0.14.0 → 0.15.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/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 +22 -12
- package/{esm → dist}/adapters/hono/bff/bff.js +35 -29
- 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/{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
|
@@ -0,0 +1,175 @@
|
|
|
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
|
+
import { generateSigningKey, importSigningKeyJwk, } from "../../server/signing-keys.js";
|
|
8
|
+
import { defaultDevIdpConfig, loadDevIdpConfig, } from "./config.js";
|
|
9
|
+
import { ADMIN_TOKEN_HEADER, isLoopbackHostname, startDevIdentityProvider, } from "./server.js";
|
|
10
|
+
const SIGNING_KEY_VARIABLE = "OIDC_SIGNING_KEY";
|
|
11
|
+
const ADMIN_TOKEN_VARIABLE = "IDP_ADMIN_TOKEN";
|
|
12
|
+
const VALUE_FLAGS = [
|
|
13
|
+
"--config",
|
|
14
|
+
"--port",
|
|
15
|
+
"--hostname",
|
|
16
|
+
"--issuer",
|
|
17
|
+
"--admin-token",
|
|
18
|
+
];
|
|
19
|
+
const BOOLEAN_FLAGS = ["--unsafe-remote-access"];
|
|
20
|
+
function parseIdpDevArgs(args) {
|
|
21
|
+
const parsed = {};
|
|
22
|
+
for (let index = 0; index < args.length; index++) {
|
|
23
|
+
const argument = args[index];
|
|
24
|
+
const separator = argument.indexOf("=");
|
|
25
|
+
const flag = separator === -1 ? argument : argument.slice(0, separator);
|
|
26
|
+
if (BOOLEAN_FLAGS.includes(flag) && separator === -1) {
|
|
27
|
+
parsed.allowRemoteAccess = true;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (!VALUE_FLAGS.includes(flag)) {
|
|
31
|
+
throw new Error(`unknown option "${argument}" (expected one of: ${[
|
|
32
|
+
...VALUE_FLAGS,
|
|
33
|
+
...BOOLEAN_FLAGS,
|
|
34
|
+
].join(", ")})`);
|
|
35
|
+
}
|
|
36
|
+
const value = separator === -1 ? args[++index] : argument.slice(separator + 1);
|
|
37
|
+
if (value === undefined || value.length === 0) {
|
|
38
|
+
throw new Error(`${flag} requires a value`);
|
|
39
|
+
}
|
|
40
|
+
if (flag === "--config")
|
|
41
|
+
parsed.configPath = value;
|
|
42
|
+
if (flag === "--hostname")
|
|
43
|
+
parsed.hostname = value;
|
|
44
|
+
if (flag === "--issuer")
|
|
45
|
+
parsed.issuer = value;
|
|
46
|
+
if (flag === "--admin-token")
|
|
47
|
+
parsed.adminToken = value;
|
|
48
|
+
if (flag === "--port") {
|
|
49
|
+
const port = Number(value);
|
|
50
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
51
|
+
throw new Error(`--port must be an integer between 0 and 65535`);
|
|
52
|
+
}
|
|
53
|
+
parsed.port = port;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return parsed;
|
|
57
|
+
}
|
|
58
|
+
function readVariable(name) {
|
|
59
|
+
return process.env[name] || undefined;
|
|
60
|
+
}
|
|
61
|
+
async function resolveSigningKey(config) {
|
|
62
|
+
const fromEnvironment = readVariable(SIGNING_KEY_VARIABLE);
|
|
63
|
+
if (fromEnvironment) {
|
|
64
|
+
let jwk;
|
|
65
|
+
try {
|
|
66
|
+
jwk = JSON.parse(fromEnvironment);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw new Error(`${SIGNING_KEY_VARIABLE} is not valid JSON`);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
key: await importSigningKeyJwk(jwk),
|
|
73
|
+
source: SIGNING_KEY_VARIABLE,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (config.signingKey) {
|
|
77
|
+
return {
|
|
78
|
+
key: await importSigningKeyJwk(config.signingKey),
|
|
79
|
+
source: "the config file",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return { key: await generateSigningKey(), source: "" };
|
|
83
|
+
}
|
|
84
|
+
function describeSeed(config) {
|
|
85
|
+
const lines = ["Users:"];
|
|
86
|
+
if (config.users.length === 0)
|
|
87
|
+
lines.push(" (none)");
|
|
88
|
+
for (const user of config.users) {
|
|
89
|
+
lines.push(` ${user.username} password: ${user.password} sub: ${user.id}`);
|
|
90
|
+
}
|
|
91
|
+
lines.push("", "Clients:");
|
|
92
|
+
if (config.clients.length === 0)
|
|
93
|
+
lines.push(" (none)");
|
|
94
|
+
for (const client of config.clients) {
|
|
95
|
+
lines.push(` ${client.id} ${client.secret ? `secret: ${client.secret}` : "public client"}`, ` grants: ${client.grants.join(", ")}`, ` redirect URIs: ${client.redirectUris.join(", ") || "(none)"}`);
|
|
96
|
+
}
|
|
97
|
+
return lines;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Runs the development identity provider until the process is stopped.
|
|
101
|
+
*
|
|
102
|
+
* Accepts `--config <path>`, `--port <number>`, `--hostname <host>`,
|
|
103
|
+
* `--issuer <url>`, `--admin-token <token>`, and `--unsafe-remote-access`;
|
|
104
|
+
* flags win over the config file, which wins over the built-in demo config.
|
|
105
|
+
* `IDP_ADMIN_TOKEN` supplies the admin token when the flag is absent.
|
|
106
|
+
*
|
|
107
|
+
* Aborting `signal` shuts the server down and resolves the returned promise.
|
|
108
|
+
*
|
|
109
|
+
* @throws {Error} When an option or the config file is invalid, or when the
|
|
110
|
+
* bind address is not loopback and `--unsafe-remote-access` was not passed.
|
|
111
|
+
*/
|
|
112
|
+
export async function idpDev(args, signal) {
|
|
113
|
+
const options = parseIdpDevArgs(args);
|
|
114
|
+
const config = options.configPath
|
|
115
|
+
? await loadDevIdpConfig(options.configPath)
|
|
116
|
+
: defaultDevIdpConfig();
|
|
117
|
+
if (options.port !== undefined)
|
|
118
|
+
config.port = options.port;
|
|
119
|
+
if (options.hostname !== undefined)
|
|
120
|
+
config.hostname = options.hostname;
|
|
121
|
+
if (options.issuer !== undefined)
|
|
122
|
+
config.issuer = options.issuer;
|
|
123
|
+
const { key, source } = await resolveSigningKey(config);
|
|
124
|
+
const idp = await startDevIdentityProvider({
|
|
125
|
+
config,
|
|
126
|
+
signingKey: key,
|
|
127
|
+
adminToken: options.adminToken ?? readVariable(ADMIN_TOKEN_VARIABLE),
|
|
128
|
+
allowRemoteAccess: options.allowRemoteAccess,
|
|
129
|
+
});
|
|
130
|
+
const loopback = isLoopbackHostname(idp.hostname);
|
|
131
|
+
const stop = () => void idp.shutdown();
|
|
132
|
+
if (signal?.aborted)
|
|
133
|
+
stop();
|
|
134
|
+
else
|
|
135
|
+
signal?.addEventListener("abort", stop, { once: true });
|
|
136
|
+
console.log([
|
|
137
|
+
"@udibo/oauth2 development identity provider",
|
|
138
|
+
"",
|
|
139
|
+
" DEVELOPMENT AND CI ONLY. State is in memory and the /__admin/",
|
|
140
|
+
" endpoints mint tokens for any seeded user without their password.",
|
|
141
|
+
" Never expose this server to a network you do not control.",
|
|
142
|
+
"",
|
|
143
|
+
`Listening on ${idp.url}`,
|
|
144
|
+
`Reachable from: ${loopback
|
|
145
|
+
? "this machine only (loopback)"
|
|
146
|
+
: `ANY HOST THAT CAN REACH ${idp.hostname}:${idp.port} — remote access was enabled explicitly`}`,
|
|
147
|
+
`Issuer: ${idp.issuer}${config.issuer
|
|
148
|
+
? ""
|
|
149
|
+
: " (derived from the bind address; pin it with --issuer)"}`,
|
|
150
|
+
`Discovery: ${idp.url}/.well-known/openid-configuration`,
|
|
151
|
+
`JWKS: ${idp.url}/jwks`,
|
|
152
|
+
`Signing key: ${source
|
|
153
|
+
? `loaded from ${source} (kid ${key.kid})`
|
|
154
|
+
: `generated (kid ${key.kid})`}`,
|
|
155
|
+
`Consent: ${config.consent === "prompt" ? "prompted" : "granted automatically"}`,
|
|
156
|
+
"",
|
|
157
|
+
`Admin token: ${idp.adminToken}`,
|
|
158
|
+
` Send it as the ${ADMIN_TOKEN_HEADER} header on every /__admin/ request.`,
|
|
159
|
+
` Set ${ADMIN_TOKEN_VARIABLE} or --admin-token to choose it yourself.`,
|
|
160
|
+
"",
|
|
161
|
+
...describeSeed(config),
|
|
162
|
+
].join("\n"));
|
|
163
|
+
if (!loopback) {
|
|
164
|
+
console.error(`\nWARNING: bound to ${idp.hostname}, which is not loopback. Anyone who ` +
|
|
165
|
+
`can reach this port and read the admin token can mint tokens for any ` +
|
|
166
|
+
`seeded user. Only do this on a network you control, such as a CI ` +
|
|
167
|
+
`job's private network.`);
|
|
168
|
+
}
|
|
169
|
+
if (!source) {
|
|
170
|
+
console.error(`\nNo ${SIGNING_KEY_VARIABLE} and no "signingKey" in the config: this ` +
|
|
171
|
+
`key exists only for this process, so tokens and JWKS change on ` +
|
|
172
|
+
`every restart. Pin one with "udibo-oauth2 oidc keygen".`);
|
|
173
|
+
}
|
|
174
|
+
await idp.finished;
|
|
175
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The development identity provider's HTML: a sign-in page, a consent screen,
|
|
3
|
+
* and the status page served at `/`.
|
|
4
|
+
*
|
|
5
|
+
* Hand-written markup with no client-side JavaScript, so the pages render the
|
|
6
|
+
* same in a browser and in a `fetch`-driven test. Every control a test needs
|
|
7
|
+
* carries a stable `id` and `name`.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { DevIdpClientConfig, DevIdpUserConfig } from "./config.ts";
|
|
12
|
+
/** Wraps HTML in a `Response` with the headers a browser and a test expect. */
|
|
13
|
+
export declare function htmlResponse(html: string, status?: number): Response;
|
|
14
|
+
/** Options for {@link loginPage}. */
|
|
15
|
+
export interface LoginPageOptions {
|
|
16
|
+
/** URL to continue to after a successful sign-in, usually the authorize URL. */
|
|
17
|
+
returnTo: string;
|
|
18
|
+
/** Seeded users, offered as one-click sign-in buttons. */
|
|
19
|
+
users: readonly DevIdpUserConfig[];
|
|
20
|
+
/** Message to show above the form after a failed attempt. */
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The sign-in page. Submits to `POST /login` with `username` + `password`, or
|
|
25
|
+
* with `as=<username>` from a one-click button.
|
|
26
|
+
*/
|
|
27
|
+
export declare function loginPage(options: LoginPageOptions): string;
|
|
28
|
+
/** Options for {@link consentPage}. */
|
|
29
|
+
export interface ConsentPageOptions {
|
|
30
|
+
/** Client asking for access. */
|
|
31
|
+
clientId: string;
|
|
32
|
+
/** Scope being requested, or `undefined` when the request named none. */
|
|
33
|
+
scope?: string;
|
|
34
|
+
/** Signed-in user's login name. */
|
|
35
|
+
username: string;
|
|
36
|
+
/** Authorize URL to resume once the decision is recorded. */
|
|
37
|
+
returnTo: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The consent screen shown when the config sets `"consent": "prompt"`.
|
|
41
|
+
* Submits to `POST /consent` with `decision=approve` or `decision=deny`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function consentPage(options: ConsentPageOptions): string;
|
|
44
|
+
/** Options for {@link statusPage}. */
|
|
45
|
+
export interface StatusPageOptions {
|
|
46
|
+
/** Issuer as resolved for this request. */
|
|
47
|
+
issuer: string;
|
|
48
|
+
/** Seeded users. */
|
|
49
|
+
users: readonly DevIdpUserConfig[];
|
|
50
|
+
/** Registered clients. */
|
|
51
|
+
clients: readonly DevIdpClientConfig[];
|
|
52
|
+
}
|
|
53
|
+
/** The page served at `/`: what is seeded and where the endpoints are. */
|
|
54
|
+
export declare function statusPage(options: StatusPageOptions): string;
|
|
55
|
+
/** A terminal page for a flow that ended without a redirect. */
|
|
56
|
+
export declare function messagePage(title: string, message: string): string;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The development identity provider's HTML: a sign-in page, a consent screen,
|
|
3
|
+
* and the status page served at `/`.
|
|
4
|
+
*
|
|
5
|
+
* Hand-written markup with no client-side JavaScript, so the pages render the
|
|
6
|
+
* same in a browser and in a `fetch`-driven test. Every control a test needs
|
|
7
|
+
* carries a stable `id` and `name`.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
const STYLE = `
|
|
12
|
+
:root { color-scheme: light dark; }
|
|
13
|
+
body {
|
|
14
|
+
font: 16px/1.5 system-ui, sans-serif;
|
|
15
|
+
margin: 0 auto; padding: 2rem 1.25rem; max-width: 40rem;
|
|
16
|
+
}
|
|
17
|
+
h1 { font-size: 1.5rem; margin: 0 0 0.25rem; }
|
|
18
|
+
h2 { font-size: 1.05rem; margin: 1.75rem 0 0.5rem; }
|
|
19
|
+
.banner {
|
|
20
|
+
border: 1px solid currentColor; border-radius: 6px;
|
|
21
|
+
padding: 0.5rem 0.75rem; margin-bottom: 1.5rem;
|
|
22
|
+
font-size: 0.85rem; font-weight: 600; letter-spacing: 0.02em;
|
|
23
|
+
}
|
|
24
|
+
label { display: block; margin: 0.75rem 0 0.25rem; font-size: 0.9rem; }
|
|
25
|
+
input {
|
|
26
|
+
width: 100%; padding: 0.5rem; font: inherit;
|
|
27
|
+
border: 1px solid currentColor; border-radius: 4px; background: transparent;
|
|
28
|
+
}
|
|
29
|
+
button {
|
|
30
|
+
font: inherit; padding: 0.5rem 1rem; margin: 1rem 0.5rem 0 0;
|
|
31
|
+
border: 1px solid currentColor; border-radius: 4px;
|
|
32
|
+
background: transparent; cursor: pointer;
|
|
33
|
+
}
|
|
34
|
+
.error { font-weight: 600; margin-top: 1rem; }
|
|
35
|
+
ul { padding-left: 1.25rem; }
|
|
36
|
+
li { margin: 0.25rem 0; }
|
|
37
|
+
code, .mono { font-family: ui-monospace, monospace; font-size: 0.9em; }
|
|
38
|
+
.quick { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
|
39
|
+
.quick button { margin: 0; }
|
|
40
|
+
footer { margin-top: 2rem; font-size: 0.85rem; opacity: 0.75; }
|
|
41
|
+
`;
|
|
42
|
+
function escapeHtml(value) {
|
|
43
|
+
return value
|
|
44
|
+
.replaceAll("&", "&")
|
|
45
|
+
.replaceAll("<", "<")
|
|
46
|
+
.replaceAll(">", ">")
|
|
47
|
+
.replaceAll('"', """)
|
|
48
|
+
.replaceAll("'", "'");
|
|
49
|
+
}
|
|
50
|
+
function layout(title, body) {
|
|
51
|
+
return `<!DOCTYPE html>
|
|
52
|
+
<html lang="en">
|
|
53
|
+
<head>
|
|
54
|
+
<meta charset="utf-8">
|
|
55
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
56
|
+
<meta name="robots" content="noindex">
|
|
57
|
+
<title>${escapeHtml(title)}</title>
|
|
58
|
+
<style>${STYLE}</style>
|
|
59
|
+
</head>
|
|
60
|
+
<body>
|
|
61
|
+
<p class="banner" id="dev-only-banner">Development identity provider — never
|
|
62
|
+
expose this to a network you do not control.</p>
|
|
63
|
+
${body}
|
|
64
|
+
<footer>@udibo/oauth2 <code>idp dev</code> · in-memory, no persistence</footer>
|
|
65
|
+
</body>
|
|
66
|
+
</html>
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
/** Wraps HTML in a `Response` with the headers a browser and a test expect. */
|
|
70
|
+
export function htmlResponse(html, status = 200) {
|
|
71
|
+
return new Response(html, {
|
|
72
|
+
status,
|
|
73
|
+
headers: {
|
|
74
|
+
"content-type": "text/html; charset=utf-8",
|
|
75
|
+
"cache-control": "no-store",
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The sign-in page. Submits to `POST /login` with `username` + `password`, or
|
|
81
|
+
* with `as=<username>` from a one-click button.
|
|
82
|
+
*/
|
|
83
|
+
export function loginPage(options) {
|
|
84
|
+
const { returnTo, users, error } = options;
|
|
85
|
+
const quickSignIn = users.length === 0
|
|
86
|
+
? ""
|
|
87
|
+
: `
|
|
88
|
+
<h2>Seeded users</h2>
|
|
89
|
+
<div class="quick">
|
|
90
|
+
${users
|
|
91
|
+
.map((user) => ` <button type="submit" name="as" value="${escapeHtml(user.username)}" form="sign-in-form">Sign in as ${escapeHtml(user.username)}</button>`)
|
|
92
|
+
.join("\n")}
|
|
93
|
+
</div>
|
|
94
|
+
<p class="mono">Passwords are printed in the startup banner.</p>`;
|
|
95
|
+
return layout("Sign in", `
|
|
96
|
+
<h1>Sign in</h1>
|
|
97
|
+
${error ? `<p class="error" id="sign-in-error">${escapeHtml(error)}</p>` : ""}
|
|
98
|
+
<form method="post" action="/login" id="sign-in-form">
|
|
99
|
+
<input type="hidden" name="return_to" value="${escapeHtml(returnTo)}">
|
|
100
|
+
<label for="username">Username</label>
|
|
101
|
+
<input id="username" name="username" autocomplete="username" autofocus>
|
|
102
|
+
<label for="password">Password</label>
|
|
103
|
+
<input id="password" name="password" type="password"
|
|
104
|
+
autocomplete="current-password">
|
|
105
|
+
<button type="submit" id="sign-in">Sign in</button>
|
|
106
|
+
</form>
|
|
107
|
+
${quickSignIn}
|
|
108
|
+
`);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The consent screen shown when the config sets `"consent": "prompt"`.
|
|
112
|
+
* Submits to `POST /consent` with `decision=approve` or `decision=deny`.
|
|
113
|
+
*/
|
|
114
|
+
export function consentPage(options) {
|
|
115
|
+
const { clientId, scope, username, returnTo } = options;
|
|
116
|
+
return layout("Authorize application", `
|
|
117
|
+
<h1>Authorize application</h1>
|
|
118
|
+
<p><span class="mono">${escapeHtml(clientId)}</span> wants to access your
|
|
119
|
+
account as <span class="mono">${escapeHtml(username)}</span>.</p>
|
|
120
|
+
<h2>Requested scope</h2>
|
|
121
|
+
<p class="mono" id="requested-scope">${scope ? escapeHtml(scope) : "(no scope requested)"}</p>
|
|
122
|
+
<form method="post" action="/consent" id="consent-form">
|
|
123
|
+
<input type="hidden" name="return_to" value="${escapeHtml(returnTo)}">
|
|
124
|
+
<button type="submit" name="decision" value="approve" id="approve">
|
|
125
|
+
Approve
|
|
126
|
+
</button>
|
|
127
|
+
<button type="submit" name="decision" value="deny" id="deny">Deny</button>
|
|
128
|
+
</form>
|
|
129
|
+
`);
|
|
130
|
+
}
|
|
131
|
+
/** The page served at `/`: what is seeded and where the endpoints are. */
|
|
132
|
+
export function statusPage(options) {
|
|
133
|
+
const { issuer, users, clients } = options;
|
|
134
|
+
const userList = users
|
|
135
|
+
.map((user) => ` <li><span class="mono">${escapeHtml(user.username)}</span> · password
|
|
136
|
+
<span class="mono">${escapeHtml(user.password)}</span> · sub
|
|
137
|
+
<span class="mono">${escapeHtml(user.id)}</span></li>`)
|
|
138
|
+
.join("\n");
|
|
139
|
+
const clientList = clients
|
|
140
|
+
.map((client) => ` <li><span class="mono">${escapeHtml(client.id)}</span>${client.secret
|
|
141
|
+
? ` · secret <span class="mono">${escapeHtml(client.secret)}</span>`
|
|
142
|
+
: " · public client"}<br>redirect URIs: <span class="mono">${client.redirectUris.map(escapeHtml).join(", ") || "(none)"}</span><br>grants: <span class="mono">${client.grants
|
|
143
|
+
.map(escapeHtml)
|
|
144
|
+
.join(", ")}</span></li>`)
|
|
145
|
+
.join("\n");
|
|
146
|
+
return layout("Development identity provider", `
|
|
147
|
+
<h1>Development identity provider</h1>
|
|
148
|
+
<p>Issuer <span class="mono">${escapeHtml(issuer)}</span></p>
|
|
149
|
+
<h2>Endpoints</h2>
|
|
150
|
+
<ul>
|
|
151
|
+
<li><a href="/.well-known/openid-configuration">
|
|
152
|
+
/.well-known/openid-configuration</a></li>
|
|
153
|
+
<li><a href="/jwks">/jwks</a></li>
|
|
154
|
+
<li><span class="mono">/authorize</span>,
|
|
155
|
+
<span class="mono">/token</span>,
|
|
156
|
+
<span class="mono">/userinfo</span>,
|
|
157
|
+
<span class="mono">/revoke</span>,
|
|
158
|
+
<span class="mono">/introspect</span></li>
|
|
159
|
+
<li><span class="mono">/login</span>,
|
|
160
|
+
<span class="mono">/logout</span></li>
|
|
161
|
+
</ul>
|
|
162
|
+
<h2>Users</h2>
|
|
163
|
+
<ul>
|
|
164
|
+
${userList || " <li>(none seeded)</li>"}
|
|
165
|
+
</ul>
|
|
166
|
+
<h2>Clients</h2>
|
|
167
|
+
<ul>
|
|
168
|
+
${clientList || " <li>(none registered)</li>"}
|
|
169
|
+
</ul>
|
|
170
|
+
<h2>Test control surface</h2>
|
|
171
|
+
<ul>
|
|
172
|
+
<li><span class="mono">POST /__admin/reset</span> — drop every session,
|
|
173
|
+
code, and token</li>
|
|
174
|
+
<li><span class="mono">POST /__admin/session</span> — sign a user in
|
|
175
|
+
without the form</li>
|
|
176
|
+
<li><span class="mono">POST /__admin/tokens</span> — mint tokens without
|
|
177
|
+
the browser</li>
|
|
178
|
+
<li><span class="mono">GET /__admin/state</span> — what is seeded right
|
|
179
|
+
now</li>
|
|
180
|
+
</ul>
|
|
181
|
+
`);
|
|
182
|
+
}
|
|
183
|
+
/** A terminal page for a flow that ended without a redirect. */
|
|
184
|
+
export function messagePage(title, message) {
|
|
185
|
+
return layout(title, `
|
|
186
|
+
<h1>${escapeHtml(title)}</h1>
|
|
187
|
+
<p id="message">${escapeHtml(message)}</p>
|
|
188
|
+
<p><a href="/">Back to the status page</a></p>
|
|
189
|
+
`);
|
|
190
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The development identity provider itself: a real {@link AuthorizationServer}
|
|
3
|
+
* over the in-memory services, served on a socket with a sign-in page, an
|
|
4
|
+
* optional consent screen, and a test-control surface under `/__admin/`.
|
|
5
|
+
*
|
|
6
|
+
* Everything here is packaging — the protocol behavior is the same code an
|
|
7
|
+
* application runs in production. What makes it a development tool is the
|
|
8
|
+
* storage (memory, dropped on exit) and the admin endpoints, which mint tokens
|
|
9
|
+
* for any seeded user without their password.
|
|
10
|
+
*
|
|
11
|
+
* Three guardrails are enforced rather than documented: the admin endpoints
|
|
12
|
+
* require a startup token in a custom header (so a browser must preflight, and
|
|
13
|
+
* a drive-by page cannot), a non-loopback bind needs an explicit opt-in, and
|
|
14
|
+
* the issuer is pinned at startup instead of read from the request's `Host`.
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import { type SigningKey } from "../../server/signing-keys.ts";
|
|
19
|
+
import type { DevIdpConfig } from "./config.ts";
|
|
20
|
+
/** Header the admin endpoints require, carrying the token printed at startup. */
|
|
21
|
+
export declare const ADMIN_TOKEN_HEADER = "x-admin-token";
|
|
22
|
+
/**
|
|
23
|
+
* Whether a bind address only accepts connections from this machine. A
|
|
24
|
+
* non-loopback bind exposes the admin endpoints to the network, so it needs an
|
|
25
|
+
* explicit opt-in.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isLoopbackHostname(hostname: string): boolean;
|
|
28
|
+
/** A running development identity provider. */
|
|
29
|
+
export interface DevIdentityProvider {
|
|
30
|
+
/** Base URL the server is reachable at. */
|
|
31
|
+
url: string;
|
|
32
|
+
/** Issuer pinned at startup and stamped into every token and metadata document. */
|
|
33
|
+
issuer: string;
|
|
34
|
+
/** Token the `/__admin/` endpoints require in {@link ADMIN_TOKEN_HEADER}. */
|
|
35
|
+
adminToken: string;
|
|
36
|
+
/** Port the server bound. Resolved when the config asked for port `0`. */
|
|
37
|
+
port: number;
|
|
38
|
+
/** Hostname the server bound. */
|
|
39
|
+
hostname: string;
|
|
40
|
+
/** Resolves once the server has finished shutting down. */
|
|
41
|
+
finished: Promise<void>;
|
|
42
|
+
/** Stops accepting connections and drains in-flight requests. */
|
|
43
|
+
shutdown(): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
/** Options for {@link startDevIdentityProvider}. */
|
|
46
|
+
export interface StartDevIdentityProviderOptions {
|
|
47
|
+
/** Resolved configuration, as returned by the config parser. */
|
|
48
|
+
config: DevIdpConfig;
|
|
49
|
+
/** Key the server signs id_tokens with and publishes at `/jwks`. */
|
|
50
|
+
signingKey: SigningKey;
|
|
51
|
+
/**
|
|
52
|
+
* Token the admin endpoints require. Generated when omitted; supply one so a
|
|
53
|
+
* CI job can hold it before the server starts.
|
|
54
|
+
*/
|
|
55
|
+
adminToken?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Permits binding a non-loopback address, which exposes the admin endpoints
|
|
58
|
+
* to the network. Refused unless this is explicitly set.
|
|
59
|
+
*/
|
|
60
|
+
allowRemoteAccess?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Starts the development identity provider on a socket and resolves once it is
|
|
64
|
+
* accepting connections.
|
|
65
|
+
*
|
|
66
|
+
* The caller owns the lifetime: keep the returned {@link DevIdentityProvider}
|
|
67
|
+
* and call `shutdown()` (a test's `finally`, a CI teardown step). Nothing is
|
|
68
|
+
* written to disk and no state survives the process.
|
|
69
|
+
*
|
|
70
|
+
* **This server is for development and CI only.** Its `/__admin/` endpoints
|
|
71
|
+
* mint tokens for any seeded user without their password; they are gated by
|
|
72
|
+
* {@link DevIdentityProvider.adminToken}, not by anything stronger.
|
|
73
|
+
*
|
|
74
|
+
* @throws {Error} When the config binds a non-loopback address without
|
|
75
|
+
* `allowRemoteAccess`.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* const idp = await startDevIdentityProvider({
|
|
80
|
+
* config: defaultDevIdpConfig(),
|
|
81
|
+
* signingKey: await generateSigningKey(),
|
|
82
|
+
* });
|
|
83
|
+
* try {
|
|
84
|
+
* const discovery = await fetch(
|
|
85
|
+
* `${idp.url}/.well-known/openid-configuration`,
|
|
86
|
+
* );
|
|
87
|
+
* // ...point the app under test at the discovered endpoints.
|
|
88
|
+
* } finally {
|
|
89
|
+
* await idp.shutdown();
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export declare function startDevIdentityProvider(options: StartDevIdentityProviderOptions): Promise<DevIdentityProvider>;
|