@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,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The provider-agnostic two-step flow for external (social) sign-in:
|
|
3
|
+
* {@link ExternalAuthFlow.start} builds the redirect and hands back a
|
|
4
|
+
* serializable transient; {@link ExternalAuthFlow.finish} verifies the
|
|
5
|
+
* callback and returns the normalized profile.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { timingSafeEqualString } from "../../utils/crypto.js";
|
|
10
|
+
import { generateCodeVerifier, generateState } from "../../utils/pkce.js";
|
|
11
|
+
import { ExternalAuthError } from "./errors.js";
|
|
12
|
+
/** Default {@link ExternalAuthFlowOptions.maxTransientAgeMs}: 10 minutes. */
|
|
13
|
+
export const DEFAULT_MAX_TRANSIENT_AGE_MS = 10 * 60 * 1000;
|
|
14
|
+
/**
|
|
15
|
+
* Drives one external provider through the authorization-code redirect dance
|
|
16
|
+
* without the library storing anything: {@link start} returns the redirect URL
|
|
17
|
+
* plus a JSON-serializable {@link ExternalAuthTransient} for the caller to keep
|
|
18
|
+
* (sealed cookie or session), and {@link finish} takes the callback params and
|
|
19
|
+
* that transient back and returns the verified {@link ExternalProfile}.
|
|
20
|
+
*
|
|
21
|
+
* The flow itself performs no network I/O — inject `fetch` on the provider to
|
|
22
|
+
* stub the network in tests. Create one flow per configured provider.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const flow = new ExternalAuthFlow({
|
|
27
|
+
* provider: googleProvider({ clientId, clientSecret }),
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* // GET /auth/social/google — redirect to Google, transient into a cookie.
|
|
31
|
+
* const { url, transient } = await flow.start({
|
|
32
|
+
* redirectUri: "https://app.example.com/auth/social/google/callback",
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // GET /auth/social/google/callback — verify and normalize.
|
|
36
|
+
* const profile = await flow.finish({
|
|
37
|
+
* params: new URL(request.url).searchParams,
|
|
38
|
+
* transient,
|
|
39
|
+
* });
|
|
40
|
+
* // App code decides: look up (profile.provider, profile.subject), create
|
|
41
|
+
* // or link a user, then start your own session.
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export class ExternalAuthFlow {
|
|
45
|
+
/** The connector this flow drives. */
|
|
46
|
+
provider;
|
|
47
|
+
#maxTransientAgeMs;
|
|
48
|
+
/** Creates a flow for one configured provider. */
|
|
49
|
+
constructor(options) {
|
|
50
|
+
this.provider = options.provider;
|
|
51
|
+
this.#maxTransientAgeMs = options.maxTransientAgeMs ??
|
|
52
|
+
DEFAULT_MAX_TRANSIENT_AGE_MS;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Begins a sign-in attempt: generates the per-attempt `state` (plus a PKCE
|
|
56
|
+
* verifier and OIDC nonce when the provider uses them), builds the
|
|
57
|
+
* provider's authorization URL, and returns both. Persist the transient
|
|
58
|
+
* (e.g. sealed cookie) and redirect the browser to `url`.
|
|
59
|
+
*
|
|
60
|
+
* @throws {ExternalAuthError} `configuration` when the provider cannot
|
|
61
|
+
* resolve its endpoints (e.g. OIDC discovery failed).
|
|
62
|
+
*/
|
|
63
|
+
async start(input) {
|
|
64
|
+
const state = generateState();
|
|
65
|
+
const codeVerifier = this.provider.usesPkce
|
|
66
|
+
? generateCodeVerifier()
|
|
67
|
+
: undefined;
|
|
68
|
+
const nonce = this.provider.usesNonce ? generateState() : undefined;
|
|
69
|
+
const scopes = input.scopes ?? this.provider.defaultScopes;
|
|
70
|
+
const url = await this.provider.buildAuthorizationUrl({
|
|
71
|
+
redirectUri: input.redirectUri,
|
|
72
|
+
state,
|
|
73
|
+
codeVerifier,
|
|
74
|
+
nonce,
|
|
75
|
+
scopes,
|
|
76
|
+
prompt: input.prompt,
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
url,
|
|
80
|
+
transient: {
|
|
81
|
+
state,
|
|
82
|
+
codeVerifier,
|
|
83
|
+
nonce,
|
|
84
|
+
provider: this.provider.id,
|
|
85
|
+
redirectUri: input.redirectUri,
|
|
86
|
+
createdAt: Date.now(),
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Completes a sign-in attempt from the provider callback: enforces the max
|
|
92
|
+
* transient age, surfaces provider `error` callback params, verifies
|
|
93
|
+
* `state` with a timing-safe compare, exchanges the code, and (for OIDC
|
|
94
|
+
* providers) validates the id_token nonce — then returns the normalized
|
|
95
|
+
* profile.
|
|
96
|
+
*
|
|
97
|
+
* @throws {ExternalAuthError} with a code describing the failure — see
|
|
98
|
+
* {@link ExternalAuthErrorCode} for how app code should respond to each.
|
|
99
|
+
*/
|
|
100
|
+
async finish(input) {
|
|
101
|
+
const { transient } = input;
|
|
102
|
+
const providerId = this.provider.id;
|
|
103
|
+
if (transient.provider !== providerId) {
|
|
104
|
+
throw new ExternalAuthError(providerId, "configuration", `callback was given a transient started for provider ` +
|
|
105
|
+
`"${transient.provider}" — the app routed the callback to the ` +
|
|
106
|
+
`wrong flow. Route each provider's callback to the flow built ` +
|
|
107
|
+
`with that provider.`);
|
|
108
|
+
}
|
|
109
|
+
if (Date.now() - transient.createdAt > this.#maxTransientAgeMs) {
|
|
110
|
+
throw new ExternalAuthError(providerId, "transient_expired", `sign-in attempt expired (older than ${this.#maxTransientAgeMs}ms). ` +
|
|
111
|
+
`Ask the user to start signing in again.`);
|
|
112
|
+
}
|
|
113
|
+
const params = toSearchParams(input.params);
|
|
114
|
+
const state = params.get("state");
|
|
115
|
+
if (!state) {
|
|
116
|
+
throw new ExternalAuthError(providerId, "invalid_callback", `callback is missing the "state" parameter — the URL is not a ` +
|
|
117
|
+
`provider callback, or the provider dropped the state.`);
|
|
118
|
+
}
|
|
119
|
+
if (!timingSafeEqualString(state, transient.state)) {
|
|
120
|
+
throw new ExternalAuthError(providerId, "state_mismatch", `callback "state" does not match this sign-in attempt — possible ` +
|
|
121
|
+
`CSRF, or a stale/mixed-up attempt. Ask the user to start again.`);
|
|
122
|
+
}
|
|
123
|
+
const providerError = params.get("error");
|
|
124
|
+
if (providerError) {
|
|
125
|
+
const description = params.get("error_description");
|
|
126
|
+
throw new ExternalAuthError(providerId, "provider_error", `provider returned an error on the callback: "${providerError}"` +
|
|
127
|
+
(description ? ` (${description})` : "") +
|
|
128
|
+
`. "access_denied" means the user cancelled; ` +
|
|
129
|
+
`"redirect_uri_mismatch" means the redirectUri is not registered ` +
|
|
130
|
+
`with the provider exactly as sent.`);
|
|
131
|
+
}
|
|
132
|
+
const code = params.get("code");
|
|
133
|
+
if (!code) {
|
|
134
|
+
throw new ExternalAuthError(providerId, "invalid_callback", `callback is missing the "code" parameter.`);
|
|
135
|
+
}
|
|
136
|
+
return await this.provider.fetchProfile({
|
|
137
|
+
code,
|
|
138
|
+
redirectUri: transient.redirectUri,
|
|
139
|
+
codeVerifier: transient.codeVerifier,
|
|
140
|
+
nonce: transient.nonce,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function toSearchParams(input) {
|
|
145
|
+
if (input instanceof URLSearchParams)
|
|
146
|
+
return input;
|
|
147
|
+
if (input instanceof URL)
|
|
148
|
+
return input.searchParams;
|
|
149
|
+
try {
|
|
150
|
+
return new URL(input).searchParams;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
const queryStart = input.indexOf("?");
|
|
154
|
+
const query = queryStart === -1 ? input : input.slice(queryStart + 1);
|
|
155
|
+
const hashStart = query.indexOf("#");
|
|
156
|
+
return new URLSearchParams(hashStart === -1 ? query : query.slice(0, hashStart));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub connector: plain OAuth2 (GitHub is not an OIDC provider), with the
|
|
3
|
+
* profile assembled from the REST API's `/user` and `/user/emails` endpoints.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
import type { ExternalProvider } from "./provider.js";
|
|
8
|
+
/** Options for {@link githubProvider}. */
|
|
9
|
+
export interface GithubProviderOptions {
|
|
10
|
+
/** Client ID of the GitHub OAuth App (or GitHub App). */
|
|
11
|
+
clientId: string;
|
|
12
|
+
/** The matching client secret. */
|
|
13
|
+
clientSecret: string;
|
|
14
|
+
/** Scopes requested by default. Defaults to `["read:user", "user:email"]`. */
|
|
15
|
+
scopes?: string[];
|
|
16
|
+
/** Fetch implementation for all provider traffic. Defaults to `globalThis.fetch`. */
|
|
17
|
+
fetch?: typeof fetch;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates a GitHub connector with id `"github"`.
|
|
21
|
+
*
|
|
22
|
+
* GitHub speaks plain OAuth2 (no discovery, no id_token, no PKCE for OAuth
|
|
23
|
+
* Apps), so the connector uses GitHub's fixed endpoints and builds the
|
|
24
|
+
* profile from `GET /user` plus `GET /user/emails`: the primary email is used
|
|
25
|
+
* (falling back to the first verified, then the first listed), and
|
|
26
|
+
* `emailVerified` reflects GitHub's flag for whichever email was chosen. When
|
|
27
|
+
* `/user/emails` is unavailable (e.g. the `user:email` scope was not granted),
|
|
28
|
+
* the public profile email is used with `emailVerified: false`. The `/user`
|
|
29
|
+
* payload (plus an `emails` array when fetched) is available on
|
|
30
|
+
* {@link ExternalProfile.raw}.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const flow = new ExternalAuthFlow({
|
|
35
|
+
* provider: githubProvider({
|
|
36
|
+
* clientId: Deno.env.get("GITHUB_CLIENT_ID")!,
|
|
37
|
+
* clientSecret: Deno.env.get("GITHUB_CLIENT_SECRET")!,
|
|
38
|
+
* }),
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function githubProvider(options: GithubProviderOptions): ExternalProvider;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub connector: plain OAuth2 (GitHub is not an OIDC provider), with the
|
|
3
|
+
* profile assembled from the REST API's `/user` and `/user/emails` endpoints.
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
import { describeError } from "./_shared.js";
|
|
8
|
+
import { runTokenExchange } from "./_token-exchange.js";
|
|
9
|
+
import { ExternalAuthError } from "./errors.js";
|
|
10
|
+
const GITHUB_AUTHORIZE_URL = "https://github.com/login/oauth/authorize";
|
|
11
|
+
const GITHUB_TOKEN_URL = "https://github.com/login/oauth/access_token";
|
|
12
|
+
const GITHUB_USER_URL = "https://api.github.com/user";
|
|
13
|
+
const GITHUB_EMAILS_URL = "https://api.github.com/user/emails";
|
|
14
|
+
/**
|
|
15
|
+
* Creates a GitHub connector with id `"github"`.
|
|
16
|
+
*
|
|
17
|
+
* GitHub speaks plain OAuth2 (no discovery, no id_token, no PKCE for OAuth
|
|
18
|
+
* Apps), so the connector uses GitHub's fixed endpoints and builds the
|
|
19
|
+
* profile from `GET /user` plus `GET /user/emails`: the primary email is used
|
|
20
|
+
* (falling back to the first verified, then the first listed), and
|
|
21
|
+
* `emailVerified` reflects GitHub's flag for whichever email was chosen. When
|
|
22
|
+
* `/user/emails` is unavailable (e.g. the `user:email` scope was not granted),
|
|
23
|
+
* the public profile email is used with `emailVerified: false`. The `/user`
|
|
24
|
+
* payload (plus an `emails` array when fetched) is available on
|
|
25
|
+
* {@link ExternalProfile.raw}.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const flow = new ExternalAuthFlow({
|
|
30
|
+
* provider: githubProvider({
|
|
31
|
+
* clientId: Deno.env.get("GITHUB_CLIENT_ID")!,
|
|
32
|
+
* clientSecret: Deno.env.get("GITHUB_CLIENT_SECRET")!,
|
|
33
|
+
* }),
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export function githubProvider(options) {
|
|
38
|
+
const id = "github";
|
|
39
|
+
const fetchImpl = (input, init) => (options.fetch ?? globalThis.fetch)(input, init);
|
|
40
|
+
async function exchangeCode(input) {
|
|
41
|
+
const { value } = await runTokenExchange({
|
|
42
|
+
provider: id,
|
|
43
|
+
displayName: "GitHub",
|
|
44
|
+
endpoint: GITHUB_TOKEN_URL,
|
|
45
|
+
body: new URLSearchParams({
|
|
46
|
+
client_id: options.clientId,
|
|
47
|
+
client_secret: options.clientSecret,
|
|
48
|
+
code: input.code,
|
|
49
|
+
redirect_uri: input.redirectUri,
|
|
50
|
+
}),
|
|
51
|
+
requiredField: "access_token",
|
|
52
|
+
fetch: fetchImpl,
|
|
53
|
+
httpErrorHint: `Check that clientId/clientSecret match the GitHub ` +
|
|
54
|
+
`OAuth App and try again.`,
|
|
55
|
+
tokenErrorHint: githubTokenErrorHint,
|
|
56
|
+
});
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
async function getJson(url, accessToken) {
|
|
60
|
+
let res;
|
|
61
|
+
try {
|
|
62
|
+
res = await fetchImpl(url, {
|
|
63
|
+
headers: {
|
|
64
|
+
Authorization: `Bearer ${accessToken}`,
|
|
65
|
+
Accept: "application/vnd.github+json",
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
throw new ExternalAuthError(id, "provider_error", `could not reach ${url} (${describeError(error)}). Try again.`, { cause: error });
|
|
71
|
+
}
|
|
72
|
+
if (!res.ok) {
|
|
73
|
+
await res.body?.cancel();
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
return await res.json();
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
throw new ExternalAuthError(id, "provider_error", `${url} returned a response that was not valid JSON ` +
|
|
81
|
+
`(${describeError(error)}).`, { cause: error });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
id,
|
|
86
|
+
displayName: "GitHub",
|
|
87
|
+
defaultScopes: options.scopes ?? ["read:user", "user:email"],
|
|
88
|
+
usesPkce: false,
|
|
89
|
+
usesNonce: false,
|
|
90
|
+
buildAuthorizationUrl(input) {
|
|
91
|
+
const url = new URL(GITHUB_AUTHORIZE_URL);
|
|
92
|
+
url.searchParams.set("client_id", options.clientId);
|
|
93
|
+
url.searchParams.set("redirect_uri", input.redirectUri);
|
|
94
|
+
url.searchParams.set("scope", input.scopes.join(" "));
|
|
95
|
+
url.searchParams.set("state", input.state);
|
|
96
|
+
if (input.prompt)
|
|
97
|
+
url.searchParams.set("prompt", input.prompt);
|
|
98
|
+
return Promise.resolve(url.toString());
|
|
99
|
+
},
|
|
100
|
+
async fetchProfile(input) {
|
|
101
|
+
const accessToken = await exchangeCode(input);
|
|
102
|
+
const [user, emailsRaw] = await Promise.all([
|
|
103
|
+
getJson(GITHUB_USER_URL, accessToken),
|
|
104
|
+
getJson(GITHUB_EMAILS_URL, accessToken),
|
|
105
|
+
]);
|
|
106
|
+
if (!user || user.id === undefined || user.id === null) {
|
|
107
|
+
throw new ExternalAuthError(id, "provider_error", `could not load the user profile from ${GITHUB_USER_URL}. The ` +
|
|
108
|
+
`access token was issued but lacks profile access — ensure the ` +
|
|
109
|
+
`"read:user" scope is requested.`);
|
|
110
|
+
}
|
|
111
|
+
const emails = parseGithubEmails(emailsRaw);
|
|
112
|
+
const chosen = emails?.find((entry) => entry.primary) ??
|
|
113
|
+
emails?.find((entry) => entry.verified) ?? emails?.[0];
|
|
114
|
+
const publicEmail = typeof user.email === "string"
|
|
115
|
+
? user.email
|
|
116
|
+
: undefined;
|
|
117
|
+
return {
|
|
118
|
+
provider: id,
|
|
119
|
+
subject: String(user.id),
|
|
120
|
+
email: chosen?.email ?? publicEmail,
|
|
121
|
+
emailVerified: chosen?.verified === true,
|
|
122
|
+
name: typeof user.name === "string" ? user.name : undefined,
|
|
123
|
+
picture: typeof user.avatar_url === "string"
|
|
124
|
+
? user.avatar_url
|
|
125
|
+
: undefined,
|
|
126
|
+
raw: Array.isArray(emailsRaw) ? { ...user, emails: emailsRaw } : user,
|
|
127
|
+
};
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function parseGithubEmails(raw) {
|
|
132
|
+
if (!Array.isArray(raw))
|
|
133
|
+
return null;
|
|
134
|
+
const entries = [];
|
|
135
|
+
for (const entry of raw) {
|
|
136
|
+
if (typeof entry !== "object" || entry === null)
|
|
137
|
+
continue;
|
|
138
|
+
const { email, primary, verified } = entry;
|
|
139
|
+
if (typeof email !== "string" || email.length === 0)
|
|
140
|
+
continue;
|
|
141
|
+
entries.push({
|
|
142
|
+
email,
|
|
143
|
+
primary: primary === true,
|
|
144
|
+
verified: verified === true,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return entries;
|
|
148
|
+
}
|
|
149
|
+
function githubTokenErrorHint(error) {
|
|
150
|
+
if (error === "incorrect_client_credentials") {
|
|
151
|
+
return `Check clientId/clientSecret against the GitHub OAuth App ` +
|
|
152
|
+
`settings.`;
|
|
153
|
+
}
|
|
154
|
+
if (error === "redirect_uri_mismatch") {
|
|
155
|
+
return `The redirectUri must exactly match the "Authorization callback ` +
|
|
156
|
+
`URL" configured on the GitHub OAuth App.`;
|
|
157
|
+
}
|
|
158
|
+
if (error === "bad_verification_code") {
|
|
159
|
+
return `The code expired or was already used — ask the user to start ` +
|
|
160
|
+
`signing in again.`;
|
|
161
|
+
}
|
|
162
|
+
return `See https://docs.github.com/apps/oauth-apps for the error's ` +
|
|
163
|
+
`meaning.`;
|
|
164
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google sign-in preset over the generic {@link oidcProvider} connector.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { DiscoveryCache } from "../../client/discovery-cache.js";
|
|
7
|
+
import type { AzpPolicy } from "./_shared.js";
|
|
8
|
+
import type { ExternalProvider } from "./provider.js";
|
|
9
|
+
/** Options for {@link googleProvider}. */
|
|
10
|
+
export interface GoogleProviderOptions {
|
|
11
|
+
/** OAuth client ID from the Google Cloud console ("Web application" type). */
|
|
12
|
+
clientId: string;
|
|
13
|
+
/** The matching OAuth client secret. */
|
|
14
|
+
clientSecret: string;
|
|
15
|
+
/** Scopes requested by default. Defaults to `["openid", "email", "profile"]`. */
|
|
16
|
+
scopes?: string[];
|
|
17
|
+
/**
|
|
18
|
+
* How the id_token's `azp` claim is checked. Defaults to `"conditional"`.
|
|
19
|
+
* Google's cross-client identity is the case for `"ignore"`: a token minted
|
|
20
|
+
* for another client of the same project reports that client in `azp` while
|
|
21
|
+
* `aud` is this one. See {@link AzpPolicy}.
|
|
22
|
+
*/
|
|
23
|
+
azp?: AzpPolicy;
|
|
24
|
+
/** Fetch implementation for all provider traffic. Defaults to `globalThis.fetch`. */
|
|
25
|
+
fetch?: typeof fetch;
|
|
26
|
+
/**
|
|
27
|
+
* Cache Google's discovery document is read from and written to, shared with
|
|
28
|
+
* any other connector given the same instance. Supply one when the connector
|
|
29
|
+
* is rebuilt per request. See {@link OidcProviderOptions.discoveryCache}.
|
|
30
|
+
*/
|
|
31
|
+
discoveryCache?: DiscoveryCache;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Creates a Google connector: the generic OIDC connector pinned to issuer
|
|
35
|
+
* `https://accounts.google.com` with id `"google"`.
|
|
36
|
+
*
|
|
37
|
+
* Claim mapping follows the OIDC normalization: `emailVerified` is `true`
|
|
38
|
+
* only when Google asserts `email_verified: true`, and Google-specific claims
|
|
39
|
+
* such as `hd` (the Workspace domain) stay available on
|
|
40
|
+
* {@link ExternalProfile.raw}.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* const flow = new ExternalAuthFlow({
|
|
45
|
+
* provider: googleProvider({
|
|
46
|
+
* clientId: Deno.env.get("GOOGLE_CLIENT_ID")!,
|
|
47
|
+
* clientSecret: Deno.env.get("GOOGLE_CLIENT_SECRET")!,
|
|
48
|
+
* }),
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function googleProvider(options: GoogleProviderOptions): ExternalProvider;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google sign-in preset over the generic {@link oidcProvider} connector.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { oidcProvider } from "./oidc.js";
|
|
7
|
+
/**
|
|
8
|
+
* Creates a Google connector: the generic OIDC connector pinned to issuer
|
|
9
|
+
* `https://accounts.google.com` with id `"google"`.
|
|
10
|
+
*
|
|
11
|
+
* Claim mapping follows the OIDC normalization: `emailVerified` is `true`
|
|
12
|
+
* only when Google asserts `email_verified: true`, and Google-specific claims
|
|
13
|
+
* such as `hd` (the Workspace domain) stay available on
|
|
14
|
+
* {@link ExternalProfile.raw}.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const flow = new ExternalAuthFlow({
|
|
19
|
+
* provider: googleProvider({
|
|
20
|
+
* clientId: Deno.env.get("GOOGLE_CLIENT_ID")!,
|
|
21
|
+
* clientSecret: Deno.env.get("GOOGLE_CLIENT_SECRET")!,
|
|
22
|
+
* }),
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function googleProvider(options) {
|
|
27
|
+
return oidcProvider({
|
|
28
|
+
id: "google",
|
|
29
|
+
displayName: "Google",
|
|
30
|
+
issuer: "https://accounts.google.com",
|
|
31
|
+
clientId: options.clientId,
|
|
32
|
+
clientSecret: options.clientSecret,
|
|
33
|
+
scopes: options.scopes,
|
|
34
|
+
azp: options.azp,
|
|
35
|
+
fetch: options.fetch,
|
|
36
|
+
discoveryCache: options.discoveryCache,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External-provider (social login) connectors: a storage-free flow that turns
|
|
3
|
+
* "Sign in with Google/GitHub/any OIDC provider" into a verified, normalized
|
|
4
|
+
* {@link ExternalProfile}.
|
|
5
|
+
*
|
|
6
|
+
* The library's job ends at the profile. It stores nothing — the only state
|
|
7
|
+
* is the JSON-serializable {@link ExternalAuthTransient} the caller keeps in a
|
|
8
|
+
* cookie or session between {@link ExternalAuthFlow.start} and
|
|
9
|
+
* {@link ExternalAuthFlow.finish} — and it takes no position on what the app
|
|
10
|
+
* does with the profile (create a user, link an account, reject): key
|
|
11
|
+
* identities by `(provider, subject)` in your own storage.
|
|
12
|
+
*
|
|
13
|
+
* - {@link ExternalAuthFlow} — the two-step redirect flow (start → finish)
|
|
14
|
+
* with CSRF state, PKCE, nonce, and transient-expiry handling built in.
|
|
15
|
+
* - {@link oidcProvider} — generic OpenID Connect connector via discovery.
|
|
16
|
+
* - {@link oauth2Provider} — generic plain-OAuth2 connector (no discovery / no
|
|
17
|
+
* id_token) for providers {@link oidcProvider} cannot cover.
|
|
18
|
+
* - {@link googleProvider} / {@link githubProvider} / {@link discordProvider} /
|
|
19
|
+
* {@link appleProvider} — presets for the most common providers.
|
|
20
|
+
* - {@link ExternalProvider} — the small interface to implement for any
|
|
21
|
+
* provider the built-ins don't cover.
|
|
22
|
+
* - {@link ExternalAuthError} — diagnosable failures; every message names the
|
|
23
|
+
* provider, what failed, and the likely fix.
|
|
24
|
+
* - {@link MemoryDiscoveryCache} — hand one to every OIDC connector a server
|
|
25
|
+
* rebuilds per request so they share a discovery fetch instead of each
|
|
26
|
+
* making their own.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import {
|
|
31
|
+
* ExternalAuthFlow,
|
|
32
|
+
* googleProvider,
|
|
33
|
+
* } from "@udibo/oauth2/identity/external";
|
|
34
|
+
*
|
|
35
|
+
* const google = new ExternalAuthFlow({
|
|
36
|
+
* provider: googleProvider({ clientId, clientSecret }),
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* // Route 1: redirect the user out.
|
|
40
|
+
* const { url, transient } = await google.start({ redirectUri });
|
|
41
|
+
* // …persist `transient` in a sealed cookie, redirect to `url`.
|
|
42
|
+
*
|
|
43
|
+
* // Route 2: the callback.
|
|
44
|
+
* const profile = await google.finish({ params: callbackUrl, transient });
|
|
45
|
+
* // …app code: find-or-create the user for (profile.provider,
|
|
46
|
+
* // profile.subject) and start a session.
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @module
|
|
50
|
+
*/
|
|
51
|
+
import "../../_dnt.polyfills.js";
|
|
52
|
+
export { ExternalAuthError, type ExternalAuthErrorCode, isExternalAuthError, } from "./errors.js";
|
|
53
|
+
export type { ExternalAuthorizationUrlInput, ExternalAuthTransient, ExternalProfile, ExternalProfileInput, ExternalProvider, } from "./provider.js";
|
|
54
|
+
export { DEFAULT_MAX_TRANSIENT_AGE_MS, type ExternalAuthFinishInput, ExternalAuthFlow, type ExternalAuthFlowOptions, type ExternalAuthStartInput, type ExternalAuthStartResult, } from "./flow.js";
|
|
55
|
+
export { oidcProvider, type OidcProviderOptions } from "./oidc.js";
|
|
56
|
+
export type { AzpPolicy } from "./_shared.js";
|
|
57
|
+
export { DEFAULT_DISCOVERY_CACHE_MAX_ENTRIES, DEFAULT_DISCOVERY_TTL_MS, type DiscoveryCache, type DiscoveryCacheEntry, MemoryDiscoveryCache, type MemoryDiscoveryCacheOptions, } from "../../client/discovery-cache.js";
|
|
58
|
+
export { googleProvider, type GoogleProviderOptions } from "./google.js";
|
|
59
|
+
export { githubProvider, type GithubProviderOptions } from "./github.js";
|
|
60
|
+
export { type OAuth2ProfileMapper, type OAuth2ProfileMapping, oauth2Provider, type OAuth2ProviderOptions, type OAuth2TokenResult, } from "./oauth2.js";
|
|
61
|
+
export { discordProvider, type DiscordProviderOptions } from "./discord.js";
|
|
62
|
+
export { appleProvider, type AppleProviderOptions } from "./apple.js";
|
|
63
|
+
export { APPLE_AUDIENCE, APPLE_CLIENT_SECRET_MAX_TTL_SECONDS, type AppleClientSecretFactory, type AppleClientSecretOptions, createAppleClientSecretFactory, DEFAULT_APPLE_CLIENT_SECRET_TTL_SECONDS, generateAppleClientSecret, } from "./apple-client-secret.js";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External-provider (social login) connectors: a storage-free flow that turns
|
|
3
|
+
* "Sign in with Google/GitHub/any OIDC provider" into a verified, normalized
|
|
4
|
+
* {@link ExternalProfile}.
|
|
5
|
+
*
|
|
6
|
+
* The library's job ends at the profile. It stores nothing — the only state
|
|
7
|
+
* is the JSON-serializable {@link ExternalAuthTransient} the caller keeps in a
|
|
8
|
+
* cookie or session between {@link ExternalAuthFlow.start} and
|
|
9
|
+
* {@link ExternalAuthFlow.finish} — and it takes no position on what the app
|
|
10
|
+
* does with the profile (create a user, link an account, reject): key
|
|
11
|
+
* identities by `(provider, subject)` in your own storage.
|
|
12
|
+
*
|
|
13
|
+
* - {@link ExternalAuthFlow} — the two-step redirect flow (start → finish)
|
|
14
|
+
* with CSRF state, PKCE, nonce, and transient-expiry handling built in.
|
|
15
|
+
* - {@link oidcProvider} — generic OpenID Connect connector via discovery.
|
|
16
|
+
* - {@link oauth2Provider} — generic plain-OAuth2 connector (no discovery / no
|
|
17
|
+
* id_token) for providers {@link oidcProvider} cannot cover.
|
|
18
|
+
* - {@link googleProvider} / {@link githubProvider} / {@link discordProvider} /
|
|
19
|
+
* {@link appleProvider} — presets for the most common providers.
|
|
20
|
+
* - {@link ExternalProvider} — the small interface to implement for any
|
|
21
|
+
* provider the built-ins don't cover.
|
|
22
|
+
* - {@link ExternalAuthError} — diagnosable failures; every message names the
|
|
23
|
+
* provider, what failed, and the likely fix.
|
|
24
|
+
* - {@link MemoryDiscoveryCache} — hand one to every OIDC connector a server
|
|
25
|
+
* rebuilds per request so they share a discovery fetch instead of each
|
|
26
|
+
* making their own.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import {
|
|
31
|
+
* ExternalAuthFlow,
|
|
32
|
+
* googleProvider,
|
|
33
|
+
* } from "@udibo/oauth2/identity/external";
|
|
34
|
+
*
|
|
35
|
+
* const google = new ExternalAuthFlow({
|
|
36
|
+
* provider: googleProvider({ clientId, clientSecret }),
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* // Route 1: redirect the user out.
|
|
40
|
+
* const { url, transient } = await google.start({ redirectUri });
|
|
41
|
+
* // …persist `transient` in a sealed cookie, redirect to `url`.
|
|
42
|
+
*
|
|
43
|
+
* // Route 2: the callback.
|
|
44
|
+
* const profile = await google.finish({ params: callbackUrl, transient });
|
|
45
|
+
* // …app code: find-or-create the user for (profile.provider,
|
|
46
|
+
* // profile.subject) and start a session.
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @module
|
|
50
|
+
*/
|
|
51
|
+
import "../../_dnt.polyfills.js";
|
|
52
|
+
export { ExternalAuthError, isExternalAuthError, } from "./errors.js";
|
|
53
|
+
export { DEFAULT_MAX_TRANSIENT_AGE_MS, ExternalAuthFlow, } from "./flow.js";
|
|
54
|
+
export { oidcProvider } from "./oidc.js";
|
|
55
|
+
export { DEFAULT_DISCOVERY_CACHE_MAX_ENTRIES, DEFAULT_DISCOVERY_TTL_MS, MemoryDiscoveryCache, } from "../../client/discovery-cache.js";
|
|
56
|
+
export { googleProvider } from "./google.js";
|
|
57
|
+
export { githubProvider } from "./github.js";
|
|
58
|
+
export { oauth2Provider, } from "./oauth2.js";
|
|
59
|
+
export { discordProvider } from "./discord.js";
|
|
60
|
+
export { appleProvider } from "./apple.js";
|
|
61
|
+
export { APPLE_AUDIENCE, APPLE_CLIENT_SECRET_MAX_TTL_SECONDS, createAppleClientSecretFactory, DEFAULT_APPLE_CLIENT_SECRET_TTL_SECONDS, generateAppleClientSecret, } from "./apple-client-secret.js";
|