@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
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*
|
|
22
22
|
* @module
|
|
23
23
|
*/
|
|
24
|
-
import type { TokenFlowStore } from "../../identity/token-flow.
|
|
24
|
+
import type { TokenFlowStore } from "../../identity/token-flow.ts";
|
|
25
25
|
/** Options for {@link runTokenFlowStoreContractTests}. */
|
|
26
26
|
export interface TokenFlowStoreContractOptions {
|
|
27
27
|
/**
|
|
@@ -21,8 +21,7 @@
|
|
|
21
21
|
*
|
|
22
22
|
* @module
|
|
23
23
|
*/
|
|
24
|
-
import { assert,
|
|
25
|
-
import { beforeEach, describe, it } from "../../deps/jsr.io/@std/testing/1.0.20/bdd.js";
|
|
24
|
+
import { assert, beforeEach, describe, expect, it } from "vitest";
|
|
26
25
|
import { CONCURRENT_CALLERS, race } from "./_race.js";
|
|
27
26
|
const PURPOSE = "password-reset";
|
|
28
27
|
const OTHER_PURPOSE = "email-verification";
|
|
@@ -59,7 +58,7 @@ export function runTokenFlowStoreContractTests(options) {
|
|
|
59
58
|
});
|
|
60
59
|
describe("save / get", () => {
|
|
61
60
|
it("returns null for an unknown token hash", async () => {
|
|
62
|
-
|
|
61
|
+
expect(await store.get("no-such-hash")).toBe(null);
|
|
63
62
|
});
|
|
64
63
|
it("round-trips every field of a saved record", async () => {
|
|
65
64
|
const saved = record({
|
|
@@ -69,12 +68,12 @@ export function runTokenFlowStoreContractTests(options) {
|
|
|
69
68
|
await store.save(saved);
|
|
70
69
|
const fetched = await store.get("hash-1");
|
|
71
70
|
assert(fetched !== null, "a saved record must be readable back");
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
expect(fetched.purpose).toStrictEqual(saved.purpose);
|
|
72
|
+
expect(fetched.subject).toStrictEqual(saved.subject);
|
|
73
|
+
expect(fetched.data).toStrictEqual(saved.data);
|
|
74
|
+
expect(fetched.expiresAt).toBe(saved.expiresAt);
|
|
75
|
+
expect(fetched.createdAt).toBe(saved.createdAt);
|
|
76
|
+
expect(fetched.consumedAt).toBe(undefined);
|
|
78
77
|
});
|
|
79
78
|
it("returns an expired record rather than hiding it", async () => {
|
|
80
79
|
await store.save(record({ tokenHash: "hash-expired", expiresAt: Date.now() - 1000 }));
|
|
@@ -85,33 +84,33 @@ export function runTokenFlowStoreContractTests(options) {
|
|
|
85
84
|
it("keeps records with different hashes independent", async () => {
|
|
86
85
|
await store.save(record({ tokenHash: "hash-1" }));
|
|
87
86
|
await store.save(record({ tokenHash: "hash-2" }));
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
expect((await store.get("hash-1"))?.tokenHash).toBe("hash-1");
|
|
88
|
+
expect((await store.get("hash-2"))?.tokenHash).toBe("hash-2");
|
|
90
89
|
});
|
|
91
90
|
});
|
|
92
91
|
describe("markConsumed", () => {
|
|
93
92
|
it("claims a live record and stamps it", async () => {
|
|
94
93
|
await store.save(record({ tokenHash: "hash-1" }));
|
|
95
94
|
const consumedAt = Date.now();
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
expect(await store.markConsumed("hash-1", consumedAt)).toBe(true);
|
|
96
|
+
expect((await store.get("hash-1"))?.consumedAt).toBe(consumedAt);
|
|
98
97
|
});
|
|
99
98
|
it("refuses a record already consumed, keeping the first stamp", async () => {
|
|
100
99
|
await store.save(record({ tokenHash: "hash-1" }));
|
|
101
100
|
const first = Date.now();
|
|
102
101
|
await store.markConsumed("hash-1", first);
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
expect(await store.markConsumed("hash-1", first + 5_000)).toBe(false);
|
|
103
|
+
expect((await store.get("hash-1"))?.consumedAt, "a losing claim must not overwrite the winner's record").toBe(first);
|
|
105
104
|
});
|
|
106
105
|
it("refuses an unknown token hash", async () => {
|
|
107
|
-
|
|
106
|
+
expect(await store.markConsumed("no-such-hash", Date.now())).toBe(false);
|
|
108
107
|
});
|
|
109
108
|
it(`claims a token for exactly one of ${CONCURRENT_CALLERS} concurrent redemptions`, async () => {
|
|
110
109
|
await store.save(record({ tokenHash: "hash-1" }));
|
|
111
110
|
const now = Date.now();
|
|
112
111
|
const results = await race((caller) => store.markConsumed("hash-1", now + caller));
|
|
113
|
-
|
|
114
|
-
"told they claimed it");
|
|
112
|
+
expect(countTrue(results), "a link is single-use — requests racing one link must not each be " +
|
|
113
|
+
"told they claimed it").toBe(1);
|
|
115
114
|
});
|
|
116
115
|
it("claims both tokens when two different ones are redeemed concurrently", async () => {
|
|
117
116
|
await store.save(record({ tokenHash: "hash-1" }));
|
|
@@ -121,7 +120,7 @@ export function runTokenFlowStoreContractTests(options) {
|
|
|
121
120
|
store.markConsumed("hash-1", now),
|
|
122
121
|
store.markConsumed("hash-2", now),
|
|
123
122
|
]);
|
|
124
|
-
|
|
123
|
+
expect(countTrue(results)).toBe(2);
|
|
125
124
|
assert((await store.get("hash-1"))?.consumedAt !== undefined &&
|
|
126
125
|
(await store.get("hash-2"))?.consumedAt !== undefined, "neither stamp may be lost to the other's stale read");
|
|
127
126
|
});
|
|
@@ -138,29 +137,29 @@ export function runTokenFlowStoreContractTests(options) {
|
|
|
138
137
|
await store.save(record({ tokenHash: "hash-1" }));
|
|
139
138
|
await store.save(record({ tokenHash: "hash-2" }));
|
|
140
139
|
await store.deleteBySubject(PURPOSE, SUBJECT);
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
expect(await store.get("hash-1")).toBe(null);
|
|
141
|
+
expect(await store.get("hash-2")).toBe(null);
|
|
143
142
|
});
|
|
144
143
|
it("leaves other subjects and other purposes alone", async () => {
|
|
145
144
|
await store.save(record({ tokenHash: "hash-mine" }));
|
|
146
145
|
await store.save(record({ tokenHash: "hash-other-subject", subject: OTHER_SUBJECT }));
|
|
147
146
|
await store.save(record({ tokenHash: "hash-other-purpose", purpose: OTHER_PURPOSE }));
|
|
148
147
|
await store.deleteBySubject(PURPOSE, SUBJECT);
|
|
149
|
-
|
|
150
|
-
assert(await store.get("hash-other-subject") !== null, "another subject's token must survive");
|
|
151
|
-
assert(await store.get("hash-other-purpose") !== null, "the same subject's token for another purpose must survive");
|
|
148
|
+
expect(await store.get("hash-mine")).toBe(null);
|
|
149
|
+
assert((await store.get("hash-other-subject")) !== null, "another subject's token must survive");
|
|
150
|
+
assert((await store.get("hash-other-purpose")) !== null, "the same subject's token for another purpose must survive");
|
|
152
151
|
});
|
|
153
152
|
it("is a no-op when the pair has no tokens", async () => {
|
|
154
153
|
await store.save(record({ tokenHash: "hash-1" }));
|
|
155
154
|
await store.deleteBySubject(PURPOSE, OTHER_SUBJECT);
|
|
156
|
-
assert(await store.get("hash-1") !== null);
|
|
155
|
+
assert((await store.get("hash-1")) !== null);
|
|
157
156
|
});
|
|
158
157
|
it("keeps an already-consumed record so it still reads as consumed", async () => {
|
|
159
158
|
await store.save(record({ tokenHash: "hash-used" }));
|
|
160
159
|
await store.save(record({ tokenHash: "hash-pending" }));
|
|
161
|
-
|
|
160
|
+
expect(await store.markConsumed("hash-used", Date.now())).toBe(true);
|
|
162
161
|
await store.deleteBySubject(PURPOSE, SUBJECT);
|
|
163
|
-
|
|
162
|
+
expect(await store.get("hash-pending"), "the pending token must be dropped").toBe(null);
|
|
164
163
|
const used = await store.get("hash-used");
|
|
165
164
|
assert(used !== null, "a consumed record must survive so inspect() can answer " +
|
|
166
165
|
"`consumed` rather than the generic `invalid`");
|
|
@@ -169,11 +168,7 @@ export function runTokenFlowStoreContractTests(options) {
|
|
|
169
168
|
});
|
|
170
169
|
}
|
|
171
170
|
else {
|
|
172
|
-
it({
|
|
173
|
-
name: "deleteBySubject is not implemented — outstanding links stay redeemable until they expire (deleteBySubject: false)",
|
|
174
|
-
ignore: true,
|
|
175
|
-
fn: () => { },
|
|
176
|
-
});
|
|
171
|
+
it.skip("deleteBySubject is not implemented — outstanding links stay redeemable until they expire (deleteBySubject: false)", () => { });
|
|
177
172
|
}
|
|
178
173
|
});
|
|
179
174
|
}
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
*
|
|
37
37
|
* @module
|
|
38
38
|
*/
|
|
39
|
-
import type { ClientInterface } from "../../models/client.
|
|
40
|
-
import type { AbstractScope, BasicScope } from "../../models/scope.
|
|
41
|
-
import type { TokenReaderInterface } from "../../server/services/token.
|
|
39
|
+
import type { ClientInterface } from "../../models/client.ts";
|
|
40
|
+
import type { AbstractScope, BasicScope } from "../../models/scope.ts";
|
|
41
|
+
import type { TokenReaderInterface } from "../../server/services/token.ts";
|
|
42
42
|
/** The reader under test plus the tokens the suite exercises it with. */
|
|
43
43
|
export interface TokenReaderContractFixture<C extends ClientInterface, U, S extends AbstractScope = BasicScope> {
|
|
44
44
|
/** The reader under test. */
|
|
@@ -36,8 +36,7 @@
|
|
|
36
36
|
*
|
|
37
37
|
* @module
|
|
38
38
|
*/
|
|
39
|
-
import { assert,
|
|
40
|
-
import { afterEach, beforeEach, describe, it } from "../../deps/jsr.io/@std/testing/1.0.20/bdd.js";
|
|
39
|
+
import { afterEach, assert, beforeEach, describe, expect, it } from "vitest";
|
|
41
40
|
/** Runs the {@link TokenReaderInterface} contract suite. */
|
|
42
41
|
export function runTokenReaderContractTests(options) {
|
|
43
42
|
describe(options.describeName ?? "TokenReaderInterface contract", () => {
|
|
@@ -50,19 +49,19 @@ export function runTokenReaderContractTests(options) {
|
|
|
50
49
|
});
|
|
51
50
|
it("echoes back the access token it was given", async () => {
|
|
52
51
|
const token = await fixture.reader.getToken(fixture.validAccessToken);
|
|
53
|
-
|
|
52
|
+
expect(token?.accessToken).toBe(fixture.validAccessToken);
|
|
54
53
|
});
|
|
55
54
|
it("projects the client the token was issued to", async () => {
|
|
56
55
|
const token = await fixture.reader.getToken(fixture.validAccessToken);
|
|
57
|
-
|
|
56
|
+
expect(token?.client.id).toBe(fixture.expected.clientId);
|
|
58
57
|
});
|
|
59
58
|
it("projects the user the token was issued for", async () => {
|
|
60
59
|
const token = await fixture.reader.getToken(fixture.validAccessToken);
|
|
61
|
-
|
|
60
|
+
expect(token?.user?.id).toBe(fixture.expected.userId);
|
|
62
61
|
});
|
|
63
62
|
it("exposes the granted scope", async () => {
|
|
64
63
|
const token = await fixture.reader.getToken(fixture.validAccessToken);
|
|
65
|
-
|
|
64
|
+
expect(token?.scope?.toString()).toBe(fixture.expected.scope);
|
|
66
65
|
});
|
|
67
66
|
it("exposes an expiry as a Date when the token carries one", async () => {
|
|
68
67
|
const token = await fixture.reader.getToken(fixture.validAccessToken);
|
|
@@ -71,7 +70,7 @@ export function runTokenReaderContractTests(options) {
|
|
|
71
70
|
});
|
|
72
71
|
it("resolves undefined for tokens it cannot validate", async () => {
|
|
73
72
|
for (const accessToken of fixture.invalidAccessTokens) {
|
|
74
|
-
|
|
73
|
+
expect(await fixture.reader.getToken(accessToken), `expected ${accessToken} to be rejected with undefined`).toBe(undefined);
|
|
75
74
|
}
|
|
76
75
|
});
|
|
77
76
|
});
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @module
|
|
16
16
|
*/
|
|
17
|
-
import type { ClientInterface } from "../../models/client.
|
|
18
|
-
import { BasicScope } from "../../models/scope.
|
|
19
|
-
import type { AbstractScope } from "../../models/scope.
|
|
20
|
-
import type { ClientServiceInterface } from "../../server/services/client.
|
|
21
|
-
import type { TokenServiceInterface } from "../../server/services/token.
|
|
22
|
-
import type { UserServiceInterface } from "../../server/services/user.
|
|
23
|
-
import type { MemoryUserShape } from "../services.
|
|
17
|
+
import type { ClientInterface } from "../../models/client.ts";
|
|
18
|
+
import { BasicScope } from "../../models/scope.ts";
|
|
19
|
+
import type { AbstractScope } from "../../models/scope.ts";
|
|
20
|
+
import type { ClientServiceInterface } from "../../server/services/client.ts";
|
|
21
|
+
import type { TokenServiceInterface } from "../../server/services/token.ts";
|
|
22
|
+
import type { UserServiceInterface } from "../../server/services/user.ts";
|
|
23
|
+
import type { MemoryUserShape } from "../services.ts";
|
|
24
24
|
/** Options for {@link runTokenServiceContractTests}. */
|
|
25
25
|
export interface TokenServiceContractOptions<C extends ClientInterface, U extends MemoryUserShape, S extends AbstractScope = BasicScope> {
|
|
26
26
|
/** Returns fresh services for each test. */
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @module
|
|
16
16
|
*/
|
|
17
|
-
import { assert,
|
|
18
|
-
import { beforeEach, describe, it } from "../../deps/jsr.io/@std/testing/1.0.20/bdd.js";
|
|
17
|
+
import { assert, beforeEach, describe, expect, it } from "vitest";
|
|
19
18
|
import { BasicScope } from "../../models/scope.js";
|
|
20
19
|
const defaultMakeUser = (seq) => ({ id: `u${seq}`, username: `user${seq}` });
|
|
21
20
|
const defaultMakeClient = (seq) => ({
|
|
@@ -25,9 +24,9 @@ const defaultMakeClient = (seq) => ({
|
|
|
25
24
|
const defaultMakeScope = (value) => new BasicScope(value);
|
|
26
25
|
/** Runs the {@link TokenServiceInterface} contract suite. */
|
|
27
26
|
export function runTokenServiceContractTests(options) {
|
|
28
|
-
const makeUser = options.makeUser ??
|
|
29
|
-
const makeClient = options.makeClient ??
|
|
30
|
-
const makeScope = options.makeScope ??
|
|
27
|
+
const makeUser = options.makeUser ?? defaultMakeUser;
|
|
28
|
+
const makeClient = options.makeClient ?? defaultMakeClient;
|
|
29
|
+
const makeScope = options.makeScope ?? defaultMakeScope;
|
|
31
30
|
const expectReuseDetection = options.refreshTokenReuseDetection ?? true;
|
|
32
31
|
describe(options.describeName ?? "TokenServiceInterface contract", () => {
|
|
33
32
|
let userService;
|
|
@@ -49,8 +48,8 @@ export function runTokenServiceContractTests(options) {
|
|
|
49
48
|
it("produces unique access tokens", async () => {
|
|
50
49
|
const a = await tokenService.generateAccessToken(client, user);
|
|
51
50
|
const b = await tokenService.generateAccessToken(client, user);
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
expect(typeof a).toStrictEqual("string");
|
|
52
|
+
expect(typeof b).toStrictEqual("string");
|
|
54
53
|
assert(a !== b, "access tokens should not collide");
|
|
55
54
|
});
|
|
56
55
|
it("produces unique refresh tokens (or undefined to opt out)", async () => {
|
|
@@ -65,7 +64,7 @@ export function runTokenServiceContractTests(options) {
|
|
|
65
64
|
it("returns the requested scope unchanged for the simple case", async () => {
|
|
66
65
|
const requested = makeScope("read");
|
|
67
66
|
const result = await tokenService.acceptedScope(client, user, requested);
|
|
68
|
-
|
|
67
|
+
expect(result?.toString()).toStrictEqual("read");
|
|
69
68
|
});
|
|
70
69
|
});
|
|
71
70
|
describe("save + getToken", () => {
|
|
@@ -80,18 +79,18 @@ export function runTokenServiceContractTests(options) {
|
|
|
80
79
|
};
|
|
81
80
|
await tokenService.save(token);
|
|
82
81
|
const fetched = await tokenService.getToken(accessToken);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
expect(fetched?.client.id).toStrictEqual(client.id);
|
|
83
|
+
expect(fetched?.user?.id).toStrictEqual(user.id);
|
|
84
|
+
expect(fetched?.accessTokenExpiresAt?.getTime()).toBe(expiresAt.getTime());
|
|
86
85
|
});
|
|
87
86
|
it("returns undefined for an unknown access token", async () => {
|
|
88
|
-
|
|
87
|
+
expect(await tokenService.getToken("nope")).toBe(undefined);
|
|
89
88
|
});
|
|
90
89
|
});
|
|
91
90
|
describe("tokens with no user", () => {
|
|
92
91
|
it("generates an access token for a client with no user", async () => {
|
|
93
92
|
const accessToken = await tokenService.generateAccessToken(client, undefined);
|
|
94
|
-
|
|
93
|
+
expect(typeof accessToken).toStrictEqual("string");
|
|
95
94
|
});
|
|
96
95
|
it("accepts scope for a client with no user", async () => {
|
|
97
96
|
const result = await tokenService.acceptedScope(client, undefined, makeScope("read"));
|
|
@@ -106,14 +105,14 @@ export function runTokenServiceContractTests(options) {
|
|
|
106
105
|
const accessToken = await tokenService.generateAccessToken(client, undefined);
|
|
107
106
|
await tokenService.save({ accessToken, client });
|
|
108
107
|
const fetched = await tokenService.getToken(accessToken);
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
expect(fetched?.client.id).toStrictEqual(client.id);
|
|
109
|
+
expect(fetched?.user).toBe(undefined);
|
|
111
110
|
});
|
|
112
111
|
it("revokes a token with no user", async () => {
|
|
113
112
|
const accessToken = await tokenService.generateAccessToken(client, undefined);
|
|
114
113
|
await tokenService.save({ accessToken, client });
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
expect(await tokenService.revoke(accessToken)).toBe(true);
|
|
115
|
+
expect(await tokenService.getToken(accessToken)).toBe(undefined);
|
|
117
116
|
});
|
|
118
117
|
});
|
|
119
118
|
describe("save + getRefreshToken", () => {
|
|
@@ -130,10 +129,10 @@ export function runTokenServiceContractTests(options) {
|
|
|
130
129
|
};
|
|
131
130
|
await tokenService.save(token);
|
|
132
131
|
const fetched = await tokenService.getRefreshToken(refreshToken);
|
|
133
|
-
|
|
132
|
+
expect(fetched?.client.id).toStrictEqual(client.id);
|
|
134
133
|
});
|
|
135
134
|
it("returns undefined for an unknown refresh token", async () => {
|
|
136
|
-
|
|
135
|
+
expect(await tokenService.getRefreshToken("nope")).toBe(undefined);
|
|
137
136
|
});
|
|
138
137
|
});
|
|
139
138
|
describe("revoke", () => {
|
|
@@ -146,15 +145,15 @@ export function runTokenServiceContractTests(options) {
|
|
|
146
145
|
};
|
|
147
146
|
await tokenService.save(token);
|
|
148
147
|
const ok = await tokenService.revoke(token);
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
expect(ok).toBe(true);
|
|
149
|
+
expect(await tokenService.getToken(accessToken)).toBe(undefined);
|
|
151
150
|
});
|
|
152
151
|
it("revokes by access token string", async () => {
|
|
153
152
|
const accessToken = await tokenService.generateAccessToken(client, user);
|
|
154
153
|
await tokenService.save({ accessToken, client, user });
|
|
155
154
|
const ok = await tokenService.revoke(accessToken);
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
expect(ok).toBe(true);
|
|
156
|
+
expect(await tokenService.getToken(accessToken)).toBe(undefined);
|
|
158
157
|
});
|
|
159
158
|
it("revokes by refresh token string when hint='refresh_token'", async () => {
|
|
160
159
|
const accessToken = await tokenService.generateAccessToken(client, user);
|
|
@@ -166,21 +165,21 @@ export function runTokenServiceContractTests(options) {
|
|
|
166
165
|
user,
|
|
167
166
|
});
|
|
168
167
|
const ok = await tokenService.revoke(refreshToken, "refresh_token");
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
168
|
+
expect(ok).toBe(true);
|
|
169
|
+
expect(await tokenService.getRefreshToken(refreshToken)).toBe(undefined);
|
|
170
|
+
expect(await tokenService.getToken(accessToken)).toBe(undefined);
|
|
172
171
|
});
|
|
173
172
|
it("returns false for an unknown token string", async () => {
|
|
174
|
-
|
|
173
|
+
expect(await tokenService.revoke("missing")).toBe(false);
|
|
175
174
|
});
|
|
176
175
|
it("answers true only for the call that removed a live token", async () => {
|
|
177
176
|
const accessToken = await tokenService.generateAccessToken(client, user);
|
|
178
177
|
const token = { accessToken, client, user };
|
|
179
|
-
|
|
180
|
-
"answering true makes a single-use check built on the result inert");
|
|
178
|
+
expect(await tokenService.revoke(token), "a token that was never saved was not revoked by this call — " +
|
|
179
|
+
"answering true makes a single-use check built on the result inert").toBe(false);
|
|
181
180
|
await tokenService.save(token);
|
|
182
|
-
|
|
183
|
-
|
|
181
|
+
expect(await tokenService.revoke(token)).toBe(true);
|
|
182
|
+
expect(await tokenService.revoke(token)).toBe(false);
|
|
184
183
|
});
|
|
185
184
|
});
|
|
186
185
|
describe("revokeCode", () => {
|
|
@@ -201,12 +200,12 @@ export function runTokenServiceContractTests(options) {
|
|
|
201
200
|
user,
|
|
202
201
|
});
|
|
203
202
|
const ok = await tokenService.revokeCode(code);
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
203
|
+
expect(ok).toBe(true);
|
|
204
|
+
expect(await tokenService.getToken(accessToken1)).toBe(undefined);
|
|
205
|
+
expect(await tokenService.getToken(accessToken2)).toBe(undefined);
|
|
207
206
|
});
|
|
208
207
|
it("returns false when no tokens were issued for the code", async () => {
|
|
209
|
-
|
|
208
|
+
expect(await tokenService.revokeCode("never-used")).toBe(false);
|
|
210
209
|
});
|
|
211
210
|
});
|
|
212
211
|
if (expectReuseDetection) {
|
|
@@ -240,48 +239,44 @@ export function runTokenServiceContractTests(options) {
|
|
|
240
239
|
it("keeps a rotated-out refresh token findable, with its family", async () => {
|
|
241
240
|
const token = await saveFamilyMember(FAMILY);
|
|
242
241
|
await tokenService.revoke(token.refreshToken, "refresh_token");
|
|
243
|
-
|
|
242
|
+
expect(await tokenService.getRefreshToken(token.refreshToken), "a rotated-out token must no longer refresh").toBe(undefined);
|
|
244
243
|
const revoked = await tokenService.getRevokedRefreshToken(token.refreshToken);
|
|
245
244
|
assert(revoked !== undefined, "a revoked refresh token must stay findable — deleting the row " +
|
|
246
245
|
"is what turns a replay into an ordinary unknown token");
|
|
247
|
-
|
|
246
|
+
expect(revoked.familyId).toBe(FAMILY);
|
|
248
247
|
});
|
|
249
248
|
it("does not report a live refresh token as revoked", async () => {
|
|
250
249
|
const token = await saveFamilyMember(FAMILY);
|
|
251
|
-
|
|
252
|
-
"refresh into a detected replay");
|
|
250
|
+
expect(await tokenService.getRevokedRefreshToken(token.refreshToken), "reporting a live token as revoked turns every legitimate " +
|
|
251
|
+
"refresh into a detected replay").toBe(undefined);
|
|
253
252
|
});
|
|
254
253
|
it("returns undefined for a refresh token that was never issued", async () => {
|
|
255
|
-
|
|
254
|
+
expect(await tokenService.getRevokedRefreshToken("never-issued")).toBe(undefined);
|
|
256
255
|
});
|
|
257
256
|
it("revokes every live member of a replayed token's family", async () => {
|
|
258
257
|
const first = await saveFamilyMember(FAMILY);
|
|
259
258
|
const second = await saveFamilyMember(FAMILY);
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
"keeps the thief's session alive for their remaining lifetime");
|
|
259
|
+
expect(await tokenService.revokeFamily(FAMILY)).toBe(true);
|
|
260
|
+
expect(await tokenService.getRefreshToken(first.refreshToken)).toBe(undefined);
|
|
261
|
+
expect(await tokenService.getRefreshToken(second.refreshToken)).toBe(undefined);
|
|
262
|
+
expect(await tokenService.getToken(second.accessToken), "the family's access tokens die with it — leaving them live " +
|
|
263
|
+
"keeps the thief's session alive for their remaining lifetime").toBe(undefined);
|
|
265
264
|
});
|
|
266
265
|
it("leaves other families untouched", async () => {
|
|
267
266
|
const mine = await saveFamilyMember(FAMILY);
|
|
268
267
|
const theirs = await saveFamilyMember(OTHER_FAMILY);
|
|
269
268
|
await tokenService.revokeFamily(FAMILY);
|
|
270
|
-
|
|
271
|
-
assert(await tokenService.getRefreshToken(theirs.refreshToken) !==
|
|
269
|
+
expect(await tokenService.getRefreshToken(mine.refreshToken)).toBe(undefined);
|
|
270
|
+
assert((await tokenService.getRefreshToken(theirs.refreshToken)) !==
|
|
272
271
|
undefined, "one compromised family must not sign every other session out");
|
|
273
272
|
});
|
|
274
273
|
it("returns false when the family has no live tokens", async () => {
|
|
275
|
-
|
|
274
|
+
expect(await tokenService.revokeFamily("never-issued")).toBe(false);
|
|
276
275
|
});
|
|
277
276
|
});
|
|
278
277
|
}
|
|
279
278
|
else {
|
|
280
|
-
it({
|
|
281
|
-
name: "refresh-token reuse detection is not implemented — a replayed rotated-out token cannot be detected (refreshTokenReuseDetection: false)",
|
|
282
|
-
ignore: true,
|
|
283
|
-
fn: () => { },
|
|
284
|
-
});
|
|
279
|
+
it.skip("refresh-token reuse detection is not implemented — a replayed rotated-out token cannot be detected (refreshTokenReuseDetection: false)", () => { });
|
|
285
280
|
}
|
|
286
281
|
});
|
|
287
282
|
}
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
*
|
|
29
29
|
* @module
|
|
30
30
|
*/
|
|
31
|
-
import type { UserServiceInterface } from "../../server/services/user.
|
|
32
|
-
import type { MemoryUserShape } from "../services.
|
|
31
|
+
import type { UserServiceInterface } from "../../server/services/user.ts";
|
|
32
|
+
import type { MemoryUserShape } from "../services.ts";
|
|
33
33
|
/** Options for {@link runUserServiceContractTests}. */
|
|
34
34
|
export interface UserServiceContractOptions<U extends MemoryUserShape> {
|
|
35
35
|
/**
|
|
@@ -28,8 +28,7 @@
|
|
|
28
28
|
*
|
|
29
29
|
* @module
|
|
30
30
|
*/
|
|
31
|
-
import {
|
|
32
|
-
import { beforeEach, describe, it } from "../../deps/jsr.io/@std/testing/1.0.20/bdd.js";
|
|
31
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
33
32
|
const defaultMakeUser = (seq) => ({ id: `u${seq}`, username: `user${seq}` });
|
|
34
33
|
/**
|
|
35
34
|
* Runs the {@link UserServiceInterface} contract suite. Call from your
|
|
@@ -37,7 +36,7 @@ const defaultMakeUser = (seq) => ({ id: `u${seq}`, username: `user${seq}` });
|
|
|
37
36
|
* runner picks up.
|
|
38
37
|
*/
|
|
39
38
|
export function runUserServiceContractTests(options) {
|
|
40
|
-
const makeUser = options.makeUser ??
|
|
39
|
+
const makeUser = options.makeUser ?? defaultMakeUser;
|
|
41
40
|
describe(options.describeName ?? "UserServiceInterface contract", () => {
|
|
42
41
|
let service;
|
|
43
42
|
beforeEach(async () => {
|
|
@@ -45,30 +44,30 @@ export function runUserServiceContractTests(options) {
|
|
|
45
44
|
});
|
|
46
45
|
describe("get", () => {
|
|
47
46
|
it("returns undefined for an unknown id", async () => {
|
|
48
|
-
|
|
47
|
+
expect(await service.get("does-not-exist")).toBe(undefined);
|
|
49
48
|
});
|
|
50
49
|
it("returns the user for a known id", async () => {
|
|
51
50
|
const user = makeUser(1);
|
|
52
51
|
await options.addUser(service, user, "pw");
|
|
53
52
|
const fetched = await service.get(user.id);
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
expect(fetched?.id).toStrictEqual(user.id);
|
|
54
|
+
expect(fetched?.username).toStrictEqual(user.username);
|
|
56
55
|
});
|
|
57
56
|
});
|
|
58
57
|
describe("getAuthenticated", () => {
|
|
59
58
|
it("returns undefined for an unknown username", async () => {
|
|
60
|
-
|
|
59
|
+
expect(await service.getAuthenticated("nobody", "pw")).toBe(undefined);
|
|
61
60
|
});
|
|
62
61
|
it("returns undefined for a wrong password", async () => {
|
|
63
62
|
const user = makeUser(2);
|
|
64
63
|
await options.addUser(service, user, "correct");
|
|
65
|
-
|
|
64
|
+
expect(await service.getAuthenticated(user.username, "wrong")).toBe(undefined);
|
|
66
65
|
});
|
|
67
66
|
it("returns the user when username + password match", async () => {
|
|
68
67
|
const user = makeUser(3);
|
|
69
68
|
await options.addUser(service, user, "secret");
|
|
70
69
|
const auth = await service.getAuthenticated(user.username, "secret");
|
|
71
|
-
|
|
70
|
+
expect(auth?.id).toStrictEqual(user.id);
|
|
72
71
|
});
|
|
73
72
|
});
|
|
74
73
|
});
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* - **Testing surface for the OAuth2 protocol.** The recommended pattern
|
|
7
7
|
* for testing apps that use the resource server is to expose your
|
|
8
8
|
* `IntrospectionTokenReader` instance from your app's OAuth2 wiring module
|
|
9
|
-
* and stub `tokenReader.getToken` directly with
|
|
10
|
-
* `
|
|
9
|
+
* and stub `tokenReader.getToken` directly with Vitest's
|
|
10
|
+
* `vi.spyOn` —
|
|
11
11
|
* one method on one object, no `fetch` indirection, no wire format to
|
|
12
12
|
* fake. For tests that need the OAuth2 protocol end-to-end (BFF flows,
|
|
13
13
|
* SPA integration), build a real in-process authorization server with
|
|
@@ -40,7 +40,6 @@
|
|
|
40
40
|
*
|
|
41
41
|
* @module
|
|
42
42
|
*/
|
|
43
|
-
|
|
44
|
-
export {
|
|
45
|
-
export {
|
|
46
|
-
export { createFakeTenant, type FakeTenant, type FakeTenantClient, type FakeTenantGrant, type FakeTenantLinkedAccount, type FakeTenantMachinePermission, type FakeTenantMembership, type FakeTenantOptions, type FakeTenantOrganization, type FakeTenantOrganizationRole, type FakeTenantSignIn, type FakeTenantSubject, type FakeTenantTokenRequest, type FakeTenantUser, } from "./tenant.js";
|
|
43
|
+
export { MemoryAuthorizationCodeService, type MemoryAuthorizationCodeServiceOptions, MemoryClientService, MemoryDeviceAuthorizationService, type MemoryDeviceAuthorizationServiceOptions, MemoryTokenService, type MemoryTokenServiceOptions, MemoryUserService, type MemoryUserServiceOptions, type MemoryUserShape, } from "./services.ts";
|
|
44
|
+
export { createMemoryAuthorizationServer, type CreateMemoryAuthorizationServerOptions, type MemoryAuthorizationServerClientSeed, type MemoryAuthorizationServerGrants, type MemoryAuthorizationServerHarness, type MemoryAuthorizationServerUserSeed, } from "./server.ts";
|
|
45
|
+
export { createFakeTenant, type FakeTenant, type FakeTenantClient, type FakeTenantGrant, type FakeTenantLinkedAccount, type FakeTenantMachinePermission, type FakeTenantMembership, type FakeTenantOptions, type FakeTenantOrganization, type FakeTenantOrganizationRole, type FakeTenantSignIn, type FakeTenantSubject, type FakeTenantTokenRequest, type FakeTenantUser, } from "./tenant.ts";
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* - **Testing surface for the OAuth2 protocol.** The recommended pattern
|
|
7
7
|
* for testing apps that use the resource server is to expose your
|
|
8
8
|
* `IntrospectionTokenReader` instance from your app's OAuth2 wiring module
|
|
9
|
-
* and stub `tokenReader.getToken` directly with
|
|
10
|
-
* `
|
|
9
|
+
* and stub `tokenReader.getToken` directly with Vitest's
|
|
10
|
+
* `vi.spyOn` —
|
|
11
11
|
* one method on one object, no `fetch` indirection, no wire format to
|
|
12
12
|
* fake. For tests that need the OAuth2 protocol end-to-end (BFF flows,
|
|
13
13
|
* SPA integration), build a real in-process authorization server with
|
|
@@ -40,7 +40,6 @@
|
|
|
40
40
|
*
|
|
41
41
|
* @module
|
|
42
42
|
*/
|
|
43
|
-
import "../_dnt.polyfills.js";
|
|
44
43
|
export { MemoryAuthorizationCodeService, MemoryClientService, MemoryDeviceAuthorizationService, MemoryTokenService, MemoryUserService, } from "./services.js";
|
|
45
44
|
export { createMemoryAuthorizationServer, } from "./server.js";
|
|
46
45
|
export { createFakeTenant, } from "./tenant.js";
|
|
@@ -23,10 +23,11 @@
|
|
|
23
23
|
*
|
|
24
24
|
* @example
|
|
25
25
|
* ```ts
|
|
26
|
+
* import { it } from "vitest";
|
|
26
27
|
* import { DirectClient } from "@udibo/oauth2/client";
|
|
27
28
|
* import { createMemoryAuthorizationServer } from "@udibo/oauth2/testing";
|
|
28
29
|
*
|
|
29
|
-
*
|
|
30
|
+
* it("client credentials grant", async () => {
|
|
30
31
|
* const oauth = await createMemoryAuthorizationServer({
|
|
31
32
|
* issuer: "http://localhost",
|
|
32
33
|
* clients: [{
|
|
@@ -47,11 +48,11 @@
|
|
|
47
48
|
*
|
|
48
49
|
* @module
|
|
49
50
|
*/
|
|
50
|
-
import type { ClientInterface } from "../models/client.
|
|
51
|
-
import type { AbstractScope, BasicScope, ScopeConstructor } from "../models/scope.
|
|
52
|
-
import { AuthorizationServer } from "../server/authorization-server.
|
|
53
|
-
import type { AuthenticateUserFn, HandleConsentFn } from "../server/authorization-server.
|
|
54
|
-
import { MemoryAuthorizationCodeService, MemoryClientService, MemoryDeviceAuthorizationService, MemoryTokenService, MemoryUserService, type MemoryUserShape } from "./services.
|
|
51
|
+
import type { ClientInterface } from "../models/client.ts";
|
|
52
|
+
import type { AbstractScope, BasicScope, ScopeConstructor } from "../models/scope.ts";
|
|
53
|
+
import { AuthorizationServer } from "../server/authorization-server.ts";
|
|
54
|
+
import type { AuthenticateUserFn, HandleConsentFn } from "../server/authorization-server.ts";
|
|
55
|
+
import { MemoryAuthorizationCodeService, MemoryClientService, MemoryDeviceAuthorizationService, MemoryTokenService, MemoryUserService, type MemoryUserShape } from "./services.ts";
|
|
55
56
|
/** Which OAuth2 grants the memory authorization server enables. */
|
|
56
57
|
export interface MemoryAuthorizationServerGrants {
|
|
57
58
|
/**
|
|
@@ -23,10 +23,11 @@
|
|
|
23
23
|
*
|
|
24
24
|
* @example
|
|
25
25
|
* ```ts
|
|
26
|
+
* import { it } from "vitest";
|
|
26
27
|
* import { DirectClient } from "@udibo/oauth2/client";
|
|
27
28
|
* import { createMemoryAuthorizationServer } from "@udibo/oauth2/testing";
|
|
28
29
|
*
|
|
29
|
-
*
|
|
30
|
+
* it("client credentials grant", async () => {
|
|
30
31
|
* const oauth = await createMemoryAuthorizationServer({
|
|
31
32
|
* issuer: "http://localhost",
|
|
32
33
|
* clients: [{
|