@atproto/oauth-provider 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/.postcssrc.yml +3 -0
- package/CHANGELOG.md +19 -0
- package/LICENSE.txt +7 -0
- package/dist/access-token/access-token-type.d.ts +6 -0
- package/dist/access-token/access-token-type.d.ts.map +1 -0
- package/dist/access-token/access-token-type.js +10 -0
- package/dist/access-token/access-token-type.js.map +1 -0
- package/dist/account/account-manager.d.ts +14 -0
- package/dist/account/account-manager.d.ts.map +1 -0
- package/dist/account/account-manager.js +39 -0
- package/dist/account/account-manager.js.map +1 -0
- package/dist/account/account-store.d.ts +39 -0
- package/dist/account/account-store.d.ts.map +1 -0
- package/dist/account/account-store.js +19 -0
- package/dist/account/account-store.js.map +1 -0
- package/dist/account/account.d.ts +8 -0
- package/dist/account/account.d.ts.map +1 -0
- package/dist/account/account.js +3 -0
- package/dist/account/account.js.map +1 -0
- package/dist/assets/app/bundle-manifest.json +22 -0
- package/dist/assets/app/main.css +3 -0
- package/dist/assets/app/main.js +20 -0
- package/dist/assets/app/main.js.map +1 -0
- package/dist/assets/asset.d.ts +9 -0
- package/dist/assets/asset.d.ts.map +1 -0
- package/dist/assets/asset.js +3 -0
- package/dist/assets/asset.js.map +1 -0
- package/dist/assets/assets-middleware.d.ts +2 -0
- package/dist/assets/assets-middleware.d.ts.map +1 -0
- package/dist/assets/assets-middleware.js +30 -0
- package/dist/assets/assets-middleware.js.map +1 -0
- package/dist/assets/index.d.ts +4 -0
- package/dist/assets/index.d.ts.map +1 -0
- package/dist/assets/index.js +65 -0
- package/dist/assets/index.js.map +1 -0
- package/dist/client/client-auth.d.ts +13 -0
- package/dist/client/client-auth.d.ts.map +1 -0
- package/dist/client/client-auth.js +35 -0
- package/dist/client/client-auth.js.map +1 -0
- package/dist/client/client-data.d.ts +8 -0
- package/dist/client/client-data.d.ts.map +1 -0
- package/dist/client/client-data.js +3 -0
- package/dist/client/client-data.js.map +1 -0
- package/dist/client/client-id.d.ts +4 -0
- package/dist/client/client-id.d.ts.map +1 -0
- package/dist/client/client-id.js +6 -0
- package/dist/client/client-id.js.map +1 -0
- package/dist/client/client-info.d.ts +13 -0
- package/dist/client/client-info.d.ts.map +1 -0
- package/dist/client/client-info.js +3 -0
- package/dist/client/client-info.js.map +1 -0
- package/dist/client/client-manager.d.ts +38 -0
- package/dist/client/client-manager.d.ts.map +1 -0
- package/dist/client/client-manager.js +534 -0
- package/dist/client/client-manager.js.map +1 -0
- package/dist/client/client-store.d.ts +13 -0
- package/dist/client/client-store.d.ts.map +1 -0
- package/dist/client/client-store.js +39 -0
- package/dist/client/client-store.js.map +1 -0
- package/dist/client/client-utils.d.ts +6 -0
- package/dist/client/client-utils.d.ts.map +1 -0
- package/dist/client/client-utils.js +40 -0
- package/dist/client/client-utils.js.map +1 -0
- package/dist/client/client.d.ts +41 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +163 -0
- package/dist/client/client.js.map +1 -0
- package/dist/constants.d.ts +42 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +53 -0
- package/dist/constants.js.map +1 -0
- package/dist/device/device-data.d.ts +20 -0
- package/dist/device/device-data.d.ts.map +1 -0
- package/dist/device/device-data.js +11 -0
- package/dist/device/device-data.js.map +1 -0
- package/dist/device/device-details.d.ts +17 -0
- package/dist/device/device-details.d.ts.map +1 -0
- package/dist/device/device-details.js +34 -0
- package/dist/device/device-details.js.map +1 -0
- package/dist/device/device-id.d.ts +6 -0
- package/dist/device/device-id.d.ts.map +1 -0
- package/dist/device/device-id.js +18 -0
- package/dist/device/device-id.js.map +1 -0
- package/dist/device/device-manager.d.ts +88 -0
- package/dist/device/device-manager.d.ts.map +1 -0
- package/dist/device/device-manager.js +206 -0
- package/dist/device/device-manager.js.map +1 -0
- package/dist/device/device-store.d.ts +15 -0
- package/dist/device/device-store.d.ts.map +1 -0
- package/dist/device/device-store.js +36 -0
- package/dist/device/device-store.js.map +1 -0
- package/dist/device/session-id.d.ts +6 -0
- package/dist/device/session-id.d.ts.map +1 -0
- package/dist/device/session-id.js +18 -0
- package/dist/device/session-id.js.map +1 -0
- package/dist/dpop/dpop-manager.d.ts +33 -0
- package/dist/dpop/dpop-manager.d.ts.map +1 -0
- package/dist/dpop/dpop-manager.js +115 -0
- package/dist/dpop/dpop-manager.js.map +1 -0
- package/dist/dpop/dpop-nonce.d.ts +13 -0
- package/dist/dpop/dpop-nonce.d.ts.map +1 -0
- package/dist/dpop/dpop-nonce.js +94 -0
- package/dist/dpop/dpop-nonce.js.map +1 -0
- package/dist/errors/access-denied-error.d.ts +8 -0
- package/dist/errors/access-denied-error.d.ts.map +1 -0
- package/dist/errors/access-denied-error.js +21 -0
- package/dist/errors/access-denied-error.js.map +1 -0
- package/dist/errors/account-selection-required-error.d.ts +6 -0
- package/dist/errors/account-selection-required-error.d.ts.map +1 -0
- package/dist/errors/account-selection-required-error.js +11 -0
- package/dist/errors/account-selection-required-error.js.map +1 -0
- package/dist/errors/consent-required-error.d.ts +6 -0
- package/dist/errors/consent-required-error.d.ts.map +1 -0
- package/dist/errors/consent-required-error.js +11 -0
- package/dist/errors/consent-required-error.js.map +1 -0
- package/dist/errors/invalid-authorization-details-error.d.ts +20 -0
- package/dist/errors/invalid-authorization-details-error.d.ts.map +1 -0
- package/dist/errors/invalid-authorization-details-error.js +26 -0
- package/dist/errors/invalid-authorization-details-error.js.map +1 -0
- package/dist/errors/invalid-client-error.d.ts +18 -0
- package/dist/errors/invalid-client-error.d.ts.map +1 -0
- package/dist/errors/invalid-client-error.js +24 -0
- package/dist/errors/invalid-client-error.js.map +1 -0
- package/dist/errors/invalid-client-id-error.d.ts +13 -0
- package/dist/errors/invalid-client-id-error.d.ts.map +1 -0
- package/dist/errors/invalid-client-id-error.js +25 -0
- package/dist/errors/invalid-client-id-error.js.map +1 -0
- package/dist/errors/invalid-client-metadata-error.d.ts +13 -0
- package/dist/errors/invalid-client-metadata-error.d.ts.map +1 -0
- package/dist/errors/invalid-client-metadata-error.js +23 -0
- package/dist/errors/invalid-client-metadata-error.js.map +1 -0
- package/dist/errors/invalid-dpop-key-binding-error.d.ts +12 -0
- package/dist/errors/invalid-dpop-key-binding-error.d.ts.map +1 -0
- package/dist/errors/invalid-dpop-key-binding-error.js +20 -0
- package/dist/errors/invalid-dpop-key-binding-error.js.map +1 -0
- package/dist/errors/invalid-dpop-proof-error.d.ts +5 -0
- package/dist/errors/invalid-dpop-proof-error.d.ts.map +1 -0
- package/dist/errors/invalid-dpop-proof-error.js +12 -0
- package/dist/errors/invalid-dpop-proof-error.js.map +1 -0
- package/dist/errors/invalid-grant-error.d.ts +14 -0
- package/dist/errors/invalid-grant-error.d.ts.map +1 -0
- package/dist/errors/invalid-grant-error.js +20 -0
- package/dist/errors/invalid-grant-error.js.map +1 -0
- package/dist/errors/invalid-parameters-error.d.ts +6 -0
- package/dist/errors/invalid-parameters-error.d.ts.map +1 -0
- package/dist/errors/invalid-parameters-error.js +11 -0
- package/dist/errors/invalid-parameters-error.js.map +1 -0
- package/dist/errors/invalid-redirect-uri-error.d.ts +11 -0
- package/dist/errors/invalid-redirect-uri-error.d.ts.map +1 -0
- package/dist/errors/invalid-redirect-uri-error.js +21 -0
- package/dist/errors/invalid-redirect-uri-error.js.map +1 -0
- package/dist/errors/invalid-request-error.d.ts +28 -0
- package/dist/errors/invalid-request-error.d.ts.map +1 -0
- package/dist/errors/invalid-request-error.js +34 -0
- package/dist/errors/invalid-request-error.js.map +1 -0
- package/dist/errors/invalid-token-error.d.ts +16 -0
- package/dist/errors/invalid-token-error.d.ts.map +1 -0
- package/dist/errors/invalid-token-error.js +45 -0
- package/dist/errors/invalid-token-error.js.map +1 -0
- package/dist/errors/login-required-error.d.ts +6 -0
- package/dist/errors/login-required-error.d.ts.map +1 -0
- package/dist/errors/login-required-error.js +11 -0
- package/dist/errors/login-required-error.js.map +1 -0
- package/dist/errors/oauth-error.d.ts +13 -0
- package/dist/errors/oauth-error.d.ts.map +1 -0
- package/dist/errors/oauth-error.js +29 -0
- package/dist/errors/oauth-error.js.map +1 -0
- package/dist/errors/unauthorized-client-error.d.ts +18 -0
- package/dist/errors/unauthorized-client-error.d.ts.map +1 -0
- package/dist/errors/unauthorized-client-error.js +24 -0
- package/dist/errors/unauthorized-client-error.js.map +1 -0
- package/dist/errors/use-dpop-nonce-error.d.ts +18 -0
- package/dist/errors/use-dpop-nonce-error.d.ts.map +1 -0
- package/dist/errors/use-dpop-nonce-error.js +27 -0
- package/dist/errors/use-dpop-nonce-error.js.map +1 -0
- package/dist/errors/www-authenticate-error.d.ts +9 -0
- package/dist/errors/www-authenticate-error.d.ts.map +1 -0
- package/dist/errors/www-authenticate-error.js +46 -0
- package/dist/errors/www-authenticate-error.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/html/build-document.d.ts +32 -0
- package/dist/lib/html/build-document.d.ts.map +1 -0
- package/dist/lib/html/build-document.js +61 -0
- package/dist/lib/html/build-document.js.map +1 -0
- package/dist/lib/html/escapers.d.ts +9 -0
- package/dist/lib/html/escapers.d.ts.map +1 -0
- package/dist/lib/html/escapers.js +66 -0
- package/dist/lib/html/escapers.js.map +1 -0
- package/dist/lib/html/html.d.ts +13 -0
- package/dist/lib/html/html.d.ts.map +1 -0
- package/dist/lib/html/html.js +53 -0
- package/dist/lib/html/html.js.map +1 -0
- package/dist/lib/html/index.d.ts +4 -0
- package/dist/lib/html/index.d.ts.map +1 -0
- package/dist/lib/html/index.js +21 -0
- package/dist/lib/html/index.js.map +1 -0
- package/dist/lib/html/tags.d.ts +34 -0
- package/dist/lib/html/tags.d.ts.map +1 -0
- package/dist/lib/html/tags.js +47 -0
- package/dist/lib/html/tags.js.map +1 -0
- package/dist/lib/html/util.d.ts +4 -0
- package/dist/lib/html/util.d.ts.map +1 -0
- package/dist/lib/html/util.js +20 -0
- package/dist/lib/html/util.js.map +1 -0
- package/dist/lib/http/accept.d.ts +29 -0
- package/dist/lib/http/accept.d.ts.map +1 -0
- package/dist/lib/http/accept.js +67 -0
- package/dist/lib/http/accept.js.map +1 -0
- package/dist/lib/http/context.d.ts +5 -0
- package/dist/lib/http/context.d.ts.map +1 -0
- package/dist/lib/http/context.js +10 -0
- package/dist/lib/http/context.js.map +1 -0
- package/dist/lib/http/index.d.ts +10 -0
- package/dist/lib/http/index.d.ts.map +1 -0
- package/dist/lib/http/index.js +26 -0
- package/dist/lib/http/index.js.map +1 -0
- package/dist/lib/http/method.d.ts +6 -0
- package/dist/lib/http/method.d.ts.map +1 -0
- package/dist/lib/http/method.js +19 -0
- package/dist/lib/http/method.js.map +1 -0
- package/dist/lib/http/middleware.d.ts +18 -0
- package/dist/lib/http/middleware.d.ts.map +1 -0
- package/dist/lib/http/middleware.js +118 -0
- package/dist/lib/http/middleware.js.map +1 -0
- package/dist/lib/http/parser.d.ts +33 -0
- package/dist/lib/http/parser.d.ts.map +1 -0
- package/dist/lib/http/parser.js +48 -0
- package/dist/lib/http/parser.js.map +1 -0
- package/dist/lib/http/path.d.ts +9 -0
- package/dist/lib/http/path.d.ts.map +1 -0
- package/dist/lib/http/path.js +54 -0
- package/dist/lib/http/path.js.map +1 -0
- package/dist/lib/http/request.d.ts +33 -0
- package/dist/lib/http/request.d.ts.map +1 -0
- package/dist/lib/http/request.js +86 -0
- package/dist/lib/http/request.js.map +1 -0
- package/dist/lib/http/response.d.ts +13 -0
- package/dist/lib/http/response.d.ts.map +1 -0
- package/dist/lib/http/response.js +98 -0
- package/dist/lib/http/response.js.map +1 -0
- package/dist/lib/http/route.d.ts +25 -0
- package/dist/lib/http/route.d.ts.map +1 -0
- package/dist/lib/http/route.js +39 -0
- package/dist/lib/http/route.js.map +1 -0
- package/dist/lib/http/router.d.ts +32 -0
- package/dist/lib/http/router.d.ts.map +1 -0
- package/dist/lib/http/router.js +74 -0
- package/dist/lib/http/router.js.map +1 -0
- package/dist/lib/http/stream.d.ts +13 -0
- package/dist/lib/http/stream.d.ts.map +1 -0
- package/dist/lib/http/stream.js +46 -0
- package/dist/lib/http/stream.js.map +1 -0
- package/dist/lib/http/types.d.ts +7 -0
- package/dist/lib/http/types.d.ts.map +1 -0
- package/dist/lib/http/types.js +3 -0
- package/dist/lib/http/types.js.map +1 -0
- package/dist/lib/http/url.d.ts +8 -0
- package/dist/lib/http/url.d.ts.map +1 -0
- package/dist/lib/http/url.js +22 -0
- package/dist/lib/http/url.js.map +1 -0
- package/dist/lib/redis.d.ts +5 -0
- package/dist/lib/redis.d.ts.map +1 -0
- package/dist/lib/redis.js +22 -0
- package/dist/lib/redis.js.map +1 -0
- package/dist/lib/util/authorization-header.d.ts +4 -0
- package/dist/lib/util/authorization-header.d.ts.map +1 -0
- package/dist/lib/util/authorization-header.js +23 -0
- package/dist/lib/util/authorization-header.js.map +1 -0
- package/dist/lib/util/cast.d.ts +2 -0
- package/dist/lib/util/cast.d.ts.map +1 -0
- package/dist/lib/util/cast.js +10 -0
- package/dist/lib/util/cast.js.map +1 -0
- package/dist/lib/util/crypto.d.ts +3 -0
- package/dist/lib/util/crypto.d.ts.map +1 -0
- package/dist/lib/util/crypto.js +29 -0
- package/dist/lib/util/crypto.js.map +1 -0
- package/dist/lib/util/date.d.ts +3 -0
- package/dist/lib/util/date.d.ts.map +1 -0
- package/dist/lib/util/date.js +12 -0
- package/dist/lib/util/date.js.map +1 -0
- package/dist/lib/util/hostname.d.ts +6 -0
- package/dist/lib/util/hostname.d.ts.map +1 -0
- package/dist/lib/util/hostname.js +24 -0
- package/dist/lib/util/hostname.js.map +1 -0
- package/dist/lib/util/redirect-uri.d.ts +7 -0
- package/dist/lib/util/redirect-uri.d.ts.map +1 -0
- package/dist/lib/util/redirect-uri.js +44 -0
- package/dist/lib/util/redirect-uri.js.map +1 -0
- package/dist/lib/util/time.d.ts +6 -0
- package/dist/lib/util/time.d.ts.map +1 -0
- package/dist/lib/util/time.js +28 -0
- package/dist/lib/util/time.js.map +1 -0
- package/dist/lib/util/type.d.ts +6 -0
- package/dist/lib/util/type.d.ts.map +1 -0
- package/dist/lib/util/type.js +3 -0
- package/dist/lib/util/type.js.map +1 -0
- package/dist/lib/util/well-known.d.ts +3 -0
- package/dist/lib/util/well-known.d.ts.map +1 -0
- package/dist/lib/util/well-known.js +11 -0
- package/dist/lib/util/well-known.js.map +1 -0
- package/dist/metadata/build-metadata.d.ts +14 -0
- package/dist/metadata/build-metadata.d.ts.map +1 -0
- package/dist/metadata/build-metadata.js +132 -0
- package/dist/metadata/build-metadata.js.map +1 -0
- package/dist/oauth-client.d.ts +4 -0
- package/dist/oauth-client.d.ts.map +1 -0
- package/dist/oauth-client.js +19 -0
- package/dist/oauth-client.js.map +1 -0
- package/dist/oauth-dpop.d.ts +3 -0
- package/dist/oauth-dpop.d.ts.map +1 -0
- package/dist/oauth-dpop.js +19 -0
- package/dist/oauth-dpop.js.map +1 -0
- package/dist/oauth-errors.d.ts +20 -0
- package/dist/oauth-errors.d.ts.map +1 -0
- package/dist/oauth-errors.js +43 -0
- package/dist/oauth-errors.js.map +1 -0
- package/dist/oauth-hooks.d.ts +42 -0
- package/dist/oauth-hooks.d.ts.map +1 -0
- package/dist/oauth-hooks.js +3 -0
- package/dist/oauth-hooks.js.map +1 -0
- package/dist/oauth-provider.d.ts +179 -0
- package/dist/oauth-provider.d.ts.map +1 -0
- package/dist/oauth-provider.js +748 -0
- package/dist/oauth-provider.js.map +1 -0
- package/dist/oauth-store.d.ts +11 -0
- package/dist/oauth-store.d.ts.map +1 -0
- package/dist/oauth-store.js +27 -0
- package/dist/oauth-store.js.map +1 -0
- package/dist/oauth-verifier.d.ts +66 -0
- package/dist/oauth-verifier.d.ts.map +1 -0
- package/dist/oauth-verifier.js +94 -0
- package/dist/oauth-verifier.js.map +1 -0
- package/dist/oidc/claims.d.ts +16 -0
- package/dist/oidc/claims.d.ts.map +1 -0
- package/dist/oidc/claims.js +29 -0
- package/dist/oidc/claims.js.map +1 -0
- package/dist/oidc/sub.d.ts +4 -0
- package/dist/oidc/sub.d.ts.map +1 -0
- package/dist/oidc/sub.js +6 -0
- package/dist/oidc/sub.js.map +1 -0
- package/dist/oidc/userinfo.d.ts +7 -0
- package/dist/oidc/userinfo.d.ts.map +1 -0
- package/dist/oidc/userinfo.js +3 -0
- package/dist/oidc/userinfo.js.map +1 -0
- package/dist/output/build-error-payload.d.ts +6 -0
- package/dist/output/build-error-payload.d.ts.map +1 -0
- package/dist/output/build-error-payload.js +108 -0
- package/dist/output/build-error-payload.js.map +1 -0
- package/dist/output/customization.d.ts +37 -0
- package/dist/output/customization.d.ts.map +1 -0
- package/dist/output/customization.js +62 -0
- package/dist/output/customization.js.map +1 -0
- package/dist/output/send-authorize-page.d.ts +43 -0
- package/dist/output/send-authorize-page.d.ts.map +1 -0
- package/dist/output/send-authorize-page.js +49 -0
- package/dist/output/send-authorize-page.js.map +1 -0
- package/dist/output/send-authorize-redirect.d.ts +25 -0
- package/dist/output/send-authorize-redirect.d.ts.map +1 -0
- package/dist/output/send-authorize-redirect.js +72 -0
- package/dist/output/send-authorize-redirect.js.map +1 -0
- package/dist/output/send-error-page.d.ts +5 -0
- package/dist/output/send-error-page.d.ts.map +1 -0
- package/dist/output/send-error-page.js +31 -0
- package/dist/output/send-error-page.js.map +1 -0
- package/dist/output/send-web-page.d.ts +8 -0
- package/dist/output/send-web-page.d.ts.map +1 -0
- package/dist/output/send-web-page.js +48 -0
- package/dist/output/send-web-page.js.map +1 -0
- package/dist/parameters/claims-requested.d.ts +3 -0
- package/dist/parameters/claims-requested.d.ts.map +1 -0
- package/dist/parameters/claims-requested.js +77 -0
- package/dist/parameters/claims-requested.js.map +1 -0
- package/dist/parameters/oidc-payload.d.ts +31 -0
- package/dist/parameters/oidc-payload.d.ts.map +1 -0
- package/dist/parameters/oidc-payload.js +25 -0
- package/dist/parameters/oidc-payload.js.map +1 -0
- package/dist/replay/replay-manager.d.ts +10 -0
- package/dist/replay/replay-manager.d.ts.map +1 -0
- package/dist/replay/replay-manager.js +23 -0
- package/dist/replay/replay-manager.js.map +1 -0
- package/dist/replay/replay-store-memory.d.ts +11 -0
- package/dist/replay/replay-store-memory.d.ts.map +1 -0
- package/dist/replay/replay-store-memory.js +30 -0
- package/dist/replay/replay-store-memory.js.map +1 -0
- package/dist/replay/replay-store-redis.d.ts +16 -0
- package/dist/replay/replay-store-redis.d.ts.map +1 -0
- package/dist/replay/replay-store-redis.js +20 -0
- package/dist/replay/replay-store-redis.js.map +1 -0
- package/dist/replay/replay-store.d.ts +16 -0
- package/dist/replay/replay-store.d.ts.map +1 -0
- package/dist/replay/replay-store.js +22 -0
- package/dist/replay/replay-store.js.map +1 -0
- package/dist/request/code.d.ts +7 -0
- package/dist/request/code.d.ts.map +1 -0
- package/dist/request/code.js +20 -0
- package/dist/request/code.js.map +1 -0
- package/dist/request/request-data.d.ts +21 -0
- package/dist/request/request-data.d.ts.map +1 -0
- package/dist/request/request-data.js +6 -0
- package/dist/request/request-data.js.map +1 -0
- package/dist/request/request-id.d.ts +6 -0
- package/dist/request/request-id.d.ts.map +1 -0
- package/dist/request/request-id.js +18 -0
- package/dist/request/request-id.js.map +1 -0
- package/dist/request/request-info.d.ts +12 -0
- package/dist/request/request-info.d.ts.map +1 -0
- package/dist/request/request-info.js +3 -0
- package/dist/request/request-info.js.map +1 -0
- package/dist/request/request-manager.d.ts +40 -0
- package/dist/request/request-manager.d.ts.map +1 -0
- package/dist/request/request-manager.js +310 -0
- package/dist/request/request-manager.js.map +1 -0
- package/dist/request/request-store-memory.d.ts +16 -0
- package/dist/request/request-store-memory.d.ts.map +1 -0
- package/dist/request/request-store-memory.js +31 -0
- package/dist/request/request-store-memory.js.map +1 -0
- package/dist/request/request-store-redis.d.ts +24 -0
- package/dist/request/request-store-redis.d.ts.map +1 -0
- package/dist/request/request-store-redis.js +58 -0
- package/dist/request/request-store-redis.js.map +1 -0
- package/dist/request/request-store.d.ts +27 -0
- package/dist/request/request-store.d.ts.map +1 -0
- package/dist/request/request-store.js +37 -0
- package/dist/request/request-store.js.map +1 -0
- package/dist/request/request-uri.d.ts +8 -0
- package/dist/request/request-uri.d.ts.map +1 -0
- package/dist/request/request-uri.js +24 -0
- package/dist/request/request-uri.js.map +1 -0
- package/dist/request/types.d.ts +328 -0
- package/dist/request/types.d.ts.map +1 -0
- package/dist/request/types.js +27 -0
- package/dist/request/types.js.map +1 -0
- package/dist/signer/signed-token-payload.d.ts +1694 -0
- package/dist/signer/signed-token-payload.d.ts.map +1 -0
- package/dist/signer/signed-token-payload.js +32 -0
- package/dist/signer/signed-token-payload.js.map +1 -0
- package/dist/signer/signer.d.ts +193 -0
- package/dist/signer/signer.d.ts.map +1 -0
- package/dist/signer/signer.js +101 -0
- package/dist/signer/signer.js.map +1 -0
- package/dist/token/refresh-token.d.ts +7 -0
- package/dist/token/refresh-token.d.ts.map +1 -0
- package/dist/token/refresh-token.js +20 -0
- package/dist/token/refresh-token.js.map +1 -0
- package/dist/token/token-claims.d.ts +1687 -0
- package/dist/token/token-claims.d.ts.map +1 -0
- package/dist/token/token-claims.js +30 -0
- package/dist/token/token-claims.js.map +1 -0
- package/dist/token/token-data.d.ts +20 -0
- package/dist/token/token-data.d.ts.map +1 -0
- package/dist/token/token-data.js +3 -0
- package/dist/token/token-data.js.map +1 -0
- package/dist/token/token-id.d.ts +7 -0
- package/dist/token/token-id.d.ts.map +1 -0
- package/dist/token/token-id.js +20 -0
- package/dist/token/token-id.js.map +1 -0
- package/dist/token/token-manager.d.ts +48 -0
- package/dist/token/token-manager.d.ts.map +1 -0
- package/dist/token/token-manager.js +421 -0
- package/dist/token/token-manager.js.map +1 -0
- package/dist/token/token-store.d.ts +35 -0
- package/dist/token/token-store.d.ts.map +1 -0
- package/dist/token/token-store.js +38 -0
- package/dist/token/token-store.js.map +1 -0
- package/dist/token/types.d.ts +250 -0
- package/dist/token/types.d.ts.map +1 -0
- package/dist/token/types.js +36 -0
- package/dist/token/types.js.map +1 -0
- package/dist/token/verify-token-claims.d.ts +17 -0
- package/dist/token/verify-token-claims.d.ts.map +1 -0
- package/dist/token/verify-token-claims.js +39 -0
- package/dist/token/verify-token-claims.js.map +1 -0
- package/package.json +83 -0
- package/rollup.config.js +55 -0
- package/src/access-token/access-token-type.ts +5 -0
- package/src/account/account-manager.ts +55 -0
- package/src/account/account-store.ts +74 -0
- package/src/account/account.ts +10 -0
- package/src/assets/app/app.tsx +28 -0
- package/src/assets/app/backend-data.ts +65 -0
- package/src/assets/app/components/accept-form.tsx +112 -0
- package/src/assets/app/components/account-identifier.tsx +18 -0
- package/src/assets/app/components/account-picker.tsx +108 -0
- package/src/assets/app/components/client-identifier.tsx +32 -0
- package/src/assets/app/components/client-name.tsx +30 -0
- package/src/assets/app/components/error-card.tsx +41 -0
- package/src/assets/app/components/help-card.tsx +42 -0
- package/src/assets/app/components/layout-title-page.tsx +43 -0
- package/src/assets/app/components/layout-welcome.tsx +58 -0
- package/src/assets/app/components/sign-in-form.tsx +290 -0
- package/src/assets/app/components/sign-up-account-form.tsx +210 -0
- package/src/assets/app/components/sign-up-disclaimer.tsx +44 -0
- package/src/assets/app/components/url-viewer.tsx +70 -0
- package/src/assets/app/cookies.ts +11 -0
- package/src/assets/app/hooks/use-api.ts +104 -0
- package/src/assets/app/hooks/use-bound-dispatch.ts +5 -0
- package/src/assets/app/hooks/use-csrf-token.ts +5 -0
- package/src/assets/app/lib/api.ts +64 -0
- package/src/assets/app/lib/clsx.ts +4 -0
- package/src/assets/app/lib/util.ts +10 -0
- package/src/assets/app/main.css +11 -0
- package/src/assets/app/main.tsx +28 -0
- package/src/assets/app/views/accept-view.tsx +51 -0
- package/src/assets/app/views/authorize-view.tsx +101 -0
- package/src/assets/app/views/error-view.tsx +27 -0
- package/src/assets/app/views/sign-in-view.tsx +121 -0
- package/src/assets/app/views/sign-up-view.tsx +93 -0
- package/src/assets/app/views/welcome-view.tsx +61 -0
- package/src/assets/asset.ts +8 -0
- package/src/assets/assets-middleware.ts +32 -0
- package/src/assets/index.ts +74 -0
- package/src/client/client-auth.ts +45 -0
- package/src/client/client-data.ts +9 -0
- package/src/client/client-id.ts +4 -0
- package/src/client/client-info.ts +13 -0
- package/src/client/client-manager.ts +818 -0
- package/src/client/client-store.ts +38 -0
- package/src/client/client-utils.ts +43 -0
- package/src/client/client.ts +231 -0
- package/src/constants.ts +69 -0
- package/src/device/device-data.ts +11 -0
- package/src/device/device-details.ts +43 -0
- package/src/device/device-id.ts +23 -0
- package/src/device/device-manager.ts +287 -0
- package/src/device/device-store.ts +35 -0
- package/src/device/session-id.ts +22 -0
- package/src/dpop/dpop-manager.ts +147 -0
- package/src/dpop/dpop-nonce.ts +104 -0
- package/src/errors/access-denied-error.ts +26 -0
- package/src/errors/account-selection-required-error.ts +12 -0
- package/src/errors/consent-required-error.ts +12 -0
- package/src/errors/invalid-authorization-details-error.ts +22 -0
- package/src/errors/invalid-client-error.ts +20 -0
- package/src/errors/invalid-client-id-error.ts +20 -0
- package/src/errors/invalid-client-metadata-error.ts +19 -0
- package/src/errors/invalid-dpop-key-binding-error.ts +21 -0
- package/src/errors/invalid-dpop-proof-error.ts +13 -0
- package/src/errors/invalid-grant-error.ts +16 -0
- package/src/errors/invalid-parameters-error.ts +12 -0
- package/src/errors/invalid-redirect-uri-error.ts +17 -0
- package/src/errors/invalid-request-error.ts +30 -0
- package/src/errors/invalid-token-error.ts +59 -0
- package/src/errors/login-required-error.ts +12 -0
- package/src/errors/oauth-error.ts +28 -0
- package/src/errors/unauthorized-client-error.ts +20 -0
- package/src/errors/use-dpop-nonce-error.ts +32 -0
- package/src/errors/www-authenticate-error.ts +65 -0
- package/src/index.ts +15 -0
- package/src/lib/html/README.md +9 -0
- package/src/lib/html/build-document.ts +98 -0
- package/src/lib/html/escapers.ts +66 -0
- package/src/lib/html/html.ts +61 -0
- package/src/lib/html/index.ts +5 -0
- package/src/lib/html/tags.ts +58 -0
- package/src/lib/html/util.ts +21 -0
- package/src/lib/http/README.md +11 -0
- package/src/lib/http/accept.ts +91 -0
- package/src/lib/http/context.ts +11 -0
- package/src/lib/http/index.ts +9 -0
- package/src/lib/http/method.ts +18 -0
- package/src/lib/http/middleware.ts +183 -0
- package/src/lib/http/parser.ts +64 -0
- package/src/lib/http/path.ts +82 -0
- package/src/lib/http/request.ts +141 -0
- package/src/lib/http/response.ts +133 -0
- package/src/lib/http/route.ts +56 -0
- package/src/lib/http/router.ts +118 -0
- package/src/lib/http/stream.ts +78 -0
- package/src/lib/http/types.ts +22 -0
- package/src/lib/http/url.ts +23 -0
- package/src/lib/redis.ts +23 -0
- package/src/lib/util/authorization-header.ts +26 -0
- package/src/lib/util/cast.ts +4 -0
- package/src/lib/util/crypto.ts +27 -0
- package/src/lib/util/date.ts +7 -0
- package/src/lib/util/hostname.ts +19 -0
- package/src/lib/util/redirect-uri.ts +46 -0
- package/src/lib/util/time.ts +33 -0
- package/src/lib/util/type.ts +4 -0
- package/src/lib/util/well-known.ts +8 -0
- package/src/metadata/build-metadata.ts +165 -0
- package/src/oauth-client.ts +3 -0
- package/src/oauth-dpop.ts +2 -0
- package/src/oauth-errors.ts +21 -0
- package/src/oauth-hooks.ts +66 -0
- package/src/oauth-provider.ts +1409 -0
- package/src/oauth-store.ts +11 -0
- package/src/oauth-verifier.ts +219 -0
- package/src/oidc/claims.ts +35 -0
- package/src/oidc/sub.ts +4 -0
- package/src/oidc/userinfo.ts +11 -0
- package/src/output/build-error-payload.ts +143 -0
- package/src/output/customization.ts +96 -0
- package/src/output/send-authorize-page.ts +111 -0
- package/src/output/send-authorize-redirect.ts +130 -0
- package/src/output/send-error-page.ts +41 -0
- package/src/output/send-web-page.ts +66 -0
- package/src/parameters/claims-requested.ts +106 -0
- package/src/parameters/oidc-payload.ts +28 -0
- package/src/replay/replay-manager.ts +38 -0
- package/src/replay/replay-store-memory.ts +36 -0
- package/src/replay/replay-store-redis.ts +31 -0
- package/src/replay/replay-store.ts +44 -0
- package/src/request/code.ts +24 -0
- package/src/request/request-data.ts +26 -0
- package/src/request/request-id.ts +23 -0
- package/src/request/request-info.ts +12 -0
- package/src/request/request-manager.ts +479 -0
- package/src/request/request-store-memory.ts +39 -0
- package/src/request/request-store-redis.ts +71 -0
- package/src/request/request-store.ts +54 -0
- package/src/request/request-uri.ts +29 -0
- package/src/request/types.ts +48 -0
- package/src/signer/signed-token-payload.ts +35 -0
- package/src/signer/signer.ts +165 -0
- package/src/token/refresh-token.ts +31 -0
- package/src/token/token-claims.ts +31 -0
- package/src/token/token-data.ts +33 -0
- package/src/token/token-id.ts +26 -0
- package/src/token/token-manager.ts +591 -0
- package/src/token/token-store.ts +78 -0
- package/src/token/types.ts +86 -0
- package/src/token/verify-token-claims.ts +65 -0
- package/tailwind.config.js +13 -0
- package/tsconfig.backend.json +9 -0
- package/tsconfig.frontend.json +11 -0
- package/tsconfig.json +8 -0
- package/tsconfig.tools.json +8 -0
@@ -0,0 +1,479 @@
|
|
1
|
+
import {
|
2
|
+
CLIENT_ASSERTION_TYPE_JWT_BEARER,
|
3
|
+
OAuthAuthenticationRequestParameters,
|
4
|
+
OAuthAuthorizationServerMetadata,
|
5
|
+
} from '@atproto/oauth-types'
|
6
|
+
|
7
|
+
import { DeviceAccountInfo } from '../account/account-store.js'
|
8
|
+
import { Account } from '../account/account.js'
|
9
|
+
import { ClientAuth } from '../client/client-auth.js'
|
10
|
+
import { ClientId } from '../client/client-id.js'
|
11
|
+
import { Client } from '../client/client.js'
|
12
|
+
import {
|
13
|
+
AUTHORIZATION_INACTIVITY_TIMEOUT,
|
14
|
+
PAR_EXPIRES_IN,
|
15
|
+
TOKEN_MAX_AGE,
|
16
|
+
} from '../constants.js'
|
17
|
+
import { DeviceId } from '../device/device-id.js'
|
18
|
+
import { AccessDeniedError } from '../errors/access-denied-error.js'
|
19
|
+
import { ConsentRequiredError } from '../errors/consent-required-error.js'
|
20
|
+
import { InvalidGrantError } from '../errors/invalid-grant-error.js'
|
21
|
+
import { InvalidParametersError } from '../errors/invalid-parameters-error.js'
|
22
|
+
import { InvalidRequestError } from '../errors/invalid-request-error.js'
|
23
|
+
import { compareRedirectUri } from '../lib/util/redirect-uri.js'
|
24
|
+
import { OAuthHooks } from '../oauth-hooks.js'
|
25
|
+
import { OIDC_SCOPE_CLAIMS } from '../oidc/claims.js'
|
26
|
+
import { Signer } from '../signer/signer.js'
|
27
|
+
import { Code, generateCode } from './code.js'
|
28
|
+
import {
|
29
|
+
isRequestDataAuthorized,
|
30
|
+
RequestDataAuthorized,
|
31
|
+
} from './request-data.js'
|
32
|
+
import { generateRequestId } from './request-id.js'
|
33
|
+
import { RequestInfo } from './request-info.js'
|
34
|
+
import { RequestStore, UpdateRequestData } from './request-store.js'
|
35
|
+
import {
|
36
|
+
decodeRequestUri,
|
37
|
+
encodeRequestUri,
|
38
|
+
RequestUri,
|
39
|
+
} from './request-uri.js'
|
40
|
+
|
41
|
+
export class RequestManager {
|
42
|
+
constructor(
|
43
|
+
protected readonly store: RequestStore,
|
44
|
+
protected readonly signer: Signer,
|
45
|
+
protected readonly metadata: OAuthAuthorizationServerMetadata,
|
46
|
+
protected readonly hooks: OAuthHooks,
|
47
|
+
protected readonly pkceRequired = true,
|
48
|
+
protected readonly tokenMaxAge = TOKEN_MAX_AGE,
|
49
|
+
) {}
|
50
|
+
|
51
|
+
protected createTokenExpiry() {
|
52
|
+
return new Date(Date.now() + this.tokenMaxAge)
|
53
|
+
}
|
54
|
+
|
55
|
+
async createAuthorizationRequest(
|
56
|
+
client: Client,
|
57
|
+
clientAuth: ClientAuth,
|
58
|
+
input: Readonly<OAuthAuthenticationRequestParameters>,
|
59
|
+
deviceId: null | DeviceId,
|
60
|
+
dpopJkt: null | string,
|
61
|
+
): Promise<RequestInfo> {
|
62
|
+
const parameters = await this.validate(client, clientAuth, input, dpopJkt)
|
63
|
+
return this.create(client, clientAuth, parameters, deviceId)
|
64
|
+
}
|
65
|
+
|
66
|
+
protected async create(
|
67
|
+
client: Client,
|
68
|
+
clientAuth: ClientAuth,
|
69
|
+
parameters: Readonly<OAuthAuthenticationRequestParameters>,
|
70
|
+
deviceId: null | DeviceId = null,
|
71
|
+
): Promise<RequestInfo> {
|
72
|
+
const expiresAt = new Date(Date.now() + PAR_EXPIRES_IN)
|
73
|
+
const id = await generateRequestId()
|
74
|
+
|
75
|
+
await this.store.createRequest(id, {
|
76
|
+
clientId: client.id,
|
77
|
+
clientAuth,
|
78
|
+
parameters,
|
79
|
+
expiresAt,
|
80
|
+
deviceId,
|
81
|
+
sub: null,
|
82
|
+
code: null,
|
83
|
+
})
|
84
|
+
|
85
|
+
const uri = encodeRequestUri(id)
|
86
|
+
return { id, uri, expiresAt, parameters, clientAuth }
|
87
|
+
}
|
88
|
+
|
89
|
+
async validate(
|
90
|
+
client: Client,
|
91
|
+
clientAuth: ClientAuth,
|
92
|
+
parameters: Readonly<OAuthAuthenticationRequestParameters>,
|
93
|
+
dpopJkt: null | string,
|
94
|
+
pkceRequired = this.pkceRequired,
|
95
|
+
): Promise<Readonly<OAuthAuthenticationRequestParameters>> {
|
96
|
+
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10#section-1.4.1
|
97
|
+
// > The authorization server MAY fully or partially ignore the scope
|
98
|
+
// > requested by the client, based on the authorization server policy or
|
99
|
+
// > the resource owner's instructions. If the issued access token scope is
|
100
|
+
// > different from the one requested by the client, the authorization
|
101
|
+
// > server MUST include the scope response parameter in the token response
|
102
|
+
// > (Section 3.2.3) to inform the client of the actual scope granted.
|
103
|
+
|
104
|
+
const cScopes = client.metadata.scope?.split(' ')
|
105
|
+
const sScopes = this.metadata.scopes_supported
|
106
|
+
|
107
|
+
const scopes =
|
108
|
+
(parameters.scope || client.metadata.scope)
|
109
|
+
?.split(' ')
|
110
|
+
.filter((scope) => !!scope && (sScopes?.includes(scope) ?? true)) ?? []
|
111
|
+
|
112
|
+
for (const scope of scopes) {
|
113
|
+
if (!cScopes?.includes(scope)) {
|
114
|
+
throw new InvalidParametersError(
|
115
|
+
parameters,
|
116
|
+
`Scope "${scope}" is not registered for this client`,
|
117
|
+
)
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
for (const [scope, claims] of Object.entries(OIDC_SCOPE_CLAIMS)) {
|
122
|
+
for (const claim of claims) {
|
123
|
+
if (
|
124
|
+
parameters?.claims?.id_token?.[claim]?.essential === true ||
|
125
|
+
parameters?.claims?.userinfo?.[claim]?.essential === true
|
126
|
+
) {
|
127
|
+
if (!scopes?.includes(scope)) {
|
128
|
+
throw new InvalidParametersError(
|
129
|
+
parameters,
|
130
|
+
`Essential ${claim} claim requires "${scope}" scope`,
|
131
|
+
)
|
132
|
+
}
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
parameters = { ...parameters, scope: scopes.join(' ') }
|
138
|
+
|
139
|
+
const responseTypes = parameters.response_type.split(' ')
|
140
|
+
|
141
|
+
if (parameters.authorization_details) {
|
142
|
+
const clientAuthDetailsTypes = client.metadata.authorization_details_types
|
143
|
+
if (!clientAuthDetailsTypes) {
|
144
|
+
throw new InvalidParametersError(
|
145
|
+
parameters,
|
146
|
+
'Client Metadata does not declare any "authorization_details"',
|
147
|
+
)
|
148
|
+
}
|
149
|
+
|
150
|
+
for (const detail of parameters.authorization_details) {
|
151
|
+
if (!clientAuthDetailsTypes?.includes(detail.type)) {
|
152
|
+
throw new InvalidParametersError(
|
153
|
+
parameters,
|
154
|
+
`Unsupported "authorization_details" type "${detail.type}"`,
|
155
|
+
)
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
const { redirect_uri } = parameters
|
161
|
+
if (
|
162
|
+
redirect_uri &&
|
163
|
+
!client.metadata.redirect_uris.some((uri) =>
|
164
|
+
compareRedirectUri(uri, redirect_uri),
|
165
|
+
)
|
166
|
+
) {
|
167
|
+
throw new InvalidParametersError(
|
168
|
+
parameters,
|
169
|
+
`Invalid redirect_uri ${redirect_uri} (allowed: ${client.metadata.redirect_uris.join(' ')})`,
|
170
|
+
)
|
171
|
+
}
|
172
|
+
|
173
|
+
// https://datatracker.ietf.org/doc/html/rfc9449#section-10
|
174
|
+
if (!parameters.dpop_jkt) {
|
175
|
+
if (dpopJkt) parameters = { ...parameters, dpop_jkt: dpopJkt }
|
176
|
+
} else if (parameters.dpop_jkt !== dpopJkt) {
|
177
|
+
throw new InvalidParametersError(
|
178
|
+
parameters,
|
179
|
+
'DPoP header and dpop_jkt do not match',
|
180
|
+
)
|
181
|
+
}
|
182
|
+
|
183
|
+
if (clientAuth.method === CLIENT_ASSERTION_TYPE_JWT_BEARER) {
|
184
|
+
if (parameters.dpop_jkt && clientAuth.jkt === parameters.dpop_jkt) {
|
185
|
+
throw new InvalidParametersError(
|
186
|
+
parameters,
|
187
|
+
'The DPoP proof must be signed with a different key than the client assertion',
|
188
|
+
)
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
if (!client.metadata.response_types.includes(parameters.response_type)) {
|
193
|
+
throw new InvalidParametersError(
|
194
|
+
parameters,
|
195
|
+
`Unsupported response_type "${parameters.response_type}"`,
|
196
|
+
'unsupported_response_type',
|
197
|
+
)
|
198
|
+
}
|
199
|
+
|
200
|
+
if (pkceRequired && responseTypes.includes('token')) {
|
201
|
+
throw new InvalidParametersError(
|
202
|
+
parameters,
|
203
|
+
`Response type "${parameters.response_type}" is incompatible with PKCE`,
|
204
|
+
'unsupported_response_type',
|
205
|
+
)
|
206
|
+
}
|
207
|
+
|
208
|
+
// https://datatracker.ietf.org/doc/html/rfc7636#section-4.4.1
|
209
|
+
if (pkceRequired && !parameters.code_challenge) {
|
210
|
+
throw new InvalidParametersError(parameters, 'code_challenge is required')
|
211
|
+
}
|
212
|
+
|
213
|
+
if (
|
214
|
+
parameters.code_challenge &&
|
215
|
+
clientAuth.method === 'none' &&
|
216
|
+
(parameters.code_challenge_method ?? 'plain') === 'plain'
|
217
|
+
) {
|
218
|
+
throw new InvalidParametersError(
|
219
|
+
parameters,
|
220
|
+
'code_challenge_method=plain requires client authentication',
|
221
|
+
)
|
222
|
+
}
|
223
|
+
|
224
|
+
// https://datatracker.ietf.org/doc/html/rfc7636#section-4.3
|
225
|
+
if (parameters.code_challenge_method && !parameters.code_challenge) {
|
226
|
+
throw new InvalidParametersError(
|
227
|
+
parameters,
|
228
|
+
'code_challenge_method requires code_challenge',
|
229
|
+
)
|
230
|
+
}
|
231
|
+
|
232
|
+
// https://openid.net/specs/openid-connect-core-1_0.html#HybridAuthRequest
|
233
|
+
//
|
234
|
+
// > nonce: REQUIRED if the Response Type of the request is "code id_token" or
|
235
|
+
// > "code id_token token" and OPTIONAL when the Response Type of the
|
236
|
+
// > request is "code token". It is a string value used to associate a
|
237
|
+
// > Client session with an ID Token, and to mitigate replay attacks. The
|
238
|
+
// > value is passed through unmodified from the Authentication Request to
|
239
|
+
// > the ID Token. Sufficient entropy MUST be present in the nonce values
|
240
|
+
// > used to prevent attackers from guessing values. For implementation
|
241
|
+
// > notes, see Section 15.5.2.
|
242
|
+
if (responseTypes.includes('id_token') && !parameters.nonce) {
|
243
|
+
throw new InvalidParametersError(
|
244
|
+
parameters,
|
245
|
+
'nonce is required for implicit and hybrid flows',
|
246
|
+
)
|
247
|
+
}
|
248
|
+
|
249
|
+
// Make "expensive" checks after the "cheaper" checks
|
250
|
+
|
251
|
+
if (parameters.id_token_hint != null) {
|
252
|
+
const { payload } = await this.signer.verify(parameters.id_token_hint, {
|
253
|
+
// these are meant to be outdated when used as a hint
|
254
|
+
clockTolerance: Infinity,
|
255
|
+
})
|
256
|
+
|
257
|
+
if (!payload.sub) {
|
258
|
+
throw new InvalidParametersError(
|
259
|
+
parameters,
|
260
|
+
`Unexpected empty id_token_hint "sub"`,
|
261
|
+
)
|
262
|
+
} else if (parameters.login_hint == null) {
|
263
|
+
parameters = { ...parameters, login_hint: payload.sub }
|
264
|
+
} else if (parameters.login_hint !== payload.sub) {
|
265
|
+
throw new InvalidParametersError(
|
266
|
+
parameters,
|
267
|
+
'login_hint does not match "sub" of id_token_hint',
|
268
|
+
)
|
269
|
+
}
|
270
|
+
}
|
271
|
+
|
272
|
+
// ATPROTO extension: if the client is not trusted, force users to consent
|
273
|
+
// to authorization requests. We do this to avoid unauthenticated clients
|
274
|
+
// from being able to silently re-authenticate users.
|
275
|
+
if (clientAuth.method === 'none' && !client.info.isFirstParty) {
|
276
|
+
if (parameters.prompt === 'none') {
|
277
|
+
throw new ConsentRequiredError(
|
278
|
+
parameters,
|
279
|
+
'Public clients are not allowed to use silent-sign-on',
|
280
|
+
)
|
281
|
+
}
|
282
|
+
|
283
|
+
// force "consent" for unauthenticated, third party clients
|
284
|
+
parameters = { ...parameters, prompt: 'consent' }
|
285
|
+
}
|
286
|
+
|
287
|
+
return parameters
|
288
|
+
}
|
289
|
+
|
290
|
+
async get(
|
291
|
+
uri: RequestUri,
|
292
|
+
clientId: ClientId,
|
293
|
+
deviceId: DeviceId,
|
294
|
+
): Promise<RequestInfo> {
|
295
|
+
const id = decodeRequestUri(uri)
|
296
|
+
|
297
|
+
const data = await this.store.readRequest(id)
|
298
|
+
if (!data) throw new InvalidRequestError(`Unknown request_uri "${uri}"`)
|
299
|
+
|
300
|
+
const updates: UpdateRequestData = {}
|
301
|
+
|
302
|
+
try {
|
303
|
+
if (data.sub || data.code) {
|
304
|
+
// If an account was linked to the request, the next step is to exchange
|
305
|
+
// the code for a token.
|
306
|
+
throw new AccessDeniedError(
|
307
|
+
data.parameters,
|
308
|
+
'This request was already authorized',
|
309
|
+
)
|
310
|
+
}
|
311
|
+
|
312
|
+
if (data.expiresAt < new Date()) {
|
313
|
+
throw new AccessDeniedError(data.parameters, 'This request has expired')
|
314
|
+
} else {
|
315
|
+
updates.expiresAt = new Date(
|
316
|
+
Date.now() + AUTHORIZATION_INACTIVITY_TIMEOUT,
|
317
|
+
)
|
318
|
+
}
|
319
|
+
|
320
|
+
if (data.clientId !== clientId) {
|
321
|
+
throw new AccessDeniedError(
|
322
|
+
data.parameters,
|
323
|
+
'This request was initiated for another client',
|
324
|
+
)
|
325
|
+
}
|
326
|
+
|
327
|
+
if (!data.deviceId) {
|
328
|
+
updates.deviceId = deviceId
|
329
|
+
} else if (data.deviceId !== deviceId) {
|
330
|
+
throw new AccessDeniedError(
|
331
|
+
data.parameters,
|
332
|
+
'This request was initiated from another device',
|
333
|
+
)
|
334
|
+
}
|
335
|
+
} catch (err) {
|
336
|
+
await this.store.deleteRequest(id)
|
337
|
+
throw err
|
338
|
+
}
|
339
|
+
|
340
|
+
if (Object.keys(updates).length > 0) {
|
341
|
+
await this.store.updateRequest(id, updates)
|
342
|
+
}
|
343
|
+
|
344
|
+
return {
|
345
|
+
id,
|
346
|
+
uri,
|
347
|
+
expiresAt: updates.expiresAt || data.expiresAt,
|
348
|
+
parameters: data.parameters,
|
349
|
+
clientAuth: data.clientAuth,
|
350
|
+
}
|
351
|
+
}
|
352
|
+
|
353
|
+
async setAuthorized(
|
354
|
+
client: Client,
|
355
|
+
uri: RequestUri,
|
356
|
+
deviceId: DeviceId,
|
357
|
+
account: Account,
|
358
|
+
info: DeviceAccountInfo,
|
359
|
+
): Promise<{ code?: Code; token?: string; id_token?: string }> {
|
360
|
+
const id = decodeRequestUri(uri)
|
361
|
+
|
362
|
+
const data = await this.store.readRequest(id)
|
363
|
+
if (!data) throw new InvalidRequestError(`Unknown request_uri "${uri}"`)
|
364
|
+
|
365
|
+
try {
|
366
|
+
if (data.expiresAt < new Date()) {
|
367
|
+
throw new AccessDeniedError(data.parameters, 'This request has expired')
|
368
|
+
}
|
369
|
+
if (!data.deviceId) {
|
370
|
+
throw new AccessDeniedError(
|
371
|
+
data.parameters,
|
372
|
+
'This request was not initiated',
|
373
|
+
)
|
374
|
+
}
|
375
|
+
if (data.deviceId !== deviceId) {
|
376
|
+
throw new AccessDeniedError(
|
377
|
+
data.parameters,
|
378
|
+
'This request was initiated from another device',
|
379
|
+
)
|
380
|
+
}
|
381
|
+
if (data.sub || data.code) {
|
382
|
+
throw new AccessDeniedError(
|
383
|
+
data.parameters,
|
384
|
+
'This request was already authorized',
|
385
|
+
)
|
386
|
+
}
|
387
|
+
|
388
|
+
const responseType = data.parameters.response_type.split(' ')
|
389
|
+
|
390
|
+
if (responseType.includes('token')) {
|
391
|
+
throw new AccessDeniedError(
|
392
|
+
data.parameters,
|
393
|
+
'Implicit "token" forbidden (use "code" with PKCE instead)',
|
394
|
+
)
|
395
|
+
}
|
396
|
+
|
397
|
+
const code = responseType.includes('code')
|
398
|
+
? await generateCode()
|
399
|
+
: undefined
|
400
|
+
|
401
|
+
// Bind the request to the account, preventing it from being used again.
|
402
|
+
await this.store.updateRequest(id, {
|
403
|
+
sub: account.sub,
|
404
|
+
code,
|
405
|
+
// Allow the client to exchange the code for a token within the next 60 seconds.
|
406
|
+
expiresAt: new Date(Date.now() + AUTHORIZATION_INACTIVITY_TIMEOUT),
|
407
|
+
})
|
408
|
+
|
409
|
+
const id_token = responseType.includes('id_token')
|
410
|
+
? await this.signer.idToken(client, data.parameters, account, {
|
411
|
+
auth_time: info.authenticatedAt,
|
412
|
+
exp: this.createTokenExpiry(),
|
413
|
+
code,
|
414
|
+
})
|
415
|
+
: undefined
|
416
|
+
|
417
|
+
return { code, id_token }
|
418
|
+
} catch (err) {
|
419
|
+
await this.store.deleteRequest(id)
|
420
|
+
throw err
|
421
|
+
}
|
422
|
+
}
|
423
|
+
|
424
|
+
/**
|
425
|
+
* @note If this method throws an error, any token previously generated from
|
426
|
+
* the same `code` **must** me revoked.
|
427
|
+
*/
|
428
|
+
public async findCode(
|
429
|
+
client: Client,
|
430
|
+
clientAuth: ClientAuth,
|
431
|
+
code: Code,
|
432
|
+
): Promise<RequestDataAuthorized> {
|
433
|
+
const result = await this.store.findRequestByCode(code)
|
434
|
+
if (!result) throw new InvalidGrantError('Invalid code')
|
435
|
+
|
436
|
+
try {
|
437
|
+
const { data } = result
|
438
|
+
|
439
|
+
if (!isRequestDataAuthorized(data)) {
|
440
|
+
// Should never happen: maybe the store implementation is faulty ?
|
441
|
+
throw new Error('Unexpected request state')
|
442
|
+
}
|
443
|
+
|
444
|
+
if (data.clientId !== client.id) {
|
445
|
+
throw new InvalidGrantError('This code was issued for another client')
|
446
|
+
}
|
447
|
+
|
448
|
+
if (data.expiresAt < new Date()) {
|
449
|
+
throw new InvalidGrantError('This code has expired')
|
450
|
+
}
|
451
|
+
|
452
|
+
if (data.clientAuth.method === 'none') {
|
453
|
+
// If the client did not use PAR, it was not authenticated when the
|
454
|
+
// request was created (see authorize() method above). Since PAR is not
|
455
|
+
// mandatory, and since the token exchange currently taking place *is*
|
456
|
+
// authenticated (`clientAuth`), we allow "upgrading" the authentication
|
457
|
+
// method (the token created will be bound to the current clientAuth).
|
458
|
+
} else {
|
459
|
+
if (clientAuth.method !== data.clientAuth.method) {
|
460
|
+
throw new InvalidGrantError('Invalid client authentication')
|
461
|
+
}
|
462
|
+
|
463
|
+
if (!(await client.validateClientAuth(data.clientAuth))) {
|
464
|
+
throw new InvalidGrantError('Invalid client authentication')
|
465
|
+
}
|
466
|
+
}
|
467
|
+
|
468
|
+
return data
|
469
|
+
} finally {
|
470
|
+
// A "code" can only be used once
|
471
|
+
await this.store.deleteRequest(result.id)
|
472
|
+
}
|
473
|
+
}
|
474
|
+
|
475
|
+
async delete(uri: RequestUri): Promise<void> {
|
476
|
+
const id = decodeRequestUri(uri)
|
477
|
+
await this.store.deleteRequest(id)
|
478
|
+
}
|
479
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { Code } from './code.js'
|
2
|
+
import { RequestId } from './request-id.js'
|
3
|
+
import { RequestData } from './request-data.js'
|
4
|
+
import { RequestStore } from './request-store.js'
|
5
|
+
|
6
|
+
export class RequestStoreMemory implements RequestStore {
|
7
|
+
#requests = new Map<RequestId, RequestData>()
|
8
|
+
|
9
|
+
async readRequest(id: RequestId): Promise<RequestData | null> {
|
10
|
+
return this.#requests.get(id) ?? null
|
11
|
+
}
|
12
|
+
|
13
|
+
async createRequest(id: RequestId, data: RequestData): Promise<void> {
|
14
|
+
this.#requests.set(id, data)
|
15
|
+
}
|
16
|
+
|
17
|
+
async updateRequest(
|
18
|
+
id: RequestId,
|
19
|
+
data: Partial<RequestData>,
|
20
|
+
): Promise<void> {
|
21
|
+
const current = this.#requests.get(id)
|
22
|
+
if (!current) throw new Error('Request not found')
|
23
|
+
const newData = { ...current, ...data }
|
24
|
+
this.#requests.set(id, newData)
|
25
|
+
}
|
26
|
+
|
27
|
+
async deleteRequest(id: RequestId): Promise<void> {
|
28
|
+
this.#requests.delete(id)
|
29
|
+
}
|
30
|
+
|
31
|
+
async findRequestByCode(
|
32
|
+
code: Code,
|
33
|
+
): Promise<{ id: RequestId; data: RequestData } | null> {
|
34
|
+
for (const [id, data] of this.#requests) {
|
35
|
+
if (data.code === code) return { id, data }
|
36
|
+
}
|
37
|
+
return null
|
38
|
+
}
|
39
|
+
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
import { Redis } from 'ioredis'
|
2
|
+
import { CreateRedisOptions, createRedis } from '../lib/redis.js'
|
3
|
+
import { Code } from './code.js'
|
4
|
+
import { RequestData } from './request-data.js'
|
5
|
+
import { RequestId, requestIdSchema } from './request-id.js'
|
6
|
+
import { RequestStore } from './request-store.js'
|
7
|
+
|
8
|
+
export type { Redis, CreateRedisOptions }
|
9
|
+
|
10
|
+
export type ReplayStoreRedisOptions = {
|
11
|
+
redis: CreateRedisOptions
|
12
|
+
}
|
13
|
+
|
14
|
+
export class RequestStoreRedis implements RequestStore {
|
15
|
+
private readonly redis: Redis
|
16
|
+
|
17
|
+
constructor(options: ReplayStoreRedisOptions) {
|
18
|
+
this.redis = createRedis(options.redis)
|
19
|
+
}
|
20
|
+
|
21
|
+
async readRequest(id: RequestId): Promise<RequestData | null> {
|
22
|
+
const data = await this.redis.get(id)
|
23
|
+
return data ? JSON.parse(data) : null
|
24
|
+
}
|
25
|
+
|
26
|
+
async createRequest(id: RequestId, data: RequestData): Promise<void> {
|
27
|
+
const timeFrame = data.expiresAt.getTime() - Date.now()
|
28
|
+
await this.redis.set(id, JSON.stringify(data), 'PX', timeFrame)
|
29
|
+
if (data.code) await this.redis.set(data.code, id, 'PX', timeFrame)
|
30
|
+
}
|
31
|
+
|
32
|
+
async updateRequest(
|
33
|
+
id: RequestId,
|
34
|
+
data: Partial<RequestData>,
|
35
|
+
): Promise<void> {
|
36
|
+
const current = await this.readRequest(id)
|
37
|
+
if (!current) throw new Error('Request not found')
|
38
|
+
if (current.code) await this.redis.del(current.code)
|
39
|
+
const newData = { ...current, ...data }
|
40
|
+
await this.createRequest(id, newData)
|
41
|
+
}
|
42
|
+
|
43
|
+
async deleteRequest(id: RequestId): Promise<void> {
|
44
|
+
const data = await this.readRequest(id)
|
45
|
+
if (!data) return
|
46
|
+
if (data.code) await this.redis.del(data.code)
|
47
|
+
await this.redis.del(id)
|
48
|
+
}
|
49
|
+
|
50
|
+
private async findRequestIdByCode(code: Code): Promise<RequestId | null> {
|
51
|
+
const value = await this.redis.get(code)
|
52
|
+
if (!value) return null
|
53
|
+
|
54
|
+
const parsed = requestIdSchema.safeParse(value)
|
55
|
+
if (!parsed.success) return null
|
56
|
+
|
57
|
+
return parsed.data
|
58
|
+
}
|
59
|
+
|
60
|
+
async findRequestByCode(
|
61
|
+
code: Code,
|
62
|
+
): Promise<{ id: RequestId; data: RequestData } | null> {
|
63
|
+
const id = await this.findRequestIdByCode(code)
|
64
|
+
if (!id) return null
|
65
|
+
|
66
|
+
const data = await this.readRequest(id)
|
67
|
+
if (!data) return null
|
68
|
+
|
69
|
+
return { id, data }
|
70
|
+
}
|
71
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import { Awaitable } from '../lib/util/type.js'
|
2
|
+
import { Code } from './code.js'
|
3
|
+
import { RequestData } from './request-data.js'
|
4
|
+
import { RequestId } from './request-id.js'
|
5
|
+
|
6
|
+
// Export all types needed to implement the RequestStore interface
|
7
|
+
export * from './code.js'
|
8
|
+
export * from './request-id.js'
|
9
|
+
export * from './request-data.js'
|
10
|
+
export type { Awaitable }
|
11
|
+
|
12
|
+
export type UpdateRequestData = Pick<
|
13
|
+
Partial<RequestData>,
|
14
|
+
'sub' | 'code' | 'deviceId' | 'expiresAt'
|
15
|
+
>
|
16
|
+
|
17
|
+
export type FoundRequestResult = {
|
18
|
+
id: RequestId
|
19
|
+
data: RequestData
|
20
|
+
}
|
21
|
+
|
22
|
+
export interface RequestStore {
|
23
|
+
createRequest(id: RequestId, data: RequestData): Awaitable<void>
|
24
|
+
/**
|
25
|
+
* Note that expired requests **can** be returned to yield a different error
|
26
|
+
* message than if the request was not found.
|
27
|
+
*/
|
28
|
+
readRequest(id: RequestId): Awaitable<RequestData | null>
|
29
|
+
updateRequest(id: RequestId, data: UpdateRequestData): Awaitable<void>
|
30
|
+
deleteRequest(id: RequestId): void | Awaitable<void>
|
31
|
+
findRequestByCode(code: Code): Awaitable<FoundRequestResult | null>
|
32
|
+
}
|
33
|
+
|
34
|
+
export function isRequestStore(
|
35
|
+
implementation: Record<string, unknown> & Partial<RequestStore>,
|
36
|
+
): implementation is Record<string, unknown> & RequestStore {
|
37
|
+
return (
|
38
|
+
typeof implementation.createRequest === 'function' &&
|
39
|
+
typeof implementation.readRequest === 'function' &&
|
40
|
+
typeof implementation.updateRequest === 'function' &&
|
41
|
+
typeof implementation.deleteRequest === 'function' &&
|
42
|
+
typeof implementation.findRequestByCode === 'function'
|
43
|
+
)
|
44
|
+
}
|
45
|
+
|
46
|
+
export function ifRequestStore(
|
47
|
+
implementation?: Record<string, unknown> & Partial<RequestStore>,
|
48
|
+
): RequestStore | undefined {
|
49
|
+
if (implementation && isRequestStore(implementation)) {
|
50
|
+
return implementation
|
51
|
+
}
|
52
|
+
|
53
|
+
return undefined
|
54
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { z } from 'zod'
|
2
|
+
|
3
|
+
import { RequestId, requestIdSchema } from './request-id.js'
|
4
|
+
|
5
|
+
export const REQUEST_URI_PREFIX = 'urn:ietf:params:oauth:request_uri:'
|
6
|
+
|
7
|
+
export const requestUriSchema = z
|
8
|
+
.string()
|
9
|
+
.url()
|
10
|
+
.refinement(
|
11
|
+
(data): data is `${typeof REQUEST_URI_PREFIX}${RequestId}` =>
|
12
|
+
data.startsWith(REQUEST_URI_PREFIX) &&
|
13
|
+
requestIdSchema.safeParse(decodeRequestUri(data as any)).success,
|
14
|
+
{
|
15
|
+
code: z.ZodIssueCode.custom,
|
16
|
+
message: 'Invalid request_uri format',
|
17
|
+
},
|
18
|
+
)
|
19
|
+
|
20
|
+
export type RequestUri = z.infer<typeof requestUriSchema>
|
21
|
+
|
22
|
+
export function encodeRequestUri(requestId: RequestId): RequestUri {
|
23
|
+
return `${REQUEST_URI_PREFIX}${encodeURIComponent(requestId) as RequestId}`
|
24
|
+
}
|
25
|
+
|
26
|
+
export function decodeRequestUri(requestUri: RequestUri): RequestId {
|
27
|
+
const requestIdEnc = requestUri.slice(REQUEST_URI_PREFIX.length)
|
28
|
+
return decodeURIComponent(requestIdEnc) as RequestId
|
29
|
+
}
|