@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,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {@link useAuthForm} — the headless hook backing every default auth form
|
|
3
|
+
* component in `@udibo/oauth2/react/components`.
|
|
4
|
+
*
|
|
5
|
+
* It owns field values, per-field and form-level errors, and the submit
|
|
6
|
+
* lifecycle, and stays entirely presentation-free: no markup, no styling, no
|
|
7
|
+
* router or network assumptions. The action is injected as `onSubmit`, so the
|
|
8
|
+
* same hook drives a client-side `fetch` in a plain React Router app or a
|
|
9
|
+
* router-action submit in Juniper. Reach for it directly when you want to own
|
|
10
|
+
* the markup completely (the "eject to headless" path); otherwise use a
|
|
11
|
+
* default component, which is built on this hook.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { type ChangeEvent } from "react";
|
|
16
|
+
import type { AuthFormErrors, AuthFormValues, AuthSubmitHandler } from "./types.js";
|
|
17
|
+
/** Lifecycle status of an {@link useAuthForm} instance. */
|
|
18
|
+
export type AuthFormStatus = "idle" | "submitting" | "success" | "error";
|
|
19
|
+
/**
|
|
20
|
+
* Props spread onto a field's `<input>` to wire value, change handling, and
|
|
21
|
+
* accessibility. Produced by {@link AuthFormState.getFieldProps}.
|
|
22
|
+
*/
|
|
23
|
+
export interface AuthFieldProps {
|
|
24
|
+
/** The input's `id`, also referenced by its label's `htmlFor`. */
|
|
25
|
+
id: string;
|
|
26
|
+
/** The field name (form key). */
|
|
27
|
+
name: string;
|
|
28
|
+
/** Current string value (checkboxes read `checked` instead — see below). */
|
|
29
|
+
value: string;
|
|
30
|
+
/** Whether a checkbox field is checked (omitted for text fields). */
|
|
31
|
+
checked?: boolean;
|
|
32
|
+
/** Change handler that reads `value`/`checked` and updates form state. */
|
|
33
|
+
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
|
34
|
+
/** `true` when the field currently has an error, else `undefined`. */
|
|
35
|
+
"aria-invalid"?: true;
|
|
36
|
+
/** The id of this field's error element when errored, else `undefined`. */
|
|
37
|
+
"aria-describedby"?: string;
|
|
38
|
+
}
|
|
39
|
+
/** Options for {@link useAuthForm}. */
|
|
40
|
+
export interface UseAuthFormOptions<V extends AuthFormValues> {
|
|
41
|
+
/** Starting values; also defines the set of fields. */
|
|
42
|
+
initialValues: V;
|
|
43
|
+
/** The injected action that performs the submit. */
|
|
44
|
+
onSubmit: AuthSubmitHandler<V>;
|
|
45
|
+
/**
|
|
46
|
+
* Optional synchronous client-side validation run before `onSubmit`. Return
|
|
47
|
+
* a map of field errors to block submission, or `null`/`undefined` to allow.
|
|
48
|
+
* A throw is trapped like an `onSubmit` throw — surfaced as a form-level
|
|
49
|
+
* error (`status: "error"`) rather than an unhandled rejection.
|
|
50
|
+
*/
|
|
51
|
+
validate?: (values: V) => AuthFormErrors<V> | null | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Called after a successful submit (no `error`/`fieldErrors` returned). A
|
|
54
|
+
* promise it returns is awaited, but a throw or rejection is caught and
|
|
55
|
+
* logged to `console.error` rather than surfaced: `status` stays `"success"`
|
|
56
|
+
* and no form error appears.
|
|
57
|
+
*/
|
|
58
|
+
onSuccess?: (values: V) => void;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The live state and actions returned by {@link useAuthForm}. This is also the
|
|
62
|
+
* value passed to a form component's render-prop `children`.
|
|
63
|
+
*/
|
|
64
|
+
export interface AuthFormState<V extends AuthFormValues> {
|
|
65
|
+
/** Current field values. */
|
|
66
|
+
values: V;
|
|
67
|
+
/** Current per-field errors. */
|
|
68
|
+
errors: AuthFormErrors<V>;
|
|
69
|
+
/** Current form-level error, or `null`. */
|
|
70
|
+
formError: string | null;
|
|
71
|
+
/** Lifecycle status. */
|
|
72
|
+
status: AuthFormStatus;
|
|
73
|
+
/** `true` while a submit is in flight (`status === "submitting"`). */
|
|
74
|
+
isSubmitting: boolean;
|
|
75
|
+
/** `true` once a submit has completed successfully. */
|
|
76
|
+
succeeded: boolean;
|
|
77
|
+
/** Increments on every submit attempt; useful as a focus-effect trigger. */
|
|
78
|
+
submitCount: number;
|
|
79
|
+
/** Set a single field's value. */
|
|
80
|
+
setValue<K extends keyof V & string>(name: K, value: V[K]): void;
|
|
81
|
+
/** Merge a partial set of field values. */
|
|
82
|
+
setValues(next: Partial<V>): void;
|
|
83
|
+
/** Reset values to `initialValues` and clear all errors/status. */
|
|
84
|
+
reset(): void;
|
|
85
|
+
/** Submit handler for a `<form onSubmit>` (calls `preventDefault`). */
|
|
86
|
+
handleSubmit(event?: {
|
|
87
|
+
preventDefault(): void;
|
|
88
|
+
}): Promise<void>;
|
|
89
|
+
/** Build the props to spread onto a field's `<input>`. */
|
|
90
|
+
getFieldProps<K extends keyof V & string>(name: K): AuthFieldProps;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Headless form engine: owns values, errors, and the submit lifecycle for an
|
|
94
|
+
* auth form, delegating the actual action to the injected `onSubmit`.
|
|
95
|
+
*
|
|
96
|
+
* @example Eject to fully custom markup
|
|
97
|
+
* ```tsx
|
|
98
|
+
* const form = useAuthForm({
|
|
99
|
+
* initialValues: { identifier: "", password: "" },
|
|
100
|
+
* onSubmit: async (values) => {
|
|
101
|
+
* const res = await fetch("/auth/sign-in", {
|
|
102
|
+
* method: "POST",
|
|
103
|
+
* body: JSON.stringify(values),
|
|
104
|
+
* });
|
|
105
|
+
* if (!res.ok) return { error: "Invalid credentials" };
|
|
106
|
+
* },
|
|
107
|
+
* });
|
|
108
|
+
* return (
|
|
109
|
+
* <form onSubmit={form.handleSubmit}>
|
|
110
|
+
* <input {...form.getFieldProps("identifier")} />
|
|
111
|
+
* <input {...form.getFieldProps("password")} type="password" />
|
|
112
|
+
* {form.formError ? <p role="alert">{form.formError}</p> : null}
|
|
113
|
+
* <button type="submit" disabled={form.isSubmitting}>Sign in</button>
|
|
114
|
+
* </form>
|
|
115
|
+
* );
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export declare function useAuthForm<V extends AuthFormValues>(options: UseAuthFormOptions<V>): AuthFormState<V>;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {@link useAuthForm} — the headless hook backing every default auth form
|
|
3
|
+
* component in `@udibo/oauth2/react/components`.
|
|
4
|
+
*
|
|
5
|
+
* It owns field values, per-field and form-level errors, and the submit
|
|
6
|
+
* lifecycle, and stays entirely presentation-free: no markup, no styling, no
|
|
7
|
+
* router or network assumptions. The action is injected as `onSubmit`, so the
|
|
8
|
+
* same hook drives a client-side `fetch` in a plain React Router app or a
|
|
9
|
+
* router-action submit in Juniper. Reach for it directly when you want to own
|
|
10
|
+
* the markup completely (the "eject to headless" path); otherwise use a
|
|
11
|
+
* default component, which is built on this hook.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { useCallback, useId, useMemo, useRef, useState, } from "react";
|
|
16
|
+
/**
|
|
17
|
+
* Headless form engine: owns values, errors, and the submit lifecycle for an
|
|
18
|
+
* auth form, delegating the actual action to the injected `onSubmit`.
|
|
19
|
+
*
|
|
20
|
+
* @example Eject to fully custom markup
|
|
21
|
+
* ```tsx
|
|
22
|
+
* const form = useAuthForm({
|
|
23
|
+
* initialValues: { identifier: "", password: "" },
|
|
24
|
+
* onSubmit: async (values) => {
|
|
25
|
+
* const res = await fetch("/auth/sign-in", {
|
|
26
|
+
* method: "POST",
|
|
27
|
+
* body: JSON.stringify(values),
|
|
28
|
+
* });
|
|
29
|
+
* if (!res.ok) return { error: "Invalid credentials" };
|
|
30
|
+
* },
|
|
31
|
+
* });
|
|
32
|
+
* return (
|
|
33
|
+
* <form onSubmit={form.handleSubmit}>
|
|
34
|
+
* <input {...form.getFieldProps("identifier")} />
|
|
35
|
+
* <input {...form.getFieldProps("password")} type="password" />
|
|
36
|
+
* {form.formError ? <p role="alert">{form.formError}</p> : null}
|
|
37
|
+
* <button type="submit" disabled={form.isSubmitting}>Sign in</button>
|
|
38
|
+
* </form>
|
|
39
|
+
* );
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function useAuthForm(options) {
|
|
43
|
+
const { initialValues, onSubmit, validate, onSuccess } = options;
|
|
44
|
+
const idBase = useId();
|
|
45
|
+
const [values, setValuesState] = useState(initialValues);
|
|
46
|
+
const [errors, setErrors] = useState({});
|
|
47
|
+
const [formError, setFormError] = useState(null);
|
|
48
|
+
const [status, setStatus] = useState("idle");
|
|
49
|
+
const [submitCount, setSubmitCount] = useState(0);
|
|
50
|
+
// Synchronous re-entrancy lock: `status` is a render-closure value, so it
|
|
51
|
+
// can't block a same-tick double submit (Enter racing autofill, etc.).
|
|
52
|
+
const submittingRef = useRef(false);
|
|
53
|
+
const setValue = useCallback((name, value) => {
|
|
54
|
+
setValuesState((prev) => ({ ...prev, [name]: value }));
|
|
55
|
+
}, []);
|
|
56
|
+
const setValues = useCallback((next) => {
|
|
57
|
+
setValuesState((prev) => ({ ...prev, ...next }));
|
|
58
|
+
}, []);
|
|
59
|
+
const reset = useCallback(() => {
|
|
60
|
+
setValuesState(initialValues);
|
|
61
|
+
setErrors({});
|
|
62
|
+
setFormError(null);
|
|
63
|
+
setStatus("idle");
|
|
64
|
+
}, [initialValues]);
|
|
65
|
+
const handleSubmit = useCallback(async (event) => {
|
|
66
|
+
event?.preventDefault();
|
|
67
|
+
if (submittingRef.current)
|
|
68
|
+
return;
|
|
69
|
+
submittingRef.current = true;
|
|
70
|
+
try {
|
|
71
|
+
setSubmitCount((count) => count + 1);
|
|
72
|
+
setFormError(null);
|
|
73
|
+
setErrors({});
|
|
74
|
+
if (validate) {
|
|
75
|
+
let validationErrors;
|
|
76
|
+
try {
|
|
77
|
+
validationErrors = validate(values);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
setFormError(error instanceof Error ? error.message : "Something went wrong.");
|
|
81
|
+
setStatus("error");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (validationErrors && Object.keys(validationErrors).length > 0) {
|
|
85
|
+
setErrors(validationErrors);
|
|
86
|
+
setStatus("error");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
setStatus("submitting");
|
|
91
|
+
let result;
|
|
92
|
+
try {
|
|
93
|
+
result = await onSubmit(values);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
setFormError(error instanceof Error ? error.message : "Something went wrong.");
|
|
97
|
+
setStatus("error");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const fieldErrors = result?.fieldErrors;
|
|
101
|
+
const hasFieldErrors = fieldErrors &&
|
|
102
|
+
Object.keys(fieldErrors).length > 0;
|
|
103
|
+
if (result?.error || hasFieldErrors) {
|
|
104
|
+
if (result?.error)
|
|
105
|
+
setFormError(result.error);
|
|
106
|
+
if (hasFieldErrors)
|
|
107
|
+
setErrors(fieldErrors);
|
|
108
|
+
setStatus("error");
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
setStatus("success");
|
|
112
|
+
// An integrator's onSuccess side effect must not become an unhandled
|
|
113
|
+
// rejection (form onSubmit doesn't await handleSubmit).
|
|
114
|
+
try {
|
|
115
|
+
await onSuccess?.(values);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
console.error("[@udibo/oauth2] auth form onSuccess failed:", error);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
submittingRef.current = false;
|
|
123
|
+
}
|
|
124
|
+
}, [values, validate, onSubmit, onSuccess]);
|
|
125
|
+
const getFieldProps = useCallback((name) => {
|
|
126
|
+
const raw = values[name];
|
|
127
|
+
const hasError = Boolean(errors[name]);
|
|
128
|
+
const id = `${idBase}-${name}`;
|
|
129
|
+
const base = {
|
|
130
|
+
id,
|
|
131
|
+
name,
|
|
132
|
+
value: typeof raw === "boolean" ? "" : String(raw ?? ""),
|
|
133
|
+
onChange: (event) => {
|
|
134
|
+
const target = event.target;
|
|
135
|
+
const next = target.type === "checkbox"
|
|
136
|
+
? target.checked
|
|
137
|
+
: target.value;
|
|
138
|
+
setValue(name, next);
|
|
139
|
+
},
|
|
140
|
+
"aria-invalid": hasError ? true : undefined,
|
|
141
|
+
"aria-describedby": hasError ? `${id}-error` : undefined,
|
|
142
|
+
};
|
|
143
|
+
if (typeof raw === "boolean")
|
|
144
|
+
base.checked = raw;
|
|
145
|
+
return base;
|
|
146
|
+
}, [values, errors, idBase, setValue]);
|
|
147
|
+
return useMemo(() => ({
|
|
148
|
+
values,
|
|
149
|
+
errors,
|
|
150
|
+
formError,
|
|
151
|
+
status,
|
|
152
|
+
isSubmitting: status === "submitting",
|
|
153
|
+
succeeded: status === "success",
|
|
154
|
+
submitCount,
|
|
155
|
+
setValue,
|
|
156
|
+
setValues,
|
|
157
|
+
reset,
|
|
158
|
+
handleSubmit,
|
|
159
|
+
getFieldProps,
|
|
160
|
+
}), [
|
|
161
|
+
values,
|
|
162
|
+
errors,
|
|
163
|
+
formError,
|
|
164
|
+
status,
|
|
165
|
+
submitCount,
|
|
166
|
+
setValue,
|
|
167
|
+
setValues,
|
|
168
|
+
reset,
|
|
169
|
+
handleSubmit,
|
|
170
|
+
getFieldProps,
|
|
171
|
+
]);
|
|
172
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {@link UserMenu} — a default, accessible, unstyled signed-in user menu. Reads
|
|
3
|
+
* the current user and `logout` from {@link useOAuth2}, renders a disclosure
|
|
4
|
+
* button showing the user's name, and exposes a logout action plus a slot for
|
|
5
|
+
* your own menu items.
|
|
6
|
+
*
|
|
7
|
+
* Renders `null` (or a `signedOut` slot) when no user is authenticated, so it
|
|
8
|
+
* is safe to mount unconditionally in a nav bar.
|
|
9
|
+
*
|
|
10
|
+
* The claims type its `renderUser` / `children` callbacks receive is
|
|
11
|
+
* `UserInfoClaims`, imported from `@udibo/oauth2/client` — it belongs to the
|
|
12
|
+
* client, not to this component.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
import { type ReactNode } from "react";
|
|
17
|
+
import type { UserInfoClaims } from "../../client/mod.js";
|
|
18
|
+
import type { BaseClassNames } from "./types.js";
|
|
19
|
+
/**
|
|
20
|
+
* Per-slot class hooks for {@link UserMenu}: the shared {@link BaseClassNames}
|
|
21
|
+
* `root` plus the menu's own slots.
|
|
22
|
+
*/
|
|
23
|
+
export interface UserMenuClassNames extends BaseClassNames {
|
|
24
|
+
/** The disclosure trigger button (`data-oauth2-user-trigger`). */
|
|
25
|
+
trigger?: string;
|
|
26
|
+
/** The display-name element inside the trigger. */
|
|
27
|
+
name?: string;
|
|
28
|
+
/** The menu panel revealed on open (`data-oauth2-user-panel`). */
|
|
29
|
+
menu?: string;
|
|
30
|
+
/** Each menu item wrapper. */
|
|
31
|
+
menuItem?: string;
|
|
32
|
+
/** The logout button (`data-oauth2-logout`). */
|
|
33
|
+
logout?: string;
|
|
34
|
+
}
|
|
35
|
+
/** Visible text overrides for {@link UserMenu}. */
|
|
36
|
+
export interface UserMenuLabels {
|
|
37
|
+
/** Logout action text. Default: `"Sign out"`. */
|
|
38
|
+
logout?: string;
|
|
39
|
+
}
|
|
40
|
+
/** Props for {@link UserMenu}. */
|
|
41
|
+
export interface UserMenuProps {
|
|
42
|
+
/** Extra menu content rendered above the logout action (links, etc.). */
|
|
43
|
+
items?: ReactNode;
|
|
44
|
+
/**
|
|
45
|
+
* Override the logout behaviour. Defaults to `useOAuth2().logout()`, which
|
|
46
|
+
* ends the session and (in the browser) navigates to the logout URL.
|
|
47
|
+
*/
|
|
48
|
+
onLogout?: () => void | Promise<void>;
|
|
49
|
+
/** Custom renderer for the trigger's user display. */
|
|
50
|
+
renderUser?: (user: UserInfoClaims) => ReactNode;
|
|
51
|
+
/** Rendered when no user is authenticated. Default: `null`. */
|
|
52
|
+
signedOut?: ReactNode;
|
|
53
|
+
/** Class for the root wrapper (merged with `classNames.root`). */
|
|
54
|
+
className?: string;
|
|
55
|
+
/** Per-slot class hooks for theming. */
|
|
56
|
+
classNames?: UserMenuClassNames;
|
|
57
|
+
/** Text overrides. */
|
|
58
|
+
labels?: UserMenuLabels;
|
|
59
|
+
/**
|
|
60
|
+
* Render-prop escape hatch. Receives the current user and a `logout`
|
|
61
|
+
* callback so you can render an entirely custom menu.
|
|
62
|
+
*/
|
|
63
|
+
children?: (state: {
|
|
64
|
+
user: UserInfoClaims;
|
|
65
|
+
logout: () => void | Promise<void>;
|
|
66
|
+
}) => ReactNode;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A ready-to-use signed-in user menu. Mount it in your nav; it reads auth
|
|
70
|
+
* state from the surrounding `<OAuth2Provider>`.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* <UserMenu
|
|
75
|
+
* items={<a href="/profile">Profile</a>}
|
|
76
|
+
* />
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function UserMenu(props: UserMenuProps): ReactNode;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* {@link UserMenu} — a default, accessible, unstyled signed-in user menu. Reads
|
|
4
|
+
* the current user and `logout` from {@link useOAuth2}, renders a disclosure
|
|
5
|
+
* button showing the user's name, and exposes a logout action plus a slot for
|
|
6
|
+
* your own menu items.
|
|
7
|
+
*
|
|
8
|
+
* Renders `null` (or a `signedOut` slot) when no user is authenticated, so it
|
|
9
|
+
* is safe to mount unconditionally in a nav bar.
|
|
10
|
+
*
|
|
11
|
+
* The claims type its `renderUser` / `children` callbacks receive is
|
|
12
|
+
* `UserInfoClaims`, imported from `@udibo/oauth2/client` — it belongs to the
|
|
13
|
+
* client, not to this component.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
18
|
+
import { useOAuth2 } from "../use-oauth2.js";
|
|
19
|
+
import { combineClassNames, displayName } from "./internal.js";
|
|
20
|
+
/**
|
|
21
|
+
* A ready-to-use signed-in user menu. Mount it in your nav; it reads auth
|
|
22
|
+
* state from the surrounding `<OAuth2Provider>`.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <UserMenu
|
|
27
|
+
* items={<a href="/profile">Profile</a>}
|
|
28
|
+
* />
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export function UserMenu(props) {
|
|
32
|
+
const { items, onLogout, renderUser, signedOut = null, className, classNames, labels, children, } = props;
|
|
33
|
+
const { user, logout } = useOAuth2();
|
|
34
|
+
const [open, setOpen] = useState(false);
|
|
35
|
+
const panelId = useId();
|
|
36
|
+
const rootRef = useRef(null);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!open)
|
|
39
|
+
return;
|
|
40
|
+
const onKeyDown = (event) => {
|
|
41
|
+
if (event.key === "Escape")
|
|
42
|
+
setOpen(false);
|
|
43
|
+
};
|
|
44
|
+
const onPointerDown = (event) => {
|
|
45
|
+
if (!rootRef.current?.contains(event.target))
|
|
46
|
+
setOpen(false);
|
|
47
|
+
};
|
|
48
|
+
document.addEventListener("keydown", onKeyDown);
|
|
49
|
+
document.addEventListener("pointerdown", onPointerDown);
|
|
50
|
+
return () => {
|
|
51
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
52
|
+
document.removeEventListener("pointerdown", onPointerDown);
|
|
53
|
+
};
|
|
54
|
+
}, [open]);
|
|
55
|
+
if (!user)
|
|
56
|
+
return _jsx(_Fragment, { children: signedOut });
|
|
57
|
+
const runLogout = onLogout ?? (async () => {
|
|
58
|
+
await logout();
|
|
59
|
+
});
|
|
60
|
+
if (children)
|
|
61
|
+
return _jsx(_Fragment, { children: children({ user, logout: runLogout }) });
|
|
62
|
+
return (_jsxs("div", { ref: rootRef, "data-oauth2-user-menu": "", className: combineClassNames(className, classNames?.root), children: [_jsx("button", { type: "button", "aria-expanded": open, "aria-controls": panelId, onClick: () => setOpen((value) => !value), "data-oauth2-user-trigger": "", className: classNames?.trigger, children: renderUser
|
|
63
|
+
? renderUser(user)
|
|
64
|
+
: (_jsx("span", { "data-oauth2-user-name": "", className: classNames?.name, children: displayName(user) })) }), open
|
|
65
|
+
? (_jsxs("div", { id: panelId, "data-oauth2-user-panel": "", className: classNames?.menu, children: [items
|
|
66
|
+
? (_jsx("div", { "data-oauth2-user-items": "", className: classNames?.menuItem, children: items }))
|
|
67
|
+
: null, _jsx("button", { type: "button", onClick: () => {
|
|
68
|
+
void Promise.resolve(runLogout()).catch((error) => {
|
|
69
|
+
console.error("[@udibo/oauth2] logout failed:", error);
|
|
70
|
+
});
|
|
71
|
+
}, "data-oauth2-logout": "", className: classNames?.logout, children: labels?.logout ?? "Sign out" })] }))
|
|
72
|
+
: null] }));
|
|
73
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React context wiring for the OAuth2 client.
|
|
3
|
+
*
|
|
4
|
+
* Internal — consumers should reach for {@link useOAuth2} (the hook),
|
|
5
|
+
* {@link OAuth2Provider}, {@link RequireAuth}, and {@link OAuth2Callback}
|
|
6
|
+
* rather than the context object directly.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { type Context } from "react";
|
|
11
|
+
import type { OAuth2ClientBase, OAuth2Error, UserInfoClaims } from "../client/mod.js";
|
|
12
|
+
/** Shape exposed by `useOAuth2()`. */
|
|
13
|
+
export interface OAuth2State {
|
|
14
|
+
/** Whether a user is currently authenticated. */
|
|
15
|
+
isAuthenticated: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* `true` during the initial session probe and during a token refresh
|
|
18
|
+
* with no currently valid access token. Settles to `false` once
|
|
19
|
+
* authentication state is known.
|
|
20
|
+
*/
|
|
21
|
+
isLoading: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Current user claims, or `null` when unauthenticated. From
|
|
24
|
+
* `GET /auth/session` behind a `BffClient`; the decoded `id_token` claims
|
|
25
|
+
* (or the `userinfo_endpoint` body) behind a `DirectClient`.
|
|
26
|
+
*/
|
|
27
|
+
user: UserInfoClaims | null;
|
|
28
|
+
/** Last error surfaced by the client, or `null`. */
|
|
29
|
+
error: OAuth2Error | null;
|
|
30
|
+
/**
|
|
31
|
+
* Seconds until the session's access token expires, or `null` when unknown.
|
|
32
|
+
* The provider calls `client.renewSession()` shortly before this elapses.
|
|
33
|
+
*/
|
|
34
|
+
sessionExpiresIn: number | null;
|
|
35
|
+
/**
|
|
36
|
+
* A URL that ends the session, or `null` when the client has none to offer.
|
|
37
|
+
* Lets a UI render a sign-out link without hardcoding the path.
|
|
38
|
+
*/
|
|
39
|
+
logoutUrl: string | null;
|
|
40
|
+
}
|
|
41
|
+
/** Internal context value shared by the provider and consumers. */
|
|
42
|
+
export interface OAuth2ContextValue extends OAuth2State {
|
|
43
|
+
/** The underlying client — a `BffClient` or a `DirectClient`. */
|
|
44
|
+
client: OAuth2ClientBase;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Internal context — providers wire up the value, consumers read it
|
|
48
|
+
* through `useOAuth2()`. Default `null` so `useOAuth2()` can throw a
|
|
49
|
+
* clear error when called outside any provider.
|
|
50
|
+
*/
|
|
51
|
+
export declare const OAuth2Context: Context<OAuth2ContextValue | null>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React context wiring for the OAuth2 client.
|
|
3
|
+
*
|
|
4
|
+
* Internal — consumers should reach for {@link useOAuth2} (the hook),
|
|
5
|
+
* {@link OAuth2Provider}, {@link RequireAuth}, and {@link OAuth2Callback}
|
|
6
|
+
* rather than the context object directly.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { createContext } from "react";
|
|
11
|
+
/**
|
|
12
|
+
* Internal context — providers wire up the value, consumers read it
|
|
13
|
+
* through `useOAuth2()`. Default `null` so `useOAuth2()` can throw a
|
|
14
|
+
* clear error when called outside any provider.
|
|
15
|
+
*/
|
|
16
|
+
export const OAuth2Context = createContext(null);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React adapter for `@udibo/oauth2/client`.
|
|
3
|
+
*
|
|
4
|
+
* Wraps a `BffClient` or a `DirectClient` in a React context and ships
|
|
5
|
+
* components / hooks for the common SPA patterns:
|
|
6
|
+
*
|
|
7
|
+
* - {@link OAuth2Provider} — install once near the app root.
|
|
8
|
+
* - {@link useOAuth2} — read state and bound auth helpers.
|
|
9
|
+
* - {@link RequireAuth} — gate a subtree behind authentication.
|
|
10
|
+
* - {@link OAuth2Callback} — callback route for a `DirectClient` app.
|
|
11
|
+
*
|
|
12
|
+
* The adapter is framework- and server-neutral: it works against any
|
|
13
|
+
* RFC 6749-compliant authorization server, and everything above is written
|
|
14
|
+
* against the clients' shared base, so the same components and hooks work
|
|
15
|
+
* whichever one the app is wired with. Reach for {@link useBffClient} or
|
|
16
|
+
* {@link useDirectClient} when a component needs one transport's specifics.
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
import "../_dnt.polyfills.js";
|
|
21
|
+
export { OAuth2Context, type OAuth2ContextValue, type OAuth2State, } from "./context.js";
|
|
22
|
+
export { OAuth2Provider, type OAuth2ProviderProps } from "./provider.js";
|
|
23
|
+
export { useBffClient, useDirectClient, useOAuth2, type UseOAuth2Result, } from "./use-oauth2.js";
|
|
24
|
+
export { useAuthorization } from "./use-authorization.js";
|
|
25
|
+
export { RequireAuth, type RequireAuthProps } from "./require-auth.js";
|
|
26
|
+
export { OAuth2Callback, type OAuth2CallbackProps } from "./callback.js";
|
package/esm/react/mod.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React adapter for `@udibo/oauth2/client`.
|
|
3
|
+
*
|
|
4
|
+
* Wraps a `BffClient` or a `DirectClient` in a React context and ships
|
|
5
|
+
* components / hooks for the common SPA patterns:
|
|
6
|
+
*
|
|
7
|
+
* - {@link OAuth2Provider} — install once near the app root.
|
|
8
|
+
* - {@link useOAuth2} — read state and bound auth helpers.
|
|
9
|
+
* - {@link RequireAuth} — gate a subtree behind authentication.
|
|
10
|
+
* - {@link OAuth2Callback} — callback route for a `DirectClient` app.
|
|
11
|
+
*
|
|
12
|
+
* The adapter is framework- and server-neutral: it works against any
|
|
13
|
+
* RFC 6749-compliant authorization server, and everything above is written
|
|
14
|
+
* against the clients' shared base, so the same components and hooks work
|
|
15
|
+
* whichever one the app is wired with. Reach for {@link useBffClient} or
|
|
16
|
+
* {@link useDirectClient} when a component needs one transport's specifics.
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
import "../_dnt.polyfills.js";
|
|
21
|
+
export { OAuth2Context, } from "./context.js";
|
|
22
|
+
export { OAuth2Provider } from "./provider.js";
|
|
23
|
+
export { useBffClient, useDirectClient, useOAuth2, } from "./use-oauth2.js";
|
|
24
|
+
export { useAuthorization } from "./use-authorization.js";
|
|
25
|
+
export { RequireAuth } from "./require-auth.js";
|
|
26
|
+
export { OAuth2Callback } from "./callback.js";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<OAuth2Provider>` — wraps the app, wires an {@link OAuth2ClientBase} into
|
|
3
|
+
* a React context, and re-renders subscribers when the client emits
|
|
4
|
+
* authentication state changes.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { type ReactNode } from "react";
|
|
9
|
+
import type { OAuth2ClientBase } from "../client/mod.js";
|
|
10
|
+
import { type OAuth2State } from "./context.js";
|
|
11
|
+
/** Props for {@link OAuth2Provider}. */
|
|
12
|
+
export interface OAuth2ProviderProps {
|
|
13
|
+
/**
|
|
14
|
+
* The OAuth2 client driving the flows — a `BffClient` or a `DirectClient`.
|
|
15
|
+
* Construct once per app.
|
|
16
|
+
*/
|
|
17
|
+
client: OAuth2ClientBase;
|
|
18
|
+
/**
|
|
19
|
+
* Optional pre-resolved auth state (typically from a server-side
|
|
20
|
+
* session probe). Populating this skips the on-mount session probe
|
|
21
|
+
* and renders the authenticated tree on the first paint — no
|
|
22
|
+
* hydration flash. Pass a stable reference (don't construct it inline
|
|
23
|
+
* in render) so the on-mount effect doesn't re-run.
|
|
24
|
+
*/
|
|
25
|
+
initialState?: Partial<OAuth2State>;
|
|
26
|
+
/** The app subtree that reads auth state via `useOAuth2()`. */
|
|
27
|
+
children: ReactNode;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Provider — install once near the root of your app. Children read the
|
|
31
|
+
* state via `useOAuth2()`.
|
|
32
|
+
*
|
|
33
|
+
* While authenticated it renews the session on a timer shortly before the
|
|
34
|
+
* access token expires, re-arming after each renew. Renewal is per tab and
|
|
35
|
+
* uncoordinated: a `DirectClient` given a refresh-token storage shared across
|
|
36
|
+
* tabs (e.g. `IndexedDBRefreshTokenStorage`) against a server that
|
|
37
|
+
* rotates refresh tokens can still have two tabs redeem the same token, which
|
|
38
|
+
* reuse detection may answer by ending the session everywhere.
|
|
39
|
+
*/
|
|
40
|
+
export declare function OAuth2Provider(props: OAuth2ProviderProps): ReactNode;
|