@udibo/oauth2 0.1.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/LICENSE +20 -0
- package/README.md +174 -0
- package/SECURITY.md +77 -0
- package/esm/_dnt.polyfills.d.ts +17 -0
- package/esm/_dnt.polyfills.js +15 -0
- package/esm/adapters/hono/_common.d.ts +66 -0
- package/esm/adapters/hono/_common.js +108 -0
- package/esm/adapters/hono/authorization-server.d.ts +211 -0
- package/esm/adapters/hono/authorization-server.js +214 -0
- package/esm/adapters/hono/bff/auth-request-store.d.ts +164 -0
- package/esm/adapters/hono/bff/auth-request-store.js +154 -0
- package/esm/adapters/hono/bff/bff.d.ts +852 -0
- package/esm/adapters/hono/bff/bff.js +1194 -0
- package/esm/adapters/hono/bff/cookie-prefix.d.ts +72 -0
- package/esm/adapters/hono/bff/cookie-prefix.js +85 -0
- package/esm/adapters/hono/bff/mod.d.ts +19 -0
- package/esm/adapters/hono/bff/mod.js +19 -0
- package/esm/adapters/hono/bff/proxy.d.ts +108 -0
- package/esm/adapters/hono/bff/proxy.js +314 -0
- package/esm/adapters/hono/bff/session-store.d.ts +250 -0
- package/esm/adapters/hono/bff/session-store.js +216 -0
- package/esm/adapters/hono/bff/testing.d.ts +165 -0
- package/esm/adapters/hono/bff/testing.js +254 -0
- package/esm/adapters/hono/identity.d.ts +117 -0
- package/esm/adapters/hono/identity.js +215 -0
- package/esm/adapters/hono/log.d.ts +49 -0
- package/esm/adapters/hono/log.js +66 -0
- package/esm/adapters/hono/resource-server.d.ts +101 -0
- package/esm/adapters/hono/resource-server.js +108 -0
- package/esm/client/_http.d.ts +91 -0
- package/esm/client/_http.js +303 -0
- package/esm/client/base.d.ts +184 -0
- package/esm/client/base.js +93 -0
- package/esm/client/bff-client.d.ts +235 -0
- package/esm/client/bff-client.js +280 -0
- package/esm/client/browser-storage.d.ts +152 -0
- package/esm/client/browser-storage.js +246 -0
- package/esm/client/check.d.ts +114 -0
- package/esm/client/check.js +97 -0
- package/esm/client/direct-client.d.ts +707 -0
- package/esm/client/direct-client.js +1237 -0
- package/esm/client/discovery-cache.d.ts +138 -0
- package/esm/client/discovery-cache.js +124 -0
- package/esm/client/events.d.ts +54 -0
- package/esm/client/events.js +37 -0
- package/esm/client/mod.d.ts +35 -0
- package/esm/client/mod.js +33 -0
- package/esm/client/storage.d.ts +127 -0
- package/esm/client/storage.js +81 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/almost_equals.d.ts +29 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/almost_equals.js +47 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/array_includes.d.ts +28 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/array_includes.js +65 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/assert.d.ts +16 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/assert.js +23 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/assertion_error.d.ts +25 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/assertion_error.js +30 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/equal.d.ts +24 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/equal.js +193 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/equals.d.ts +36 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/equals.js +61 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/exists.d.ts +17 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/exists.js +27 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/fail.d.ts +14 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/fail.js +20 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/false.d.ts +18 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/false.js +23 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/greater.d.ts +19 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/greater.js +29 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/greater_or_equal.d.ts +19 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/greater_or_equal.js +29 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/instance_of.d.ts +22 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/instance_of.js +52 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/is_error.d.ts +24 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/is_error.js +53 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/less.d.ts +18 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/less.js +28 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/less_or_equal.d.ts +19 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/less_or_equal.js +29 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/match.d.ts +17 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/match.js +26 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/mod.d.ts +43 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/mod.js +45 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_equals.d.ts +26 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_equals.js +39 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_instance_of.d.ts +19 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_instance_of.js +29 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_match.d.ts +17 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_match.js +26 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_strict_equals.d.ts +22 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_strict_equals.js +32 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/object_match.d.ts +28 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/object_match.js +177 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/rejects.d.ts +41 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/rejects.js +53 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/strict_equals.d.ts +23 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/strict_equals.js +58 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/string_includes.d.ts +17 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/string_includes.js +26 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/throws.d.ts +44 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/throws.js +44 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/unimplemented.d.ts +14 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/unimplemented.js +20 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/unreachable.d.ts +14 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/unreachable.js +20 -0
- package/esm/deps/jsr.io/@std/async/1.5.0/delay.d.ts +44 -0
- package/esm/deps/jsr.io/@std/async/1.5.0/delay.js +84 -0
- package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.d.ts +39 -0
- package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.js +61 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common16.d.ts +22 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common16.js +51 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common32.d.ts +34 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common32.js +192 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common64.d.ts +34 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common64.js +113 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common_detach.d.ts +3 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_common_detach.js +13 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_types.d.ts +8 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_types.js +2 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_validate_binary_like.d.ts +1 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/_validate_binary_like.js +26 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/ascii85.d.ts +60 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/ascii85.js +152 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base32.d.ts +39 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base32.js +87 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base58.d.ts +39 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base58.js +131 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base64.d.ts +39 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base64.js +82 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base64url.d.ts +39 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/base64url.js +72 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/hex.d.ts +38 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/hex.js +87 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/mod.d.ts +97 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/mod.js +99 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/varint.d.ts +119 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.11/varint.js +209 -0
- package/esm/deps/jsr.io/@std/http/1.1.3/status.d.ts +343 -0
- package/esm/deps/jsr.io/@std/http/1.1.3/status.js +343 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/assertion_state.d.ts +159 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/assertion_state.js +223 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/build_message.d.ts +79 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/build_message.js +116 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/diff.d.ts +139 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/diff.js +277 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/diff_str.d.ts +98 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/diff_str.js +181 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/format.d.ts +29 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/format.js +68 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/styles.d.ts +158 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/styles.js +206 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/types.d.ts +24 -0
- package/esm/deps/jsr.io/@std/internal/1.0.14/types.js +3 -0
- package/esm/deps/jsr.io/@std/testing/1.0.20/_test_suite.d.ts +91 -0
- package/esm/deps/jsr.io/@std/testing/1.0.20/_test_suite.js +347 -0
- package/esm/deps/jsr.io/@std/testing/1.0.20/bdd.d.ts +382 -0
- package/esm/deps/jsr.io/@std/testing/1.0.20/bdd.js +1110 -0
- package/esm/deps/jsr.io/@udibo/http-error/0.11.1/mod.d.ts +363 -0
- package/esm/deps/jsr.io/@udibo/http-error/0.11.1/mod.js +616 -0
- package/esm/errors.d.ts +203 -0
- package/esm/errors.js +287 -0
- package/esm/identity/captcha.d.ts +147 -0
- package/esm/identity/captcha.js +64 -0
- package/esm/identity/delivery.d.ts +96 -0
- package/esm/identity/delivery.js +41 -0
- package/esm/identity/errors.d.ts +39 -0
- package/esm/identity/errors.js +46 -0
- package/esm/identity/events.d.ts +242 -0
- package/esm/identity/events.js +39 -0
- package/esm/identity/external/_shared.d.ts +86 -0
- package/esm/identity/external/_shared.js +107 -0
- package/esm/identity/external/_token-exchange.d.ts +61 -0
- package/esm/identity/external/_token-exchange.js +179 -0
- package/esm/identity/external/apple-client-secret.d.ts +82 -0
- package/esm/identity/external/apple-client-secret.js +133 -0
- package/esm/identity/external/apple.d.ts +64 -0
- package/esm/identity/external/apple.js +248 -0
- package/esm/identity/external/discord.d.ts +38 -0
- package/esm/identity/external/discord.js +62 -0
- package/esm/identity/external/errors.d.ts +48 -0
- package/esm/identity/external/errors.js +36 -0
- package/esm/identity/external/flow.d.ts +107 -0
- package/esm/identity/external/flow.js +158 -0
- package/esm/identity/external/github.d.ts +42 -0
- package/esm/identity/external/github.js +164 -0
- package/esm/identity/external/google.d.ts +52 -0
- package/esm/identity/external/google.js +38 -0
- package/esm/identity/external/mod.d.ts +63 -0
- package/esm/identity/external/mod.js +61 -0
- package/esm/identity/external/oauth2.d.ts +110 -0
- package/esm/identity/external/oauth2.js +158 -0
- package/esm/identity/external/oidc.d.ts +81 -0
- package/esm/identity/external/oidc.js +250 -0
- package/esm/identity/external/provider.d.ts +132 -0
- package/esm/identity/external/provider.js +12 -0
- package/esm/identity/hibp.d.ts +67 -0
- package/esm/identity/hibp.js +87 -0
- package/esm/identity/identifier.d.ts +44 -0
- package/esm/identity/identifier.js +47 -0
- package/esm/identity/lockout.d.ts +155 -0
- package/esm/identity/lockout.js +117 -0
- package/esm/identity/mfa/mod.d.ts +42 -0
- package/esm/identity/mfa/mod.js +42 -0
- package/esm/identity/mfa/recovery-codes.d.ts +96 -0
- package/esm/identity/mfa/recovery-codes.js +80 -0
- package/esm/identity/mfa/service.d.ts +338 -0
- package/esm/identity/mfa/service.js +351 -0
- package/esm/identity/mfa/totp.d.ts +186 -0
- package/esm/identity/mfa/totp.js +194 -0
- package/esm/identity/migration.d.ts +155 -0
- package/esm/identity/migration.js +243 -0
- package/esm/identity/mod.d.ts +65 -0
- package/esm/identity/mod.js +64 -0
- package/esm/identity/otp.d.ts +255 -0
- package/esm/identity/otp.js +245 -0
- package/esm/identity/password-policy.d.ts +45 -0
- package/esm/identity/password-policy.js +60 -0
- package/esm/identity/password.d.ts +171 -0
- package/esm/identity/password.js +160 -0
- package/esm/identity/rate-limit.d.ts +192 -0
- package/esm/identity/rate-limit.js +168 -0
- package/esm/identity/service.d.ts +579 -0
- package/esm/identity/service.js +835 -0
- package/esm/identity/session.d.ts +122 -0
- package/esm/identity/session.js +48 -0
- package/esm/identity/token-flow.d.ts +214 -0
- package/esm/identity/token-flow.js +173 -0
- package/esm/models/authentication.d.ts +24 -0
- package/esm/models/authentication.js +1 -0
- package/esm/models/authorization-code.d.ts +63 -0
- package/esm/models/authorization-code.js +1 -0
- package/esm/models/authorization.d.ts +165 -0
- package/esm/models/authorization.js +160 -0
- package/esm/models/client.d.ts +78 -0
- package/esm/models/client.js +1 -0
- package/esm/models/device-authorization.d.ts +30 -0
- package/esm/models/device-authorization.js +1 -0
- package/esm/models/responses.d.ts +93 -0
- package/esm/models/responses.js +1 -0
- package/esm/models/scope.d.ts +81 -0
- package/esm/models/scope.js +125 -0
- package/esm/models/token.d.ts +135 -0
- package/esm/models/token.js +1 -0
- package/esm/package.json +3 -0
- package/esm/react/callback.d.ts +52 -0
- package/esm/react/callback.js +71 -0
- package/esm/react/components/class-names.d.ts +91 -0
- package/esm/react/components/class-names.js +118 -0
- package/esm/react/components/internal.d.ts +62 -0
- package/esm/react/components/internal.js +102 -0
- package/esm/react/components/mfa-challenge-form.d.ts +66 -0
- package/esm/react/components/mfa-challenge-form.js +46 -0
- package/esm/react/components/mfa-enrollment-form.d.ts +83 -0
- package/esm/react/components/mfa-enrollment-form.js +41 -0
- package/esm/react/components/mod.d.ts +103 -0
- package/esm/react/components/mod.js +93 -0
- package/esm/react/components/request-password-reset-form.d.ts +61 -0
- package/esm/react/components/request-password-reset-form.js +41 -0
- package/esm/react/components/reset-password-form.d.ts +66 -0
- package/esm/react/components/reset-password-form.js +56 -0
- package/esm/react/components/sign-in-form.d.ts +74 -0
- package/esm/react/components/sign-in-form.js +43 -0
- package/esm/react/components/sign-up-form.d.ts +85 -0
- package/esm/react/components/sign-up-form.js +57 -0
- package/esm/react/components/types.d.ts +208 -0
- package/esm/react/components/types.js +14 -0
- package/esm/react/components/use-auth-form.d.ts +118 -0
- package/esm/react/components/use-auth-form.js +172 -0
- package/esm/react/components/user-menu.d.ts +79 -0
- package/esm/react/components/user-menu.js +73 -0
- package/esm/react/context.d.ts +51 -0
- package/esm/react/context.js +16 -0
- package/esm/react/mod.d.ts +26 -0
- package/esm/react/mod.js +26 -0
- package/esm/react/provider.d.ts +40 -0
- package/esm/react/provider.js +189 -0
- package/esm/react/require-auth.d.ts +31 -0
- package/esm/react/require-auth.js +37 -0
- package/esm/react/testing.d.ts +322 -0
- package/esm/react/testing.js +461 -0
- package/esm/react/use-authorization.d.ts +31 -0
- package/esm/react/use-authorization.js +36 -0
- package/esm/react/use-oauth2.d.ts +112 -0
- package/esm/react/use-oauth2.js +127 -0
- package/esm/server/authorization-server.d.ts +736 -0
- package/esm/server/authorization-server.js +1304 -0
- package/esm/server/client-authentication.d.ts +28 -0
- package/esm/server/client-authentication.js +51 -0
- package/esm/server/grants/authorization-code.d.ts +179 -0
- package/esm/server/grants/authorization-code.js +232 -0
- package/esm/server/grants/client-credentials.d.ts +52 -0
- package/esm/server/grants/client-credentials.js +53 -0
- package/esm/server/grants/device-authorization.d.ts +103 -0
- package/esm/server/grants/device-authorization.js +156 -0
- package/esm/server/grants/grant.d.ts +165 -0
- package/esm/server/grants/grant.js +173 -0
- package/esm/server/grants/password.d.ts +80 -0
- package/esm/server/grants/password.js +92 -0
- package/esm/server/grants/refresh-token.d.ts +80 -0
- package/esm/server/grants/refresh-token.js +136 -0
- package/esm/server/introspection-token-reader.d.ts +153 -0
- package/esm/server/introspection-token-reader.js +164 -0
- package/esm/server/jwks-token-reader.d.ts +263 -0
- package/esm/server/jwks-token-reader.js +508 -0
- package/esm/server/mod.d.ts +23 -0
- package/esm/server/mod.js +15 -0
- package/esm/server/public-suffix/mod.d.ts +62 -0
- package/esm/server/public-suffix/mod.js +103 -0
- package/esm/server/public-suffix/rules.d.ts +23 -0
- package/esm/server/public-suffix/rules.js +23 -0
- package/esm/server/redirect-uri.d.ts +187 -0
- package/esm/server/redirect-uri.js +331 -0
- package/esm/server/resource-server.d.ts +286 -0
- package/esm/server/resource-server.js +365 -0
- package/esm/server/services/authorization-code.d.ts +84 -0
- package/esm/server/services/authorization-code.js +35 -0
- package/esm/server/services/client.d.ts +35 -0
- package/esm/server/services/client.js +1 -0
- package/esm/server/services/device-authorization.d.ts +134 -0
- package/esm/server/services/device-authorization.js +7 -0
- package/esm/server/services/token.d.ts +242 -0
- package/esm/server/services/token.js +78 -0
- package/esm/server/services/user.d.ts +29 -0
- package/esm/server/services/user.js +7 -0
- package/esm/server/signing-keys.d.ts +201 -0
- package/esm/server/signing-keys.js +225 -0
- package/esm/server/utils/hash.d.ts +6 -0
- package/esm/server/utils/hash.js +11 -0
- package/esm/testing/contract/authorization-code.d.ts +37 -0
- package/esm/testing/contract/authorization-code.js +93 -0
- package/esm/testing/contract/client.d.ts +85 -0
- package/esm/testing/contract/client.js +126 -0
- package/esm/testing/contract/device-authorization.d.ts +37 -0
- package/esm/testing/contract/device-authorization.js +193 -0
- package/esm/testing/contract/lockout-store.d.ts +47 -0
- package/esm/testing/contract/lockout-store.js +122 -0
- package/esm/testing/contract/mfa-store.d.ts +50 -0
- package/esm/testing/contract/mfa-store.js +226 -0
- package/esm/testing/contract/mod.d.ts +39 -0
- package/esm/testing/contract/mod.js +39 -0
- package/esm/testing/contract/otp-store.d.ts +48 -0
- package/esm/testing/contract/otp-store.js +197 -0
- package/esm/testing/contract/rate-limit-store.d.ts +52 -0
- package/esm/testing/contract/rate-limit-store.js +105 -0
- package/esm/testing/contract/token-flow-store.d.ts +54 -0
- package/esm/testing/contract/token-flow-store.js +179 -0
- package/esm/testing/contract/token-reader.d.ts +77 -0
- package/esm/testing/contract/token-reader.js +78 -0
- package/esm/testing/contract/token.d.ts +61 -0
- package/esm/testing/contract/token.js +287 -0
- package/esm/testing/contract/user.d.ts +63 -0
- package/esm/testing/contract/user.js +75 -0
- package/esm/testing/mod.d.ts +34 -0
- package/esm/testing/mod.js +34 -0
- package/esm/testing/server.d.ts +197 -0
- package/esm/testing/server.js +193 -0
- package/esm/testing/services.d.ts +373 -0
- package/esm/testing/services.js +703 -0
- package/esm/utils/_buffer.d.ts +10 -0
- package/esm/utils/_buffer.js +12 -0
- package/esm/utils/_timing-safe.d.ts +13 -0
- package/esm/utils/_timing-safe.js +22 -0
- package/esm/utils/authentication-context.d.ts +3 -0
- package/esm/utils/authentication-context.js +14 -0
- package/esm/utils/basic-auth.d.ts +50 -0
- package/esm/utils/basic-auth.js +106 -0
- package/esm/utils/crypto.d.ts +97 -0
- package/esm/utils/crypto.js +162 -0
- package/esm/utils/pkce.d.ts +151 -0
- package/esm/utils/pkce.js +179 -0
- package/esm/utils/text.d.ts +24 -0
- package/esm/utils/text.js +28 -0
- package/esm/utils/url.d.ts +66 -0
- package/esm/utils/url.js +90 -0
- package/package.json +92 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* `<OAuth2Provider>` — wraps the app, wires an {@link OAuth2ClientBase} into
|
|
4
|
+
* a React context, and re-renders subscribers when the client emits
|
|
5
|
+
* authentication state changes.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { useEffect, useMemo, useState } from "react";
|
|
10
|
+
import { toOAuth2Error } from "../errors.js";
|
|
11
|
+
import { OAuth2Context, } from "./context.js";
|
|
12
|
+
const DEFAULT_STATE = {
|
|
13
|
+
isAuthenticated: false,
|
|
14
|
+
isLoading: true,
|
|
15
|
+
user: null,
|
|
16
|
+
error: null,
|
|
17
|
+
sessionExpiresIn: null,
|
|
18
|
+
logoutUrl: null,
|
|
19
|
+
};
|
|
20
|
+
const RENEW_SKEW_SECONDS = 30;
|
|
21
|
+
const MIN_RENEW_MS = 5_000;
|
|
22
|
+
/**
|
|
23
|
+
* Fraction of the renew delay given up to jitter, applied one-sided so a renew
|
|
24
|
+
* never lands later than the un-jittered schedule.
|
|
25
|
+
*/
|
|
26
|
+
const RENEW_JITTER = 0.1;
|
|
27
|
+
const isBrowser = () => typeof window !== "undefined";
|
|
28
|
+
/**
|
|
29
|
+
* Delay before renewing a session that expires in `expiresIn` seconds.
|
|
30
|
+
*
|
|
31
|
+
* Floors at {@link MIN_RENEW_MS}, so `0` — which a `DirectClient` reports for
|
|
32
|
+
* an already-expired token a refresh token can still revive — schedules a
|
|
33
|
+
* near-immediate renew rather than nothing at all.
|
|
34
|
+
*/
|
|
35
|
+
function renewDelayMs(expiresIn) {
|
|
36
|
+
const base = Math.max(MIN_RENEW_MS, (expiresIn - RENEW_SKEW_SECONDS) * 1000);
|
|
37
|
+
return base * (1 - RENEW_JITTER * Math.random());
|
|
38
|
+
}
|
|
39
|
+
/** Seconds until `tokens` expires, or `null` when the server said nothing. */
|
|
40
|
+
function expiresInFrom(tokens) {
|
|
41
|
+
if (!tokens.accessTokenExpiresAt)
|
|
42
|
+
return null;
|
|
43
|
+
return Math.max(0, Math.round((tokens.accessTokenExpiresAt - Date.now()) / 1000));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Provider — install once near the root of your app. Children read the
|
|
47
|
+
* state via `useOAuth2()`.
|
|
48
|
+
*
|
|
49
|
+
* While authenticated it renews the session on a timer shortly before the
|
|
50
|
+
* access token expires, re-arming after each renew. Renewal is per tab and
|
|
51
|
+
* uncoordinated: a `DirectClient` given a refresh-token storage shared across
|
|
52
|
+
* tabs (e.g. `IndexedDBRefreshTokenStorage`) against a server that
|
|
53
|
+
* rotates refresh tokens can still have two tabs redeem the same token, which
|
|
54
|
+
* reuse detection may answer by ending the session everywhere.
|
|
55
|
+
*/
|
|
56
|
+
export function OAuth2Provider(props) {
|
|
57
|
+
const { client, children, initialState } = props;
|
|
58
|
+
const [state, setState] = useState(() => ({
|
|
59
|
+
...DEFAULT_STATE,
|
|
60
|
+
isLoading: initialState ? false : true,
|
|
61
|
+
...initialState,
|
|
62
|
+
}));
|
|
63
|
+
const [renewCount, setRenewCount] = useState(0);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
let cancelled = false;
|
|
66
|
+
const handle = (event) => {
|
|
67
|
+
setState((prev) => reduce(prev, event));
|
|
68
|
+
// The `authenticated` event carries tokens only, so refetch user claims.
|
|
69
|
+
if (event.type === "authenticated") {
|
|
70
|
+
client.getUser().then((user) => {
|
|
71
|
+
if (!cancelled)
|
|
72
|
+
setState((prev) => ({ ...prev, user }));
|
|
73
|
+
}, () => { });
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const unsubscribe = client.subscribe(handle);
|
|
77
|
+
return () => {
|
|
78
|
+
cancelled = true;
|
|
79
|
+
unsubscribe();
|
|
80
|
+
};
|
|
81
|
+
}, [client]);
|
|
82
|
+
// Re-sync when the server-resolved state changes (the only signal in BFF
|
|
83
|
+
// mode, whose callback completes server-side). Keyed on an identity
|
|
84
|
+
// signature, not the often-inline `initialState` reference, to avoid thrash.
|
|
85
|
+
const seededAuthenticated = initialState?.isAuthenticated ?? null;
|
|
86
|
+
const seededUserSub = initialState?.user?.sub ?? null;
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (!initialState)
|
|
89
|
+
return;
|
|
90
|
+
setState((prev) => {
|
|
91
|
+
const next = {
|
|
92
|
+
...DEFAULT_STATE,
|
|
93
|
+
isLoading: false,
|
|
94
|
+
...initialState,
|
|
95
|
+
};
|
|
96
|
+
if (prev.isAuthenticated === next.isAuthenticated &&
|
|
97
|
+
(prev.user?.sub ?? null) === (next.user?.sub ?? null) &&
|
|
98
|
+
prev.isLoading === next.isLoading) {
|
|
99
|
+
return prev;
|
|
100
|
+
}
|
|
101
|
+
return next;
|
|
102
|
+
});
|
|
103
|
+
}, [client, seededAuthenticated, seededUserSub]);
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (initialState)
|
|
106
|
+
return;
|
|
107
|
+
if (!isBrowser())
|
|
108
|
+
return;
|
|
109
|
+
let cancelled = false;
|
|
110
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
111
|
+
client.getSession().then((session) => {
|
|
112
|
+
if (!cancelled)
|
|
113
|
+
setState({ ...session, isLoading: false, error: null });
|
|
114
|
+
}, (error) => {
|
|
115
|
+
if (cancelled)
|
|
116
|
+
return;
|
|
117
|
+
setState({
|
|
118
|
+
...DEFAULT_STATE,
|
|
119
|
+
isLoading: false,
|
|
120
|
+
error: toOAuth2Error(error),
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
return () => {
|
|
124
|
+
cancelled = true;
|
|
125
|
+
};
|
|
126
|
+
}, [client, initialState]);
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
if (!isBrowser())
|
|
129
|
+
return;
|
|
130
|
+
if (!state.isAuthenticated)
|
|
131
|
+
return;
|
|
132
|
+
const expiresIn = state.sessionExpiresIn;
|
|
133
|
+
if (expiresIn == null || !Number.isFinite(expiresIn) || expiresIn < 0) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
let cancelled = false;
|
|
137
|
+
const delayMs = renewDelayMs(expiresIn);
|
|
138
|
+
const timer = setTimeout(() => {
|
|
139
|
+
client.renewSession().then((session) => {
|
|
140
|
+
if (cancelled)
|
|
141
|
+
return;
|
|
142
|
+
setState((prev) => ({ ...prev, ...session }));
|
|
143
|
+
setRenewCount((count) => count + 1);
|
|
144
|
+
}, () => {
|
|
145
|
+
if (!cancelled)
|
|
146
|
+
setRenewCount((count) => count + 1);
|
|
147
|
+
});
|
|
148
|
+
}, delayMs);
|
|
149
|
+
return () => {
|
|
150
|
+
cancelled = true;
|
|
151
|
+
clearTimeout(timer);
|
|
152
|
+
};
|
|
153
|
+
}, [client, state.isAuthenticated, state.sessionExpiresIn, renewCount]);
|
|
154
|
+
const value = useMemo(() => ({
|
|
155
|
+
client,
|
|
156
|
+
...state,
|
|
157
|
+
}), [client, state]);
|
|
158
|
+
return (_jsx(OAuth2Context.Provider, { value: value, children: children }));
|
|
159
|
+
}
|
|
160
|
+
function reduce(prev, event) {
|
|
161
|
+
switch (event.type) {
|
|
162
|
+
case "authenticated":
|
|
163
|
+
return {
|
|
164
|
+
...prev,
|
|
165
|
+
isAuthenticated: true,
|
|
166
|
+
isLoading: false,
|
|
167
|
+
error: null,
|
|
168
|
+
sessionExpiresIn: expiresInFrom(event.tokens),
|
|
169
|
+
};
|
|
170
|
+
case "logged_out":
|
|
171
|
+
return {
|
|
172
|
+
isAuthenticated: false,
|
|
173
|
+
isLoading: false,
|
|
174
|
+
user: null,
|
|
175
|
+
error: null,
|
|
176
|
+
sessionExpiresIn: null,
|
|
177
|
+
logoutUrl: null,
|
|
178
|
+
};
|
|
179
|
+
case "token_refreshed":
|
|
180
|
+
return {
|
|
181
|
+
...prev,
|
|
182
|
+
isLoading: false,
|
|
183
|
+
error: null,
|
|
184
|
+
sessionExpiresIn: expiresInFrom(event.tokens),
|
|
185
|
+
};
|
|
186
|
+
case "error":
|
|
187
|
+
return { ...prev, error: toOAuth2Error(event.error) };
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<RequireAuth>` — gate a subtree behind authentication. If the user is
|
|
3
|
+
* not authenticated, calls `login({ returnTo })` (the {@link useOAuth2}
|
|
4
|
+
* action, which navigates the browser to the login / authorize URL) with
|
|
5
|
+
* `returnTo` set to the current path, and renders a configurable
|
|
6
|
+
* `fallback` while the redirect is in flight.
|
|
7
|
+
*
|
|
8
|
+
* Avoids the `withAuthenticationRequired` re-mount footgun (the HOC
|
|
9
|
+
* isn't created in render; this component just gates its children).
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { type ReactNode } from "react";
|
|
14
|
+
/** Props for {@link RequireAuth}. */
|
|
15
|
+
export interface RequireAuthProps {
|
|
16
|
+
/** Children rendered when authenticated. */
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
/**
|
|
19
|
+
* What to render while the redirect is being kicked off / the
|
|
20
|
+
* initial probe is in flight. Defaults to `null` (nothing).
|
|
21
|
+
*/
|
|
22
|
+
fallback?: ReactNode;
|
|
23
|
+
/** Optional explicit `returnTo`. Defaults to `window.location.pathname + window.location.search`. */
|
|
24
|
+
returnTo?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Render `children` only when authenticated. Otherwise call
|
|
28
|
+
* `login({ returnTo })` once and render `fallback` while the redirect
|
|
29
|
+
* is in flight.
|
|
30
|
+
*/
|
|
31
|
+
export declare function RequireAuth(props: RequireAuthProps): ReactNode;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// deno-lint-ignore-file no-window -- browser-only; `window` used only after isBrowser() guards
|
|
2
|
+
/**
|
|
3
|
+
* `<RequireAuth>` — gate a subtree behind authentication. If the user is
|
|
4
|
+
* not authenticated, calls `login({ returnTo })` (the {@link useOAuth2}
|
|
5
|
+
* action, which navigates the browser to the login / authorize URL) with
|
|
6
|
+
* `returnTo` set to the current path, and renders a configurable
|
|
7
|
+
* `fallback` while the redirect is in flight.
|
|
8
|
+
*
|
|
9
|
+
* Avoids the `withAuthenticationRequired` re-mount footgun (the HOC
|
|
10
|
+
* isn't created in render; this component just gates its children).
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import { useEffect } from "react";
|
|
15
|
+
import { useOAuth2 } from "./use-oauth2.js";
|
|
16
|
+
const isBrowser = () => typeof window !== "undefined";
|
|
17
|
+
/**
|
|
18
|
+
* Render `children` only when authenticated. Otherwise call
|
|
19
|
+
* `login({ returnTo })` once and render `fallback` while the redirect
|
|
20
|
+
* is in flight.
|
|
21
|
+
*/
|
|
22
|
+
export function RequireAuth(props) {
|
|
23
|
+
const { children, fallback = null, returnTo } = props;
|
|
24
|
+
const { isAuthenticated, isLoading, login } = useOAuth2();
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (isLoading || isAuthenticated)
|
|
27
|
+
return;
|
|
28
|
+
if (!isBrowser())
|
|
29
|
+
return;
|
|
30
|
+
const target = returnTo ??
|
|
31
|
+
`${window.location.pathname}${window.location.search}`;
|
|
32
|
+
login({ returnTo: target }).catch(() => { });
|
|
33
|
+
}, [isLoading, isAuthenticated, login, returnTo]);
|
|
34
|
+
if (isLoading || !isAuthenticated)
|
|
35
|
+
return fallback;
|
|
36
|
+
return children;
|
|
37
|
+
}
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Testing helpers for the `@udibo/oauth2/react` adapter.
|
|
3
|
+
*
|
|
4
|
+
* Three mock clients and a provider:
|
|
5
|
+
*
|
|
6
|
+
* - {@link createMockOAuth2Client} — an `OAuth2ClientBase` with no HTTP,
|
|
7
|
+
* PKCE, or storage behind it. Use it for a component written against the
|
|
8
|
+
* shared surface.
|
|
9
|
+
* - {@link createMockBffClient} / {@link createMockDirectClient} — the same
|
|
10
|
+
* mock behavior on a real `BffClient` / `DirectClient` subclass, so
|
|
11
|
+
* `useBffClient()`, `useDirectClient()`, and `<OAuth2Callback>` accept them.
|
|
12
|
+
* Reach for these when the component under test narrows.
|
|
13
|
+
* - {@link MockOAuth2Provider} — drop-in replacement for `<OAuth2Provider>`
|
|
14
|
+
* that skips the initial session probe and accepts any of the three. Use it
|
|
15
|
+
* to unit-test components that consume `useOAuth2()` / `<RequireAuth>`
|
|
16
|
+
* without any network.
|
|
17
|
+
*
|
|
18
|
+
* Every mock emits on the same event bus the real clients use, so a subtree
|
|
19
|
+
* under a real `<OAuth2Provider>` re-renders just as it would in production.
|
|
20
|
+
* {@link MockOAuth2Provider} is not live: it seeds its context once from the
|
|
21
|
+
* client and keeps that snapshot, so a test that needs the state to *change*
|
|
22
|
+
* mid-render should mount a real `<OAuth2Provider>` around the mock client and
|
|
23
|
+
* call `signIn` / `signOut` on it. Configure `sessionExpiresIn` to exercise
|
|
24
|
+
* `<OAuth2Provider>`'s pre-expiry renew timer, and read
|
|
25
|
+
* {@link MockOAuth2Controls.renewCount} to assert it fired.
|
|
26
|
+
*
|
|
27
|
+
* **JSDOM recipes** for component tests in this adapter:
|
|
28
|
+
*
|
|
29
|
+
* - `window.location.assign` — the adapter's `login()` / `logout()` (via
|
|
30
|
+
* `useOAuth2()` and `<RequireAuth>`) navigate by calling
|
|
31
|
+
* `window.location.assign(url)`. JSDOM throws on unhandled navigation;
|
|
32
|
+
* stub it: `stub(window.location, "assign", () => {})` (or the
|
|
33
|
+
* equivalent for your runner).
|
|
34
|
+
* - `crypto.subtle` — required for PKCE in a real `DirectClient`. The mocks
|
|
35
|
+
* don't use it, so JSDOM tests of components-with-mock-client are
|
|
36
|
+
* safe out of the box.
|
|
37
|
+
* - `sessionStorage` — needed by
|
|
38
|
+
* `SessionStorageAuthRequestStorage`. JSDOM ships one; the mocks
|
|
39
|
+
* never touch it.
|
|
40
|
+
* - `history.replaceState` — `<OAuth2Callback>`'s default `onNavigate`
|
|
41
|
+
* uses it. JSDOM ships it.
|
|
42
|
+
*
|
|
43
|
+
* @module
|
|
44
|
+
*/
|
|
45
|
+
import "../_dnt.polyfills.js";
|
|
46
|
+
import { type ReactNode } from "react";
|
|
47
|
+
import { type AuthorizationRedirect, type BaseLoginOptions, BffClient, DirectClient, type LoginRedirect, type LogoutRedirect, OAuth2ClientBase, type OAuth2Error, type SessionState, type UserInfoClaims } from "../client/mod.js";
|
|
48
|
+
import { type OAuth2State } from "./context.js";
|
|
49
|
+
/** Where a mock client starts. */
|
|
50
|
+
export interface MockOAuth2ClientState {
|
|
51
|
+
/** Whether the mock starts signed in. Defaults to `user !== null`. */
|
|
52
|
+
isAuthenticated?: boolean;
|
|
53
|
+
/** The cached user claims the mock starts with. Defaults to `null`. */
|
|
54
|
+
user?: UserInfoClaims | null;
|
|
55
|
+
/** The `logoutUrl` the mock reports while signed in. Defaults to `/auth/logout`. */
|
|
56
|
+
logoutUrl?: string | null;
|
|
57
|
+
/**
|
|
58
|
+
* Seconds the mock reports until expiry. Defaults to `null` (no expiry, so
|
|
59
|
+
* `<OAuth2Provider>` schedules no renew). Set it to arm the renew timer.
|
|
60
|
+
*/
|
|
61
|
+
sessionExpiresIn?: number | null;
|
|
62
|
+
}
|
|
63
|
+
/** The state knobs every mock client exposes, whatever it subclasses. */
|
|
64
|
+
export interface MockOAuth2Controls {
|
|
65
|
+
/**
|
|
66
|
+
* The starting state the mock was built with, defaults applied — what
|
|
67
|
+
* {@link MockOAuth2Provider} seeds its context from, so configuring the
|
|
68
|
+
* client is enough. A snapshot taken at construction: later
|
|
69
|
+
* `signIn`/`signOut` calls drive the event bus and do not change it.
|
|
70
|
+
*/
|
|
71
|
+
readonly initialState: Pick<OAuth2State, "isAuthenticated" | "user">;
|
|
72
|
+
/** How many times `renewSession()` has been called. */
|
|
73
|
+
readonly renewCount: number;
|
|
74
|
+
/** Pushes the mock into an authenticated state and emits `authenticated`. */
|
|
75
|
+
signIn(user?: UserInfoClaims): void;
|
|
76
|
+
/** Pushes the mock into an unauthenticated state and emits `logged_out`. */
|
|
77
|
+
signOut(): void;
|
|
78
|
+
/** Emits `token_refreshed` with a bundle expiring in `expiresIn` seconds. */
|
|
79
|
+
refreshTokens(expiresIn?: number | null): void;
|
|
80
|
+
/** Surfaces an error through the event bus. */
|
|
81
|
+
setError(error: OAuth2Error | unknown): void;
|
|
82
|
+
/** Replaces the cached user without changing authentication status. */
|
|
83
|
+
setUser(user: UserInfoClaims | null): void;
|
|
84
|
+
/** Replaces the reported seconds-to-expiry. */
|
|
85
|
+
setSessionExpiresIn(seconds: number | null): void;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* A client that satisfies the shared `OAuth2ClientBase` surface without making
|
|
89
|
+
* a single request.
|
|
90
|
+
*
|
|
91
|
+
* Neither a `BffClient` nor a `DirectClient`, so `useBffClient()` and
|
|
92
|
+
* `useDirectClient()` reject it — that is deliberate, and
|
|
93
|
+
* {@link createMockBffClient} / {@link createMockDirectClient} are what a
|
|
94
|
+
* narrowing component wants.
|
|
95
|
+
*/
|
|
96
|
+
export declare class MockOAuth2Client extends OAuth2ClientBase implements MockOAuth2Controls {
|
|
97
|
+
#private;
|
|
98
|
+
/**
|
|
99
|
+
* Builds a mock client and snapshots its starting state.
|
|
100
|
+
*
|
|
101
|
+
* @param state Where the mock starts. Everything is optional; the default
|
|
102
|
+
* is a signed-out client.
|
|
103
|
+
*/
|
|
104
|
+
constructor(state?: MockOAuth2ClientState);
|
|
105
|
+
/** The starting state, defaults applied. */
|
|
106
|
+
get initialState(): Pick<OAuth2State, "isAuthenticated" | "user">;
|
|
107
|
+
/** How many times `renewSession()` has been called. */
|
|
108
|
+
get renewCount(): number;
|
|
109
|
+
/** Resolves a fixed `mock://login` URL without touching any network. */
|
|
110
|
+
login(_options?: BaseLoginOptions): Promise<LoginRedirect>;
|
|
111
|
+
/** Drops to signed out, emits `logged_out`, and returns no redirect URL. */
|
|
112
|
+
logout(): Promise<LogoutRedirect>;
|
|
113
|
+
/** The mock's current user, or `null` while signed out. */
|
|
114
|
+
getUser(): Promise<UserInfoClaims | null>;
|
|
115
|
+
/** The mock's current state. */
|
|
116
|
+
getSession(): Promise<SessionState>;
|
|
117
|
+
/** Counts the call and re-reads {@link getSession}. */
|
|
118
|
+
renewSession(): Promise<SessionState>;
|
|
119
|
+
/** Passes straight through to `globalThis.fetch` with no auth attached. */
|
|
120
|
+
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
121
|
+
/** Pushes the mock into an authenticated state and emits `authenticated`. */
|
|
122
|
+
signIn(user?: UserInfoClaims): void;
|
|
123
|
+
/** Pushes the mock into an unauthenticated state and emits `logged_out`. */
|
|
124
|
+
signOut(): void;
|
|
125
|
+
/** Emits `token_refreshed` with a bundle expiring in `expiresIn` seconds. */
|
|
126
|
+
refreshTokens(expiresIn?: number | null): void;
|
|
127
|
+
/** Surfaces an error through the event bus. */
|
|
128
|
+
setError(error: OAuth2Error | unknown): void;
|
|
129
|
+
/** Replaces the cached user without changing authentication status. */
|
|
130
|
+
setUser(user: UserInfoClaims | null): void;
|
|
131
|
+
/** Replaces the reported seconds-to-expiry. */
|
|
132
|
+
setSessionExpiresIn(seconds: number | null): void;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* A real `BffClient` whose four session operations answer from mock state
|
|
136
|
+
* instead of the BFF. `useBffClient()` accepts it.
|
|
137
|
+
*/
|
|
138
|
+
export declare class MockBffClient extends BffClient implements MockOAuth2Controls {
|
|
139
|
+
#private;
|
|
140
|
+
/**
|
|
141
|
+
* Builds a mock client and snapshots its starting state.
|
|
142
|
+
*
|
|
143
|
+
* @param state Where the mock starts. Everything is optional; the default
|
|
144
|
+
* is a signed-out client.
|
|
145
|
+
*/
|
|
146
|
+
constructor(state?: MockOAuth2ClientState);
|
|
147
|
+
/** The starting state, defaults applied. */
|
|
148
|
+
get initialState(): Pick<OAuth2State, "isAuthenticated" | "user">;
|
|
149
|
+
/** How many times `renewSession()` has been called. */
|
|
150
|
+
get renewCount(): number;
|
|
151
|
+
/** Resolves a fixed `mock://login` URL, bypassing the BFF's URL builder. */
|
|
152
|
+
login(_options?: BaseLoginOptions): Promise<LoginRedirect>;
|
|
153
|
+
/** Drops to signed out and returns no redirect URL. */
|
|
154
|
+
logout(): Promise<LogoutRedirect>;
|
|
155
|
+
/** The mock's current user, with no session probe. */
|
|
156
|
+
getUser(): Promise<UserInfoClaims | null>;
|
|
157
|
+
/** The mock's current state, with no session probe. */
|
|
158
|
+
getSession(): Promise<SessionState>;
|
|
159
|
+
/** Counts the call and re-reads {@link getSession}. */
|
|
160
|
+
renewSession(): Promise<SessionState>;
|
|
161
|
+
/** Passes straight through to `globalThis.fetch`. */
|
|
162
|
+
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
163
|
+
/** Pushes the mock into an authenticated state and emits `authenticated`. */
|
|
164
|
+
signIn(user?: UserInfoClaims): void;
|
|
165
|
+
/** Pushes the mock into an unauthenticated state and emits `logged_out`. */
|
|
166
|
+
signOut(): void;
|
|
167
|
+
/** Emits `token_refreshed` with a bundle expiring in `expiresIn` seconds. */
|
|
168
|
+
refreshTokens(expiresIn?: number | null): void;
|
|
169
|
+
/** Surfaces an error through the event bus. */
|
|
170
|
+
setError(error: OAuth2Error | unknown): void;
|
|
171
|
+
/** Replaces the cached user without changing authentication status. */
|
|
172
|
+
setUser(user: UserInfoClaims | null): void;
|
|
173
|
+
/** Replaces the reported seconds-to-expiry. */
|
|
174
|
+
setSessionExpiresIn(seconds: number | null): void;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* A real `DirectClient` whose session operations answer from mock state
|
|
178
|
+
* instead of a token endpoint. `useDirectClient()` and `<OAuth2Callback>`
|
|
179
|
+
* accept it.
|
|
180
|
+
*
|
|
181
|
+
* The token-holding methods it does **not** override (`refresh`,
|
|
182
|
+
* `handleAuthorizationCallback`, `introspect`, …) still reach for the network.
|
|
183
|
+
* Stub the one your test drives, or point a real `DirectClient` at
|
|
184
|
+
* `createMemoryAuthorizationServer().fetch` instead.
|
|
185
|
+
*/
|
|
186
|
+
export declare class MockDirectClient extends DirectClient implements MockOAuth2Controls {
|
|
187
|
+
#private;
|
|
188
|
+
/**
|
|
189
|
+
* Builds a mock client and snapshots its starting state.
|
|
190
|
+
*
|
|
191
|
+
* @param state Where the mock starts. Everything is optional; the default
|
|
192
|
+
* is a signed-out client.
|
|
193
|
+
*/
|
|
194
|
+
constructor(state?: MockOAuth2ClientState);
|
|
195
|
+
/** The starting state, defaults applied. */
|
|
196
|
+
get initialState(): Pick<OAuth2State, "isAuthenticated" | "user">;
|
|
197
|
+
/** How many times `renewSession()` has been called. */
|
|
198
|
+
get renewCount(): number;
|
|
199
|
+
/** Resolves a fixed `mock://login` URL, skipping PKCE and storage. */
|
|
200
|
+
login(_options?: BaseLoginOptions): Promise<AuthorizationRedirect>;
|
|
201
|
+
/** Drops to signed out without revoking anything. */
|
|
202
|
+
logout(): Promise<LogoutRedirect>;
|
|
203
|
+
/** The mock's current user, with no token read. */
|
|
204
|
+
getUser(): Promise<UserInfoClaims | null>;
|
|
205
|
+
/** The mock's current state, with no token read. */
|
|
206
|
+
getSession(): Promise<SessionState>;
|
|
207
|
+
/** Counts the call and re-reads {@link getSession}. */
|
|
208
|
+
renewSession(): Promise<SessionState>;
|
|
209
|
+
/** Passes straight through to `globalThis.fetch`, attaching no bearer. */
|
|
210
|
+
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
211
|
+
/** Resolves the mock access token without touching storage. */
|
|
212
|
+
getAccessToken(): Promise<string>;
|
|
213
|
+
/** Pushes the mock into an authenticated state and emits `authenticated`. */
|
|
214
|
+
signIn(user?: UserInfoClaims): void;
|
|
215
|
+
/** Pushes the mock into an unauthenticated state and emits `logged_out`. */
|
|
216
|
+
signOut(): void;
|
|
217
|
+
/** Emits `token_refreshed` with a bundle expiring in `expiresIn` seconds. */
|
|
218
|
+
refreshTokens(expiresIn?: number | null): void;
|
|
219
|
+
/** Surfaces an error through the event bus. */
|
|
220
|
+
setError(error: OAuth2Error | unknown): void;
|
|
221
|
+
/** Replaces the cached user without changing authentication status. */
|
|
222
|
+
setUser(user: UserInfoClaims | null): void;
|
|
223
|
+
/** Replaces the reported seconds-to-expiry. */
|
|
224
|
+
setSessionExpiresIn(seconds: number | null): void;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Builds a {@link MockOAuth2Client}. No HTTP, no storage, no PKCE — just
|
|
228
|
+
* state and an event bus that the React adapter reads through the provider.
|
|
229
|
+
*
|
|
230
|
+
* @param initialState Where the mock starts.
|
|
231
|
+
* @returns The mock client, ready to hand to a provider.
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```tsx
|
|
235
|
+
* import { createMockOAuth2Client, MockOAuth2Provider } from
|
|
236
|
+
* "@udibo/oauth2/react/testing";
|
|
237
|
+
*
|
|
238
|
+
* const client = createMockOAuth2Client({ user: { sub: "u1" } });
|
|
239
|
+
* render(
|
|
240
|
+
* <MockOAuth2Provider client={client}>
|
|
241
|
+
* <Header />
|
|
242
|
+
* </MockOAuth2Provider>,
|
|
243
|
+
* );
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
export declare function createMockOAuth2Client(initialState?: MockOAuth2ClientState): MockOAuth2Client;
|
|
247
|
+
/**
|
|
248
|
+
* Builds a {@link MockBffClient} — mock state on a real `BffClient`, so a
|
|
249
|
+
* component that calls `useBffClient()` can be unit-tested.
|
|
250
|
+
*
|
|
251
|
+
* @param initialState Where the mock starts.
|
|
252
|
+
* @returns The mock client, ready to hand to a provider.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```tsx
|
|
256
|
+
* import { createMockBffClient, MockOAuth2Provider } from
|
|
257
|
+
* "@udibo/oauth2/react/testing";
|
|
258
|
+
*
|
|
259
|
+
* const client = createMockBffClient({ user: { sub: "u1" } });
|
|
260
|
+
* render(
|
|
261
|
+
* <MockOAuth2Provider client={client}>
|
|
262
|
+
* <SignInLink returnTo="/dashboard" />
|
|
263
|
+
* </MockOAuth2Provider>,
|
|
264
|
+
* );
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
export declare function createMockBffClient(initialState?: MockOAuth2ClientState): MockBffClient;
|
|
268
|
+
/**
|
|
269
|
+
* Builds a {@link MockDirectClient} — mock state on a real `DirectClient`, so
|
|
270
|
+
* a component that calls `useDirectClient()` (or mounts `<OAuth2Callback>`)
|
|
271
|
+
* can be unit-tested.
|
|
272
|
+
*
|
|
273
|
+
* @param initialState Where the mock starts.
|
|
274
|
+
* @returns The mock client, ready to hand to a provider.
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```tsx
|
|
278
|
+
* import { createMockDirectClient, MockOAuth2Provider } from
|
|
279
|
+
* "@udibo/oauth2/react/testing";
|
|
280
|
+
*
|
|
281
|
+
* const client = createMockDirectClient({ user: { sub: "u1" } });
|
|
282
|
+
* render(
|
|
283
|
+
* <MockOAuth2Provider client={client}>
|
|
284
|
+
* <TokenReadout />
|
|
285
|
+
* </MockOAuth2Provider>,
|
|
286
|
+
* );
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
289
|
+
export declare function createMockDirectClient(initialState?: MockOAuth2ClientState): MockDirectClient;
|
|
290
|
+
/** Props for {@link MockOAuth2Provider}. */
|
|
291
|
+
export interface MockOAuth2ProviderProps {
|
|
292
|
+
/**
|
|
293
|
+
* Built via {@link createMockOAuth2Client}, {@link createMockBffClient}, or
|
|
294
|
+
* {@link createMockDirectClient}.
|
|
295
|
+
*/
|
|
296
|
+
client: OAuth2ClientBase & MockOAuth2Controls;
|
|
297
|
+
/**
|
|
298
|
+
* Optional initial state override, applied key by key: a key you pass wins
|
|
299
|
+
* (including `user: null`), a key you omit falls back to the mock client's
|
|
300
|
+
* {@link MockOAuth2Controls.initialState} for `isAuthenticated` / `user` and
|
|
301
|
+
* to the signed-out default for the rest. So a test configures the client
|
|
302
|
+
* once instead of restating the same user here.
|
|
303
|
+
*/
|
|
304
|
+
state?: Partial<OAuth2State>;
|
|
305
|
+
/** The subtree rendered under the mock provider. */
|
|
306
|
+
children: ReactNode;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Drop-in replacement for `<OAuth2Provider>` that skips the on-mount
|
|
310
|
+
* session probe (the mock clients don't issue one) and surfaces the
|
|
311
|
+
* mock state synchronously.
|
|
312
|
+
*
|
|
313
|
+
* The context it publishes is a snapshot of the client as it was built (plus
|
|
314
|
+
* any `state` overrides): it subscribes to nothing, so calling `signIn` /
|
|
315
|
+
* `signOut` on the client afterwards does not re-render the subtree. Render
|
|
316
|
+
* the state you want, or use a real `<OAuth2Provider>` when the test is about
|
|
317
|
+
* a transition.
|
|
318
|
+
*
|
|
319
|
+
* @param props A mock client, optional state overrides, and children.
|
|
320
|
+
* @returns The subtree wrapped in a pre-resolved OAuth2 context.
|
|
321
|
+
*/
|
|
322
|
+
export declare function MockOAuth2Provider(props: MockOAuth2ProviderProps): ReactNode;
|