@atproto/oauth-provider 0.6.5 → 0.7.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/CHANGELOG.md +46 -0
- package/dist/access-token/access-token-mode.d.ts +5 -0
- package/dist/access-token/access-token-mode.d.ts.map +1 -0
- package/dist/access-token/access-token-mode.js +9 -0
- package/dist/access-token/access-token-mode.js.map +1 -0
- package/dist/account/account-manager.d.ts +13 -7
- package/dist/account/account-manager.d.ts.map +1 -1
- package/dist/account/account-manager.js +69 -52
- package/dist/account/account-manager.js.map +1 -1
- package/dist/account/account-store.d.ts +88 -77
- package/dist/account/account-store.d.ts.map +1 -1
- package/dist/account/account-store.js +24 -73
- package/dist/account/account-store.js.map +1 -1
- package/dist/account/sign-in-data.d.ts +4 -13
- package/dist/account/sign-in-data.d.ts.map +1 -1
- package/dist/account/sign-in-data.js +9 -9
- package/dist/account/sign-in-data.js.map +1 -1
- package/dist/account/sign-up-input.d.ts +4 -5
- package/dist/account/sign-up-input.d.ts.map +1 -1
- package/dist/account/sign-up-input.js +13 -3
- package/dist/account/sign-up-input.js.map +1 -1
- package/dist/client/client-manager.d.ts +4 -1
- package/dist/client/client-manager.d.ts.map +1 -1
- package/dist/client/client-manager.js +13 -1
- package/dist/client/client-manager.js.map +1 -1
- package/dist/client/client-store.d.ts +1 -1
- package/dist/client/client-store.d.ts.map +1 -1
- package/dist/constants.d.ts +5 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +6 -2
- package/dist/constants.js.map +1 -1
- package/dist/customization/branding.d.ts +54 -0
- package/dist/customization/branding.d.ts.map +1 -0
- package/dist/customization/branding.js +13 -0
- package/dist/customization/branding.js.map +1 -0
- package/dist/customization/build-customization-css.d.ts +3 -0
- package/dist/customization/build-customization-css.d.ts.map +1 -0
- package/dist/customization/build-customization-css.js +27 -0
- package/dist/customization/build-customization-css.js.map +1 -0
- package/dist/customization/build-customization-data.d.ts +4 -0
- package/dist/customization/build-customization-data.d.ts.map +1 -0
- package/dist/customization/build-customization-data.js +18 -0
- package/dist/customization/build-customization-data.js.map +1 -0
- package/dist/customization/colors.d.ts +7 -0
- package/dist/customization/colors.d.ts.map +1 -0
- package/dist/customization/colors.js +27 -0
- package/dist/customization/colors.js.map +1 -0
- package/dist/customization/customization.d.ts +129 -0
- package/dist/customization/customization.d.ts.map +1 -0
- package/dist/customization/customization.js +26 -0
- package/dist/customization/customization.js.map +1 -0
- package/dist/customization/links.d.ts +26 -0
- package/dist/customization/links.d.ts.map +1 -0
- package/dist/customization/links.js +12 -0
- package/dist/customization/links.js.map +1 -0
- package/dist/device/device-id.d.ts +1 -0
- package/dist/device/device-id.d.ts.map +1 -1
- package/dist/device/device-id.js +4 -0
- package/dist/device/device-id.js.map +1 -1
- package/dist/device/device-manager.d.ts +6 -36
- package/dist/device/device-manager.d.ts.map +1 -1
- package/dist/device/device-manager.js +49 -43
- package/dist/device/device-manager.js.map +1 -1
- package/dist/device/device-store.d.ts +1 -0
- package/dist/device/device-store.d.ts.map +1 -1
- package/dist/device/device-store.js.map +1 -1
- package/dist/dpop/dpop-manager.d.ts +3 -3
- package/dist/dpop/dpop-nonce.d.ts +3 -3
- package/dist/dpop/dpop-nonce.d.ts.map +1 -1
- package/dist/errors/access-denied-error.d.ts +4 -3
- package/dist/errors/access-denied-error.d.ts.map +1 -1
- package/dist/errors/access-denied-error.js +5 -6
- package/dist/errors/access-denied-error.js.map +1 -1
- package/dist/{output/build-error-payload.d.ts → errors/error-parser.d.ts} +1 -1
- package/dist/errors/error-parser.d.ts.map +1 -0
- package/dist/{output/build-error-payload.js → errors/error-parser.js} +2 -2
- package/dist/errors/error-parser.js.map +1 -0
- package/dist/errors/invalid-grant-error.d.ts +1 -0
- package/dist/errors/invalid-grant-error.d.ts.map +1 -1
- package/dist/errors/invalid-grant-error.js +5 -0
- package/dist/errors/invalid-grant-error.js.map +1 -1
- package/dist/errors/login-required-error.d.ts +1 -0
- package/dist/errors/login-required-error.d.ts.map +1 -1
- package/dist/errors/login-required-error.js +5 -0
- package/dist/errors/login-required-error.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/html/build-document.d.ts +2 -2
- package/dist/lib/html/build-document.d.ts.map +1 -1
- package/dist/lib/html/build-document.js +4 -0
- package/dist/lib/html/build-document.js.map +1 -1
- package/dist/lib/html/hydration-data.d.ts +4 -0
- package/dist/lib/html/hydration-data.d.ts.map +1 -0
- package/dist/{output/backend-data.js → lib/html/hydration-data.js} +8 -8
- package/dist/lib/html/hydration-data.js.map +1 -0
- package/dist/lib/html/tags.d.ts +1 -1
- package/dist/lib/html/tags.d.ts.map +1 -1
- package/dist/lib/html/tags.js +1 -1
- package/dist/lib/html/tags.js.map +1 -1
- package/dist/lib/http/accept.d.ts +2 -2
- package/dist/lib/http/accept.d.ts.map +1 -1
- package/dist/lib/http/accept.js +1 -1
- package/dist/lib/http/accept.js.map +1 -1
- package/dist/lib/http/context.d.ts +2 -4
- package/dist/lib/http/context.d.ts.map +1 -1
- package/dist/lib/http/context.js +29 -4
- package/dist/lib/http/context.js.map +1 -1
- package/dist/lib/http/headers.d.ts +3 -0
- package/dist/lib/http/headers.d.ts.map +1 -0
- package/dist/lib/http/headers.js +14 -0
- package/dist/lib/http/headers.js.map +1 -0
- package/dist/lib/http/index.d.ts +1 -0
- package/dist/lib/http/index.d.ts.map +1 -1
- package/dist/lib/http/index.js +1 -0
- package/dist/lib/http/index.js.map +1 -1
- package/dist/lib/http/middleware.d.ts +1 -1
- package/dist/lib/http/middleware.d.ts.map +1 -1
- package/dist/lib/http/middleware.js +8 -24
- package/dist/lib/http/middleware.js.map +1 -1
- package/dist/lib/http/parser.d.ts +3 -3
- package/dist/lib/http/parser.d.ts.map +1 -1
- package/dist/lib/http/request.d.ts +13 -9
- package/dist/lib/http/request.d.ts.map +1 -1
- package/dist/lib/http/request.js +27 -49
- package/dist/lib/http/request.js.map +1 -1
- package/dist/lib/http/response.d.ts +6 -2
- package/dist/lib/http/response.d.ts.map +1 -1
- package/dist/lib/http/response.js +31 -11
- package/dist/lib/http/response.js.map +1 -1
- package/dist/lib/http/route.d.ts +3 -3
- package/dist/lib/http/route.d.ts.map +1 -1
- package/dist/lib/http/route.js +1 -1
- package/dist/lib/http/route.js.map +1 -1
- package/dist/lib/http/router.d.ts +12 -11
- package/dist/lib/http/router.d.ts.map +1 -1
- package/dist/lib/http/router.js +26 -34
- package/dist/lib/http/router.js.map +1 -1
- package/dist/lib/http/security-headers.js +1 -1
- package/dist/lib/http/security-headers.js.map +1 -1
- package/dist/lib/http/stream.d.ts +3 -3
- package/dist/lib/http/stream.d.ts.map +1 -1
- package/dist/lib/http/types.d.ts +1 -1
- package/dist/lib/http/types.d.ts.map +1 -1
- package/dist/lib/send-web-page.d.ts +8 -0
- package/dist/lib/send-web-page.d.ts.map +1 -0
- package/dist/{output → lib}/send-web-page.js +9 -7
- package/dist/lib/send-web-page.js.map +1 -0
- package/dist/lib/util/authorization-header.d.ts.map +1 -1
- package/dist/lib/util/color.d.ts +32 -0
- package/dist/lib/util/color.d.ts.map +1 -0
- package/dist/lib/util/color.js +116 -0
- package/dist/lib/util/color.js.map +1 -0
- package/dist/lib/util/crypto.d.ts +1 -0
- package/dist/lib/util/crypto.d.ts.map +1 -1
- package/dist/lib/util/crypto.js +8 -3
- package/dist/lib/util/crypto.js.map +1 -1
- package/dist/lib/util/function.d.ts +1 -0
- package/dist/lib/util/function.d.ts.map +1 -1
- package/dist/lib/util/function.js +12 -0
- package/dist/lib/util/function.js.map +1 -1
- package/dist/lib/util/locale.d.ts +20 -0
- package/dist/lib/util/locale.d.ts.map +1 -0
- package/dist/lib/util/locale.js +14 -0
- package/dist/lib/util/locale.js.map +1 -0
- package/dist/lib/util/time.d.ts +1 -1
- package/dist/lib/util/time.d.ts.map +1 -1
- package/dist/lib/util/time.js +1 -1
- package/dist/lib/util/time.js.map +1 -1
- package/dist/lib/util/type.d.ts +22 -0
- package/dist/lib/util/type.d.ts.map +1 -1
- package/dist/lib/util/type.js.map +1 -1
- package/dist/lib/util/ui8.d.ts +4 -0
- package/dist/lib/util/ui8.d.ts.map +1 -0
- package/dist/lib/util/ui8.js +17 -0
- package/dist/lib/util/ui8.js.map +1 -0
- package/dist/lib/util/zod-error.d.ts +2 -0
- package/dist/lib/util/zod-error.d.ts.map +1 -0
- package/dist/lib/util/zod-error.js +16 -0
- package/dist/lib/util/zod-error.js.map +1 -0
- package/dist/oauth-errors.d.ts +22 -22
- package/dist/oauth-errors.d.ts.map +1 -1
- package/dist/oauth-errors.js +37 -45
- package/dist/oauth-errors.js.map +1 -1
- package/dist/oauth-hooks.d.ts +11 -23
- package/dist/oauth-hooks.d.ts.map +1 -1
- package/dist/oauth-hooks.js.map +1 -1
- package/dist/oauth-middleware.d.ts +12 -0
- package/dist/oauth-middleware.d.ts.map +1 -0
- package/dist/oauth-middleware.js +32 -0
- package/dist/oauth-middleware.js.map +1 -0
- package/dist/oauth-provider.d.ts +109 -113
- package/dist/oauth-provider.d.ts.map +1 -1
- package/dist/oauth-provider.js +124 -542
- package/dist/oauth-provider.js.map +1 -1
- package/dist/oauth-verifier.d.ts +7 -26
- package/dist/oauth-verifier.d.ts.map +1 -1
- package/dist/oauth-verifier.js +6 -16
- package/dist/oauth-verifier.js.map +1 -1
- package/dist/request/code.d.ts.map +1 -1
- package/dist/request/request-data.d.ts +2 -4
- package/dist/request/request-data.d.ts.map +1 -1
- package/dist/request/request-data.js.map +1 -1
- package/dist/request/request-manager.d.ts +4 -2
- package/dist/request/request-manager.d.ts.map +1 -1
- package/dist/request/request-manager.js +9 -8
- package/dist/request/request-manager.js.map +1 -1
- package/dist/request/request-store.d.ts +6 -0
- package/dist/request/request-store.d.ts.map +1 -1
- package/dist/request/request-store.js +3 -1
- package/dist/request/request-store.js.map +1 -1
- package/dist/result/authorization-redirect-parameters.d.ts +18 -0
- package/dist/result/authorization-redirect-parameters.d.ts.map +1 -0
- package/dist/result/authorization-redirect-parameters.js +3 -0
- package/dist/result/authorization-redirect-parameters.js.map +1 -0
- package/dist/result/authorization-result-authorize-page.d.ts +13 -0
- package/dist/result/authorization-result-authorize-page.d.ts.map +1 -0
- package/dist/result/authorization-result-authorize-page.js +3 -0
- package/dist/result/authorization-result-authorize-page.js.map +1 -0
- package/dist/result/authorization-result-redirect.d.ts +8 -0
- package/dist/result/authorization-result-redirect.d.ts.map +1 -0
- package/dist/result/authorization-result-redirect.js +3 -0
- package/dist/result/authorization-result-redirect.js.map +1 -0
- package/dist/router/assets/assets-manifest.d.ts +10 -0
- package/dist/router/assets/assets-manifest.d.ts.map +1 -0
- package/dist/router/assets/assets-manifest.js +77 -0
- package/dist/router/assets/assets-manifest.js.map +1 -0
- package/dist/router/assets/assets.d.ts +16 -0
- package/dist/router/assets/assets.d.ts.map +1 -0
- package/dist/router/assets/assets.js +43 -0
- package/dist/router/assets/assets.js.map +1 -0
- package/dist/router/assets/csrf.d.ts +4 -0
- package/dist/router/assets/csrf.d.ts.map +1 -0
- package/dist/router/assets/csrf.js +51 -0
- package/dist/router/assets/csrf.js.map +1 -0
- package/dist/router/assets/send-account-page.d.ts +7 -0
- package/dist/router/assets/send-account-page.d.ts.map +1 -0
- package/dist/router/assets/send-account-page.js +34 -0
- package/dist/router/assets/send-account-page.js.map +1 -0
- package/dist/router/assets/send-authorization-page.d.ts +5 -0
- package/dist/router/assets/send-authorization-page.d.ts.map +1 -0
- package/dist/router/assets/send-authorization-page.js +49 -0
- package/dist/router/assets/send-authorization-page.js.map +1 -0
- package/dist/router/assets/send-error-page.d.ts +4 -0
- package/dist/router/assets/send-error-page.d.ts.map +1 -0
- package/dist/router/assets/send-error-page.js +34 -0
- package/dist/router/assets/send-error-page.js.map +1 -0
- package/dist/router/create-account-page-middleware.d.ts +6 -0
- package/dist/router/create-account-page-middleware.d.ts.map +1 -0
- package/dist/router/create-account-page-middleware.js +39 -0
- package/dist/router/create-account-page-middleware.js.map +1 -0
- package/dist/router/create-api-middleware.d.ts +8 -0
- package/dist/router/create-api-middleware.d.ts.map +1 -0
- package/dist/router/create-api-middleware.js +501 -0
- package/dist/router/create-api-middleware.js.map +1 -0
- package/dist/router/create-authorization-page-middleware.d.ts +6 -0
- package/dist/router/create-authorization-page-middleware.d.ts.map +1 -0
- package/dist/router/create-authorization-page-middleware.js +104 -0
- package/dist/router/create-authorization-page-middleware.js.map +1 -0
- package/dist/router/create-oauth-middleware.d.ts +6 -0
- package/dist/router/create-oauth-middleware.d.ts.map +1 -0
- package/dist/router/create-oauth-middleware.js +142 -0
- package/dist/router/create-oauth-middleware.js.map +1 -0
- package/dist/router/error-handler.d.ts +3 -0
- package/dist/router/error-handler.d.ts.map +1 -0
- package/dist/{account/account.js → router/error-handler.js} +1 -1
- package/dist/router/error-handler.js.map +1 -0
- package/dist/router/middleware-options.d.ts +6 -0
- package/dist/router/middleware-options.d.ts.map +1 -0
- package/dist/router/middleware-options.js +3 -0
- package/dist/router/middleware-options.js.map +1 -0
- package/dist/router/send-redirect.d.ts +16 -0
- package/dist/router/send-redirect.d.ts.map +1 -0
- package/dist/{output/send-authorize-redirect.js → router/send-redirect.js} +40 -24
- package/dist/router/send-redirect.js.map +1 -0
- package/dist/{token/token-claims.d.ts → signer/api-token-payload.d.ts} +237 -232
- package/dist/signer/api-token-payload.d.ts.map +1 -0
- package/dist/signer/api-token-payload.js +17 -0
- package/dist/signer/api-token-payload.js.map +1 -0
- package/dist/signer/signed-token-payload.d.ts +164 -159
- package/dist/signer/signed-token-payload.d.ts.map +1 -1
- package/dist/signer/signed-token-payload.js +10 -16
- package/dist/signer/signed-token-payload.js.map +1 -1
- package/dist/signer/signer.d.ts +42 -11246
- package/dist/signer/signer.d.ts.map +1 -1
- package/dist/signer/signer.js +30 -15
- package/dist/signer/signer.js.map +1 -1
- package/dist/token/refresh-token.d.ts.map +1 -1
- package/dist/token/token-data.d.ts +1 -1
- package/dist/token/token-data.d.ts.map +1 -1
- package/dist/token/token-id.d.ts.map +1 -1
- package/dist/token/token-manager.d.ts +28 -26
- package/dist/token/token-manager.d.ts.map +1 -1
- package/dist/token/token-manager.js +138 -196
- package/dist/token/token-manager.js.map +1 -1
- package/dist/token/token-store.d.ts +4 -4
- package/dist/token/token-store.d.ts.map +1 -1
- package/dist/token/token-store.js +1 -0
- package/dist/token/token-store.js.map +1 -1
- package/dist/token/verify-token-claims.d.ts +3 -3
- package/dist/token/verify-token-claims.d.ts.map +1 -1
- package/dist/token/verify-token-claims.js +1 -1
- package/dist/token/verify-token-claims.js.map +1 -1
- package/dist/types/email-otp.d.ts +3 -0
- package/dist/types/email-otp.d.ts.map +1 -0
- package/dist/types/email-otp.js +6 -0
- package/dist/types/email-otp.js.map +1 -0
- package/dist/types/email.d.ts +3 -0
- package/dist/types/email.d.ts.map +1 -0
- package/dist/types/email.js +29 -0
- package/dist/types/email.js.map +1 -0
- package/dist/types/handle.d.ts +3 -0
- package/dist/types/handle.d.ts.map +1 -0
- package/dist/types/handle.js +22 -0
- package/dist/types/handle.js.map +1 -0
- package/dist/types/invite-code.d.ts +4 -0
- package/dist/types/invite-code.d.ts.map +1 -0
- package/dist/types/invite-code.js +6 -0
- package/dist/types/invite-code.js.map +1 -0
- package/dist/types/password.d.ts +4 -0
- package/dist/types/password.d.ts.map +1 -0
- package/dist/types/password.js +7 -0
- package/dist/types/password.js.map +1 -0
- package/package.json +11 -8
- package/src/access-token/access-token-mode.ts +4 -0
- package/src/account/account-manager.ts +105 -75
- package/src/account/account-store.ts +118 -114
- package/src/account/sign-in-data.ts +10 -10
- package/src/account/sign-up-input.ts +13 -4
- package/src/client/client-manager.ts +34 -2
- package/src/client/client-store.ts +1 -1
- package/src/constants.ts +6 -1
- package/src/customization/branding.ts +12 -0
- package/src/customization/build-customization-css.ts +30 -0
- package/src/customization/build-customization-data.ts +22 -0
- package/src/customization/colors.ts +30 -0
- package/src/customization/customization.ts +25 -0
- package/src/customization/links.ts +10 -0
- package/src/device/device-id.ts +5 -0
- package/src/device/device-manager.ts +76 -66
- package/src/device/device-store.ts +2 -0
- package/src/errors/access-denied-error.ts +24 -17
- package/src/{output/build-error-payload.ts → errors/error-parser.ts} +1 -1
- package/src/errors/invalid-grant-error.ts +5 -0
- package/src/errors/login-required-error.ts +10 -0
- package/src/index.ts +1 -0
- package/src/lib/html/build-document.ts +6 -4
- package/src/{output/backend-data.ts → lib/html/hydration-data.ts} +7 -5
- package/src/lib/html/tags.ts +2 -2
- package/src/lib/http/accept.ts +3 -3
- package/src/lib/http/context.ts +41 -10
- package/src/lib/http/headers.ts +15 -0
- package/src/lib/http/index.ts +1 -0
- package/src/lib/http/middleware.ts +8 -23
- package/src/lib/http/request.ts +40 -75
- package/src/lib/http/response.ts +39 -15
- package/src/lib/http/route.ts +8 -5
- package/src/lib/http/router.ts +40 -46
- package/src/lib/http/security-headers.ts +1 -1
- package/src/lib/http/types.ts +1 -6
- package/src/{output → lib}/send-web-page.ts +10 -9
- package/src/lib/util/color.ts +132 -0
- package/src/lib/util/crypto.ts +9 -4
- package/src/lib/util/function.ts +14 -0
- package/src/lib/util/locale.ts +18 -0
- package/src/lib/util/time.ts +3 -4
- package/src/lib/util/type.ts +24 -0
- package/src/lib/util/ui8.ts +14 -0
- package/src/lib/util/zod-error.ts +14 -0
- package/src/oauth-errors.ts +22 -22
- package/src/oauth-hooks.ts +11 -24
- package/src/oauth-middleware.ts +53 -0
- package/src/oauth-provider.ts +290 -1061
- package/src/oauth-verifier.ts +9 -55
- package/src/request/request-data.ts +5 -4
- package/src/request/request-manager.ts +11 -11
- package/src/request/request-store.ts +7 -0
- package/src/result/authorization-redirect-parameters.ts +24 -0
- package/src/result/authorization-result-authorize-page.ts +14 -0
- package/src/result/authorization-result-redirect.ts +8 -0
- package/src/router/assets/assets-manifest.ts +108 -0
- package/src/router/assets/assets.ts +54 -0
- package/src/router/assets/csrf.ts +63 -0
- package/src/router/assets/send-account-page.ts +43 -0
- package/src/router/assets/send-authorization-page.ts +62 -0
- package/src/router/assets/send-error-page.ts +42 -0
- package/src/router/create-account-page-middleware.ts +69 -0
- package/src/router/create-api-middleware.ts +814 -0
- package/src/router/create-authorization-page-middleware.ts +173 -0
- package/src/router/create-oauth-middleware.ts +247 -0
- package/src/router/error-handler.ts +6 -0
- package/src/router/middleware-options.ts +9 -0
- package/src/router/send-redirect.ts +142 -0
- package/src/signer/api-token-payload.ts +18 -0
- package/src/signer/signed-token-payload.ts +18 -28
- package/src/signer/signer.ts +49 -34
- package/src/token/token-data.ts +1 -1
- package/src/token/token-manager.ts +190 -239
- package/src/token/token-store.ts +6 -4
- package/src/token/verify-token-claims.ts +4 -4
- package/src/types/email-otp.ts +3 -0
- package/src/types/email.ts +26 -0
- package/src/types/handle.ts +18 -0
- package/src/types/invite-code.ts +4 -0
- package/src/types/password.ts +4 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +1 -1
- package/dist/access-token/access-token-type.d.ts +0 -6
- package/dist/access-token/access-token-type.d.ts.map +0 -1
- package/dist/access-token/access-token-type.js +0 -10
- package/dist/access-token/access-token-type.js.map +0 -1
- package/dist/account/account.d.ts +0 -2
- package/dist/account/account.d.ts.map +0 -1
- package/dist/account/account.js.map +0 -1
- package/dist/assets/assets-middleware.d.ts +0 -5
- package/dist/assets/assets-middleware.d.ts.map +0 -1
- package/dist/assets/assets-middleware.js +0 -41
- package/dist/assets/assets-middleware.js.map +0 -1
- package/dist/lib/locale.d.ts +0 -15
- package/dist/lib/locale.d.ts.map +0 -1
- package/dist/lib/locale.js +0 -17
- package/dist/lib/locale.js.map +0 -1
- package/dist/output/backend-data.d.ts +0 -4
- package/dist/output/backend-data.d.ts.map +0 -1
- package/dist/output/backend-data.js.map +0 -1
- package/dist/output/build-authorize-data.d.ts +0 -29
- package/dist/output/build-authorize-data.d.ts.map +0 -1
- package/dist/output/build-authorize-data.js +0 -21
- package/dist/output/build-authorize-data.js.map +0 -1
- package/dist/output/build-customization-data.d.ts +0 -234
- package/dist/output/build-customization-data.d.ts.map +0 -1
- package/dist/output/build-customization-data.js +0 -174
- package/dist/output/build-customization-data.js.map +0 -1
- package/dist/output/build-error-data.d.ts +0 -3
- package/dist/output/build-error-data.d.ts.map +0 -1
- package/dist/output/build-error-data.js +0 -10
- package/dist/output/build-error-data.js.map +0 -1
- package/dist/output/build-error-payload.d.ts.map +0 -1
- package/dist/output/build-error-payload.js.map +0 -1
- package/dist/output/output-manager.d.ts +0 -28
- package/dist/output/output-manager.d.ts.map +0 -1
- package/dist/output/output-manager.js +0 -134
- package/dist/output/output-manager.js.map +0 -1
- package/dist/output/send-authorize-redirect.d.ts +0 -25
- package/dist/output/send-authorize-redirect.d.ts.map +0 -1
- package/dist/output/send-authorize-redirect.js.map +0 -1
- package/dist/output/send-web-page.d.ts +0 -8
- package/dist/output/send-web-page.d.ts.map +0 -1
- package/dist/output/send-web-page.js.map +0 -1
- package/dist/token/token-claims.d.ts.map +0 -1
- package/dist/token/token-claims.js +0 -27
- package/dist/token/token-claims.js.map +0 -1
- package/src/access-token/access-token-type.ts +0 -5
- package/src/account/account.ts +0 -1
- package/src/assets/assets-middleware.ts +0 -44
- package/src/lib/locale.ts +0 -21
- package/src/output/build-authorize-data.ts +0 -53
- package/src/output/build-customization-data.ts +0 -217
- package/src/output/build-error-data.ts +0 -8
- package/src/output/output-manager.ts +0 -188
- package/src/output/send-authorize-redirect.ts +0 -137
- package/src/token/token-claims.ts +0 -30
- package/tsconfig.backend.tsbuildinfo +0 -1
- /package/{tsconfig.backend.json → tsconfig.build.json} +0 -0
@@ -0,0 +1,173 @@
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http'
|
2
|
+
import {
|
3
|
+
oauthAuthorizationRequestQuerySchema,
|
4
|
+
oauthClientCredentialsSchema,
|
5
|
+
} from '@atproto/oauth-types'
|
6
|
+
import { AccessDeniedError } from '../errors/access-denied-error.js'
|
7
|
+
import { InvalidRequestError } from '../errors/invalid-request-error.js'
|
8
|
+
import {
|
9
|
+
Middleware,
|
10
|
+
Router,
|
11
|
+
RouterCtx,
|
12
|
+
validateFetchDest,
|
13
|
+
validateFetchMode,
|
14
|
+
validateFetchSite,
|
15
|
+
validateOrigin,
|
16
|
+
validateReferrer,
|
17
|
+
} from '../lib/http/index.js'
|
18
|
+
import type { Awaitable } from '../lib/util/type.js'
|
19
|
+
import { extractZodErrorMessage } from '../lib/util/zod-error.js'
|
20
|
+
import type { OAuthProvider } from '../oauth-provider.js'
|
21
|
+
import { requestUriSchema } from '../request/request-uri.js'
|
22
|
+
import { AuthorizationResultRedirect } from '../result/authorization-result-redirect.js'
|
23
|
+
import { sendAuthorizePageFactory } from './assets/send-authorization-page.js'
|
24
|
+
import { sendErrorPageFactory } from './assets/send-error-page.js'
|
25
|
+
import { parseRedirectUrl } from './create-api-middleware.js'
|
26
|
+
import type { MiddlewareOptions } from './middleware-options.js'
|
27
|
+
import {
|
28
|
+
buildRedirectMode,
|
29
|
+
buildRedirectParams,
|
30
|
+
buildRedirectUri,
|
31
|
+
sendRedirect,
|
32
|
+
} from './send-redirect.js'
|
33
|
+
|
34
|
+
export function createAuthorizationPageMiddleware<
|
35
|
+
Ctx extends object | void = void,
|
36
|
+
Req extends IncomingMessage = IncomingMessage,
|
37
|
+
Res extends ServerResponse = ServerResponse,
|
38
|
+
>(
|
39
|
+
server: OAuthProvider,
|
40
|
+
{ onError }: MiddlewareOptions<Req, Res>,
|
41
|
+
): Middleware<Ctx, Req, Res> {
|
42
|
+
const sendAuthorizePage = sendAuthorizePageFactory(server.customization)
|
43
|
+
const sendErrorPage = sendErrorPageFactory(server.customization)
|
44
|
+
|
45
|
+
const issuerUrl = new URL(server.issuer)
|
46
|
+
const issuerOrigin = issuerUrl.origin
|
47
|
+
|
48
|
+
const router = new Router<Ctx, Req, Res>(issuerUrl)
|
49
|
+
|
50
|
+
router.get(
|
51
|
+
'/oauth/authorize',
|
52
|
+
withErrorHandler(async function (req, res) {
|
53
|
+
res.setHeader('Cache-Control', 'no-store')
|
54
|
+
res.setHeader('Pragma', 'no-cache')
|
55
|
+
|
56
|
+
validateFetchSite(req, ['cross-site', 'none'])
|
57
|
+
validateFetchMode(req, ['navigate'])
|
58
|
+
validateFetchDest(req, ['document'])
|
59
|
+
validateOrigin(req, issuerOrigin)
|
60
|
+
|
61
|
+
const query = Object.fromEntries(this.url.searchParams)
|
62
|
+
|
63
|
+
const clientCredentials = await oauthClientCredentialsSchema
|
64
|
+
.parseAsync(query, { path: ['query'] })
|
65
|
+
.catch(throwInvalidRequest)
|
66
|
+
|
67
|
+
if ('client_secret' in clientCredentials) {
|
68
|
+
throw new InvalidRequestError('Client secret must not be provided')
|
69
|
+
}
|
70
|
+
|
71
|
+
const authorizationRequest = await oauthAuthorizationRequestQuerySchema
|
72
|
+
.parseAsync(query, { path: ['query'] })
|
73
|
+
.catch(throwInvalidRequest)
|
74
|
+
|
75
|
+
const deviceInfo = await server.deviceManager.load(req, res)
|
76
|
+
|
77
|
+
try {
|
78
|
+
const result = await server.authorize(
|
79
|
+
clientCredentials,
|
80
|
+
authorizationRequest,
|
81
|
+
deviceInfo.deviceId,
|
82
|
+
deviceInfo.deviceMetadata,
|
83
|
+
)
|
84
|
+
|
85
|
+
if ('redirect' in result) {
|
86
|
+
return sendAuthorizeRedirect(res, result)
|
87
|
+
} else {
|
88
|
+
return sendAuthorizePage(req, res, result)
|
89
|
+
}
|
90
|
+
} catch (err) {
|
91
|
+
// If we have the "redirect_uri" parameter, we can redirect the user
|
92
|
+
// to the client with an error.
|
93
|
+
if (err instanceof AccessDeniedError && err.parameters.redirect_uri) {
|
94
|
+
// Prefer logging the cause
|
95
|
+
onError?.(req, res, err.cause ?? err, 'Authorization failed')
|
96
|
+
|
97
|
+
return sendAuthorizeRedirect(res, {
|
98
|
+
issuer: server.issuer,
|
99
|
+
parameters: err.parameters,
|
100
|
+
redirect: err.toJSON(),
|
101
|
+
})
|
102
|
+
}
|
103
|
+
|
104
|
+
throw err
|
105
|
+
}
|
106
|
+
}),
|
107
|
+
)
|
108
|
+
|
109
|
+
// This is a private endpoint that will be called by the user after the
|
110
|
+
// authorization request was either approved or denied. The logic performed
|
111
|
+
// here **could** be performed directly in the frontend. We decided to
|
112
|
+
// implement it here to avoid duplicating the logic.
|
113
|
+
router.get(
|
114
|
+
'/oauth/authorize/redirect',
|
115
|
+
withErrorHandler(async function (req, res) {
|
116
|
+
// Ensure we come from the authorization page
|
117
|
+
validateFetchSite(req, ['same-origin'])
|
118
|
+
validateFetchMode(req, ['navigate'])
|
119
|
+
validateFetchDest(req, ['document'])
|
120
|
+
validateOrigin(req, issuerOrigin)
|
121
|
+
|
122
|
+
const referrer = validateReferrer(req, {
|
123
|
+
origin: issuerOrigin,
|
124
|
+
pathname: '/oauth/authorize',
|
125
|
+
})
|
126
|
+
|
127
|
+
// Ensure we are coming from the authorization page
|
128
|
+
requestUriSchema.parse(referrer.searchParams.get('request_uri'))
|
129
|
+
|
130
|
+
return sendRedirect(res, parseRedirectUrl(this.url))
|
131
|
+
}),
|
132
|
+
)
|
133
|
+
|
134
|
+
return router.buildMiddleware()
|
135
|
+
|
136
|
+
function withErrorHandler<T extends RouterCtx>(
|
137
|
+
handler: (this: T, req: Req, res: Res) => Awaitable<void>,
|
138
|
+
): Middleware<T, Req, Res> {
|
139
|
+
return async function (req, res) {
|
140
|
+
try {
|
141
|
+
await handler.call(this, req, res)
|
142
|
+
} catch (err) {
|
143
|
+
onError?.(
|
144
|
+
req,
|
145
|
+
res,
|
146
|
+
err,
|
147
|
+
`Failed to handle navigation request to "${req.url}"`,
|
148
|
+
)
|
149
|
+
|
150
|
+
if (!res.headersSent) {
|
151
|
+
sendErrorPage(req, res, err)
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
function throwInvalidRequest(err: unknown): never {
|
159
|
+
throw new InvalidRequestError(
|
160
|
+
extractZodErrorMessage(err) ?? 'Input validation error',
|
161
|
+
err,
|
162
|
+
)
|
163
|
+
}
|
164
|
+
|
165
|
+
function sendAuthorizeRedirect(
|
166
|
+
res: ServerResponse,
|
167
|
+
{ issuer, parameters, redirect }: AuthorizationResultRedirect,
|
168
|
+
) {
|
169
|
+
const redirectUri = buildRedirectUri(parameters)
|
170
|
+
const mode = buildRedirectMode(parameters)
|
171
|
+
const params = buildRedirectParams(issuer, parameters, redirect)
|
172
|
+
return sendRedirect(res, { mode, redirectUri, params })
|
173
|
+
}
|
@@ -0,0 +1,247 @@
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http'
|
2
|
+
import {
|
3
|
+
oauthAuthorizationRequestParSchema,
|
4
|
+
oauthClientCredentialsSchema,
|
5
|
+
oauthTokenIdentificationSchema,
|
6
|
+
oauthTokenRequestSchema,
|
7
|
+
} from '@atproto/oauth-types'
|
8
|
+
import { buildErrorPayload, buildErrorStatus } from '../errors/error-parser.js'
|
9
|
+
import { InvalidClientError } from '../errors/invalid-client-error.js'
|
10
|
+
import { InvalidGrantError } from '../errors/invalid-grant-error.js'
|
11
|
+
import { InvalidRequestError } from '../errors/invalid-request-error.js'
|
12
|
+
import { WWWAuthenticateError } from '../errors/www-authenticate-error.js'
|
13
|
+
import {
|
14
|
+
Middleware,
|
15
|
+
Router,
|
16
|
+
cacheControlMiddleware,
|
17
|
+
combineMiddlewares,
|
18
|
+
jsonHandler,
|
19
|
+
parseHttpRequest,
|
20
|
+
staticJsonMiddleware,
|
21
|
+
} from '../lib/http/index.js'
|
22
|
+
import { extractZodErrorMessage } from '../lib/util/zod-error.js'
|
23
|
+
import type { OAuthProvider } from '../oauth-provider.js'
|
24
|
+
import type { MiddlewareOptions } from './middleware-options.js'
|
25
|
+
|
26
|
+
// CORS preflight
|
27
|
+
const corsHeaders: Middleware = function (req, res, next) {
|
28
|
+
res.setHeader('Access-Control-Max-Age', '86400') // 1 day
|
29
|
+
|
30
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
31
|
+
//
|
32
|
+
// > For requests without credentials, the literal value "*" can be
|
33
|
+
// > specified as a wildcard; the value tells browsers to allow
|
34
|
+
// > requesting code from any origin to access the resource.
|
35
|
+
// > Attempting to use the wildcard with credentials results in an
|
36
|
+
// > error.
|
37
|
+
//
|
38
|
+
// A "*" is safer to use than reflecting the request origin.
|
39
|
+
res.setHeader('Access-Control-Allow-Origin', '*')
|
40
|
+
|
41
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
|
42
|
+
// > The value "*" only counts as a special wildcard value for
|
43
|
+
// > requests without credentials (requests without HTTP cookies or
|
44
|
+
// > HTTP authentication information). In requests with credentials,
|
45
|
+
// > it is treated as the literal method name "*" without special
|
46
|
+
// > semantics.
|
47
|
+
res.setHeader('Access-Control-Allow-Methods', '*')
|
48
|
+
|
49
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type,DPoP')
|
50
|
+
|
51
|
+
next()
|
52
|
+
}
|
53
|
+
|
54
|
+
const corsPreflight: Middleware = combineMiddlewares([
|
55
|
+
corsHeaders,
|
56
|
+
(req, res) => {
|
57
|
+
res.writeHead(200).end()
|
58
|
+
},
|
59
|
+
])
|
60
|
+
|
61
|
+
export function createOAuthMiddleware<
|
62
|
+
Ctx extends object | void = void,
|
63
|
+
Req extends IncomingMessage = IncomingMessage,
|
64
|
+
Res extends ServerResponse = ServerResponse,
|
65
|
+
>(
|
66
|
+
server: OAuthProvider,
|
67
|
+
{ onError }: MiddlewareOptions<Req, Res>,
|
68
|
+
): Middleware<Ctx, Req, Res> {
|
69
|
+
const router = new Router<Ctx, Req, Res>(new URL(server.issuer))
|
70
|
+
|
71
|
+
//- Public OAuth endpoints
|
72
|
+
|
73
|
+
router.options('/.well-known/oauth-authorization-server', corsPreflight)
|
74
|
+
router.get(
|
75
|
+
'/.well-known/oauth-authorization-server',
|
76
|
+
corsHeaders,
|
77
|
+
cacheControlMiddleware(300),
|
78
|
+
staticJsonMiddleware(server.metadata),
|
79
|
+
)
|
80
|
+
|
81
|
+
router.options('/oauth/jwks', corsPreflight)
|
82
|
+
router.get(
|
83
|
+
'/oauth/jwks',
|
84
|
+
corsHeaders,
|
85
|
+
cacheControlMiddleware(300),
|
86
|
+
staticJsonMiddleware(server.jwks),
|
87
|
+
)
|
88
|
+
|
89
|
+
router.options('/oauth/par', corsPreflight)
|
90
|
+
router.post(
|
91
|
+
'/oauth/par',
|
92
|
+
corsHeaders,
|
93
|
+
oauthHandler(async function (req) {
|
94
|
+
const payload = await parseHttpRequest(req, ['json', 'urlencoded'])
|
95
|
+
|
96
|
+
const credentials = await oauthClientCredentialsSchema
|
97
|
+
.parseAsync(payload, { path: ['body'] })
|
98
|
+
.catch(throwInvalidRequest)
|
99
|
+
|
100
|
+
const authorizationRequest = await oauthAuthorizationRequestParSchema
|
101
|
+
.parseAsync(payload, { path: ['body'] })
|
102
|
+
.catch(throwInvalidRequest)
|
103
|
+
|
104
|
+
const dpopJkt = await server.checkDpopProof(
|
105
|
+
req.headers['dpop'],
|
106
|
+
req.method!,
|
107
|
+
this.url,
|
108
|
+
)
|
109
|
+
|
110
|
+
return server.pushedAuthorizationRequest(
|
111
|
+
credentials,
|
112
|
+
authorizationRequest,
|
113
|
+
dpopJkt,
|
114
|
+
)
|
115
|
+
}, 201),
|
116
|
+
)
|
117
|
+
// https://datatracker.ietf.org/doc/html/rfc9126#section-2.3
|
118
|
+
// > If the request did not use the POST method, the authorization server
|
119
|
+
// > responds with an HTTP 405 (Method Not Allowed) status code.
|
120
|
+
router.all('/oauth/par', (req, res) => {
|
121
|
+
res.writeHead(405).end()
|
122
|
+
})
|
123
|
+
|
124
|
+
router.options('/oauth/token', corsPreflight)
|
125
|
+
router.post(
|
126
|
+
'/oauth/token',
|
127
|
+
corsHeaders,
|
128
|
+
oauthHandler(async function (req) {
|
129
|
+
const payload = await parseHttpRequest(req, ['json', 'urlencoded'])
|
130
|
+
|
131
|
+
const clientMetadata = await server.deviceManager.getRequestMetadata(req)
|
132
|
+
|
133
|
+
const clientCredentials = await oauthClientCredentialsSchema
|
134
|
+
.parseAsync(payload, { path: ['body'] })
|
135
|
+
.catch(throwInvalidClient)
|
136
|
+
|
137
|
+
const tokenRequest = await oauthTokenRequestSchema
|
138
|
+
.parseAsync(payload, { path: ['body'] })
|
139
|
+
.catch(throwInvalidGrant)
|
140
|
+
|
141
|
+
const dpopJkt = await server.checkDpopProof(
|
142
|
+
req.headers['dpop'],
|
143
|
+
req.method!,
|
144
|
+
this.url,
|
145
|
+
)
|
146
|
+
|
147
|
+
return server.token(
|
148
|
+
clientCredentials,
|
149
|
+
clientMetadata,
|
150
|
+
tokenRequest,
|
151
|
+
dpopJkt,
|
152
|
+
)
|
153
|
+
}),
|
154
|
+
)
|
155
|
+
|
156
|
+
router.options('/oauth/revoke', corsPreflight)
|
157
|
+
router.post(
|
158
|
+
'/oauth/revoke',
|
159
|
+
corsHeaders,
|
160
|
+
oauthHandler(async function (req, res) {
|
161
|
+
const payload = await parseHttpRequest(req, ['json', 'urlencoded'])
|
162
|
+
|
163
|
+
const credentials = await oauthClientCredentialsSchema
|
164
|
+
.parseAsync(payload, { path: ['body'] })
|
165
|
+
.catch(throwInvalidRequest)
|
166
|
+
|
167
|
+
const tokenIdentification = await oauthTokenIdentificationSchema
|
168
|
+
.parseAsync(payload, { path: ['body'] })
|
169
|
+
.catch(throwInvalidRequest)
|
170
|
+
|
171
|
+
try {
|
172
|
+
await server.revoke(credentials, tokenIdentification)
|
173
|
+
} catch (err) {
|
174
|
+
// > Note: invalid tokens do not cause an error response since the
|
175
|
+
// > client cannot handle such an error in a reasonable way. Moreover,
|
176
|
+
// > the purpose of the revocation request, invalidating the particular
|
177
|
+
// > token, is already achieved.
|
178
|
+
//
|
179
|
+
// https://datatracker.ietf.org/doc/html/rfc7009#section-2.2
|
180
|
+
|
181
|
+
onError?.(req, res, err, 'Failed to revoke token')
|
182
|
+
}
|
183
|
+
|
184
|
+
return {}
|
185
|
+
}),
|
186
|
+
)
|
187
|
+
|
188
|
+
return router.buildMiddleware()
|
189
|
+
|
190
|
+
function oauthHandler<T>(
|
191
|
+
buildOAuthResponse: (this: T, req: Req, res: Res) => unknown,
|
192
|
+
status?: number,
|
193
|
+
): Middleware<T, Req, Res> {
|
194
|
+
return jsonHandler<T, Req, Res>(async function (req, res) {
|
195
|
+
try {
|
196
|
+
// https://www.rfc-editor.org/rfc/rfc6749.html#section-5.1
|
197
|
+
res.setHeader('Cache-Control', 'no-store')
|
198
|
+
res.setHeader('Pragma', 'no-cache')
|
199
|
+
|
200
|
+
// https://datatracker.ietf.org/doc/html/rfc9449#section-8.2
|
201
|
+
const dpopNonce = server.nextDpopNonce()
|
202
|
+
if (dpopNonce) {
|
203
|
+
const name = 'DPoP-Nonce'
|
204
|
+
res.setHeader(name, dpopNonce)
|
205
|
+
res.appendHeader('Access-Control-Expose-Headers', name)
|
206
|
+
}
|
207
|
+
|
208
|
+
const payload = await buildOAuthResponse.call(this, req, res)
|
209
|
+
return { payload, status }
|
210
|
+
} catch (err) {
|
211
|
+
onError?.(req, res, err, 'OAuth request error')
|
212
|
+
|
213
|
+
if (!res.headersSent && err instanceof WWWAuthenticateError) {
|
214
|
+
const name = 'WWW-Authenticate'
|
215
|
+
res.setHeader(name, err.wwwAuthenticateHeader)
|
216
|
+
res.appendHeader('Access-Control-Expose-Headers', name)
|
217
|
+
}
|
218
|
+
|
219
|
+
const status = buildErrorStatus(err)
|
220
|
+
const payload = buildErrorPayload(err)
|
221
|
+
|
222
|
+
return { payload, status }
|
223
|
+
}
|
224
|
+
})
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
function throwInvalidGrant(err: unknown): never {
|
229
|
+
throw new InvalidGrantError(
|
230
|
+
extractZodErrorMessage(err) ?? 'Invalid grant',
|
231
|
+
err,
|
232
|
+
)
|
233
|
+
}
|
234
|
+
|
235
|
+
function throwInvalidClient(err: unknown): never {
|
236
|
+
throw new InvalidClientError(
|
237
|
+
extractZodErrorMessage(err) ?? 'Client authentication failed',
|
238
|
+
err,
|
239
|
+
)
|
240
|
+
}
|
241
|
+
|
242
|
+
function throwInvalidRequest(err: unknown): never {
|
243
|
+
throw new InvalidRequestError(
|
244
|
+
extractZodErrorMessage(err) ?? 'Input validation error',
|
245
|
+
err,
|
246
|
+
)
|
247
|
+
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http'
|
2
|
+
import type { ErrorHandler } from './error-handler.js'
|
3
|
+
|
4
|
+
export type MiddlewareOptions<
|
5
|
+
Req extends IncomingMessage = IncomingMessage,
|
6
|
+
Res extends ServerResponse = ServerResponse,
|
7
|
+
> = {
|
8
|
+
onError?: ErrorHandler<Req, Res>
|
9
|
+
}
|
@@ -0,0 +1,142 @@
|
|
1
|
+
import type { ServerResponse } from 'node:http'
|
2
|
+
import {
|
3
|
+
OAuthAuthorizationRequestParameters,
|
4
|
+
OAuthResponseMode,
|
5
|
+
} from '@atproto/oauth-types'
|
6
|
+
import { AccessDeniedError } from '../errors/access-denied-error.js'
|
7
|
+
import { html, js } from '../lib/html/index.js'
|
8
|
+
import { sendWebPage } from '../lib/send-web-page.js'
|
9
|
+
import { AuthorizationRedirectParameters } from '../result/authorization-redirect-parameters.js'
|
10
|
+
|
11
|
+
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-7.5.4
|
12
|
+
const REDIRECT_STATUS_CODE = 303
|
13
|
+
|
14
|
+
export const SUCCESS_REDIRECT_KEYS = [
|
15
|
+
'code',
|
16
|
+
'id_token',
|
17
|
+
'access_token',
|
18
|
+
'expires_in',
|
19
|
+
'token_type',
|
20
|
+
] as const
|
21
|
+
|
22
|
+
export const ERROR_REDIRECT_KEYS = [
|
23
|
+
'error',
|
24
|
+
'error_description',
|
25
|
+
'error_uri',
|
26
|
+
] as const
|
27
|
+
|
28
|
+
export type OAuthRedirectQueryParameter =
|
29
|
+
| 'iss'
|
30
|
+
| 'state'
|
31
|
+
| (typeof SUCCESS_REDIRECT_KEYS)[number]
|
32
|
+
| (typeof ERROR_REDIRECT_KEYS)[number]
|
33
|
+
|
34
|
+
export function buildRedirectUri(
|
35
|
+
parameters: OAuthAuthorizationRequestParameters,
|
36
|
+
): string {
|
37
|
+
const uri = parameters.redirect_uri
|
38
|
+
if (uri) return uri
|
39
|
+
|
40
|
+
throw new AccessDeniedError(parameters, 'No redirect_uri', 'invalid_request')
|
41
|
+
}
|
42
|
+
|
43
|
+
export function buildRedirectMode(
|
44
|
+
parameters: OAuthAuthorizationRequestParameters,
|
45
|
+
): OAuthResponseMode {
|
46
|
+
const mode = parameters.response_mode || 'query' // @TODO default should depend on response_type
|
47
|
+
return mode
|
48
|
+
}
|
49
|
+
|
50
|
+
export function buildRedirectParams(
|
51
|
+
issuer: string,
|
52
|
+
parameters: OAuthAuthorizationRequestParameters,
|
53
|
+
redirect: AuthorizationRedirectParameters,
|
54
|
+
): [OAuthRedirectQueryParameter, string][] {
|
55
|
+
const params: [OAuthRedirectQueryParameter, string][] = [
|
56
|
+
['iss', issuer], // rfc9207
|
57
|
+
]
|
58
|
+
|
59
|
+
if (parameters.state != null) {
|
60
|
+
params.push(['state', parameters.state])
|
61
|
+
}
|
62
|
+
|
63
|
+
const keys = 'code' in redirect ? SUCCESS_REDIRECT_KEYS : ERROR_REDIRECT_KEYS
|
64
|
+
for (const key of keys) {
|
65
|
+
const value = redirect[key]
|
66
|
+
if (value != null) params.push([key, value])
|
67
|
+
}
|
68
|
+
|
69
|
+
return params
|
70
|
+
}
|
71
|
+
|
72
|
+
export type OAuthRedirectOptions = {
|
73
|
+
mode: OAuthResponseMode
|
74
|
+
redirectUri: string
|
75
|
+
params: Iterable<[string, string]>
|
76
|
+
}
|
77
|
+
|
78
|
+
export function sendRedirect(
|
79
|
+
res: ServerResponse,
|
80
|
+
{ mode, redirectUri: uri, params }: OAuthRedirectOptions,
|
81
|
+
): void {
|
82
|
+
res.setHeader('Cache-Control', 'no-store')
|
83
|
+
|
84
|
+
switch (mode) {
|
85
|
+
case 'query':
|
86
|
+
return writeQuery(res, uri, params)
|
87
|
+
case 'fragment':
|
88
|
+
return writeFragment(res, uri, params)
|
89
|
+
case 'form_post':
|
90
|
+
return writeFormPost(res, uri, params)
|
91
|
+
}
|
92
|
+
|
93
|
+
// @ts-expect-error fool proof
|
94
|
+
throw new Error(`Unsupported mode: ${mode}`)
|
95
|
+
}
|
96
|
+
|
97
|
+
function writeQuery(
|
98
|
+
res: ServerResponse,
|
99
|
+
uri: string,
|
100
|
+
params: Iterable<[string, string]>,
|
101
|
+
): void {
|
102
|
+
const url = new URL(uri)
|
103
|
+
for (const [key, value] of params) url.searchParams.set(key, value)
|
104
|
+
res.writeHead(REDIRECT_STATUS_CODE, { Location: url.href }).end()
|
105
|
+
}
|
106
|
+
|
107
|
+
function writeFragment(
|
108
|
+
res: ServerResponse,
|
109
|
+
uri: string,
|
110
|
+
params: Iterable<[string, string]>,
|
111
|
+
): void {
|
112
|
+
const url = new URL(uri)
|
113
|
+
const searchParams = new URLSearchParams()
|
114
|
+
for (const [key, value] of params) searchParams.set(key, value)
|
115
|
+
url.hash = searchParams.toString()
|
116
|
+
res.writeHead(REDIRECT_STATUS_CODE, { Location: url.href }).end()
|
117
|
+
}
|
118
|
+
|
119
|
+
function writeFormPost(
|
120
|
+
res: ServerResponse,
|
121
|
+
uri: string,
|
122
|
+
params: Iterable<[string, string]>,
|
123
|
+
): void {
|
124
|
+
// Prevent the Chrome from caching this page
|
125
|
+
// see: https://latesthackingnews.com/2023/12/12/google-updates-chrome-bfcache-for-faster-page-viewing/
|
126
|
+
res.setHeader('Set-Cookie', `bfCacheBypass=foo; max-age=1; SameSite=Lax`)
|
127
|
+
res.setHeader('Cache-Control', 'no-store')
|
128
|
+
res.setHeader('Permissions-Policy', 'otp-credentials=*, document-domain=()')
|
129
|
+
|
130
|
+
return sendWebPage(res, {
|
131
|
+
htmlAttrs: { lang: 'en' },
|
132
|
+
body: html`
|
133
|
+
<form method="post" action="${uri}">
|
134
|
+
${Array.from(params, ([key, value]) => [
|
135
|
+
html`<input type="hidden" name="${key}" value="${value}" />`,
|
136
|
+
])}
|
137
|
+
<input type="submit" value="Continue" />
|
138
|
+
</form>
|
139
|
+
`,
|
140
|
+
scripts: [js`document.forms[0].submit();`],
|
141
|
+
})
|
142
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { z } from 'zod'
|
2
|
+
import { jwtPayloadSchema } from '@atproto/jwk'
|
3
|
+
import { deviceIdSchema } from '../oauth-store.js'
|
4
|
+
import { subSchema } from '../oidc/sub.js'
|
5
|
+
import { requestUriSchema } from '../request/request-uri.js'
|
6
|
+
|
7
|
+
export const apiTokenPayloadSchema = jwtPayloadSchema
|
8
|
+
.extend({
|
9
|
+
sub: subSchema,
|
10
|
+
|
11
|
+
deviceId: deviceIdSchema,
|
12
|
+
// If the token is bound to a particular authorization request, it can only
|
13
|
+
// be used in the context of that request.
|
14
|
+
requestUri: requestUriSchema.optional(),
|
15
|
+
})
|
16
|
+
.passthrough()
|
17
|
+
|
18
|
+
export type ApiTokenPayload = z.infer<typeof apiTokenPayloadSchema>
|
@@ -1,35 +1,25 @@
|
|
1
1
|
import { z } from 'zod'
|
2
2
|
import { jwtPayloadSchema } from '@atproto/jwk'
|
3
3
|
import { clientIdSchema } from '../client/client-id.js'
|
4
|
-
import { Simplify } from '../lib/util/type.js'
|
5
4
|
import { subSchema } from '../oidc/sub.js'
|
6
5
|
import { tokenIdSchema } from '../token/token-id.js'
|
7
6
|
|
8
|
-
export const signedTokenPayloadSchema =
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
.
|
17
|
-
jwtPayloadSchema
|
18
|
-
.omit({
|
19
|
-
exp: true,
|
20
|
-
iat: true,
|
21
|
-
iss: true,
|
22
|
-
aud: true,
|
23
|
-
})
|
24
|
-
.partial()
|
25
|
-
.extend({
|
26
|
-
jti: tokenIdSchema,
|
27
|
-
sub: subSchema,
|
28
|
-
client_id: clientIdSchema,
|
29
|
-
})
|
30
|
-
.passthrough(),
|
31
|
-
)
|
7
|
+
export const signedTokenPayloadSchema = jwtPayloadSchema
|
8
|
+
.partial()
|
9
|
+
.extend({
|
10
|
+
// Following are required
|
11
|
+
jti: tokenIdSchema,
|
12
|
+
sub: subSchema,
|
13
|
+
exp: z.number().int(),
|
14
|
+
iat: z.number().int(),
|
15
|
+
iss: z.string().min(1),
|
32
16
|
|
33
|
-
|
34
|
-
|
35
|
-
|
17
|
+
// @NOTE "aud", "scope", "client_id" are not required, as are stored in the
|
18
|
+
// DB in 'light' access token mode.
|
19
|
+
|
20
|
+
// Restrict type of following
|
21
|
+
client_id: clientIdSchema.optional(),
|
22
|
+
})
|
23
|
+
.passthrough()
|
24
|
+
|
25
|
+
export type SignedTokenPayload = z.infer<typeof signedTokenPayloadSchema>
|