@atproto/oauth-provider 0.16.5 → 0.17.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 +32 -0
- package/dist/access-token/access-token-mode.js +2 -5
- package/dist/access-token/access-token-mode.js.map +1 -1
- package/dist/account/account-manager.js +25 -33
- package/dist/account/account-manager.js.map +1 -1
- package/dist/account/account-store.js +11 -32
- package/dist/account/account-store.js.map +1 -1
- package/dist/account/sign-in-data.js +9 -12
- package/dist/account/sign-in-data.js.map +1 -1
- package/dist/account/sign-up-input.js +14 -17
- package/dist/account/sign-up-input.js.map +1 -1
- package/dist/client/client-auth.js +1 -2
- package/dist/client/client-data.js +1 -2
- package/dist/client/client-id.js +2 -5
- package/dist/client/client-id.js.map +1 -1
- package/dist/client/client-info.js +1 -2
- package/dist/client/client-manager.js +86 -97
- package/dist/client/client-manager.js.map +1 -1
- package/dist/client/client-store.js +7 -26
- package/dist/client/client-store.js.map +1 -1
- package/dist/client/client-utils.js +10 -14
- package/dist/client/client-utils.js.map +1 -1
- package/dist/client/client.js +43 -53
- package/dist/client/client.js.map +1 -1
- package/dist/constants.js +28 -31
- package/dist/constants.js.map +1 -1
- package/dist/customization/branding.js +8 -11
- package/dist/customization/branding.js.map +1 -1
- package/dist/customization/build-customization-css.js +8 -11
- package/dist/customization/build-customization-css.js.map +1 -1
- package/dist/customization/build-customization-data.js +1 -4
- package/dist/customization/build-customization-data.js.map +1 -1
- package/dist/customization/colors.js +11 -14
- package/dist/customization/colors.js.map +1 -1
- package/dist/customization/customization.js +8 -11
- package/dist/customization/customization.js.map +1 -1
- package/dist/customization/links.js +7 -10
- package/dist/customization/links.js.map +1 -1
- package/dist/device/device-data.js +7 -10
- package/dist/device/device-data.js.map +1 -1
- package/dist/device/device-id.js +11 -16
- package/dist/device/device-id.js.map +1 -1
- package/dist/device/device-manager.js +32 -38
- package/dist/device/device-manager.js.map +1 -1
- package/dist/device/device-store.js +7 -25
- package/dist/device/device-store.js.map +1 -1
- package/dist/device/session-id.js +9 -13
- package/dist/device/session-id.js.map +1 -1
- package/dist/dpop/dpop-manager.d.ts +3 -3
- package/dist/dpop/dpop-manager.js +38 -43
- package/dist/dpop/dpop-manager.js.map +1 -1
- package/dist/dpop/dpop-nonce.d.ts +2 -2
- package/dist/dpop/dpop-nonce.d.ts.map +1 -1
- package/dist/dpop/dpop-nonce.js +14 -18
- package/dist/dpop/dpop-nonce.js.map +1 -1
- package/dist/dpop/dpop-proof.js +1 -2
- package/dist/errors/access-denied-error.js +2 -6
- package/dist/errors/access-denied-error.js.map +1 -1
- package/dist/errors/account-selection-required-error.js +2 -6
- package/dist/errors/account-selection-required-error.js.map +1 -1
- package/dist/errors/authorization-error.js +7 -12
- package/dist/errors/authorization-error.js.map +1 -1
- package/dist/errors/consent-required-error.js +2 -6
- package/dist/errors/consent-required-error.js.map +1 -1
- package/dist/errors/error-parser.js +14 -18
- package/dist/errors/error-parser.js.map +1 -1
- package/dist/errors/handle-unavailable-error.js +2 -7
- package/dist/errors/handle-unavailable-error.js.map +1 -1
- package/dist/errors/invalid-authorization-details-error.js +2 -6
- package/dist/errors/invalid-authorization-details-error.js.map +1 -1
- package/dist/errors/invalid-client-error.js +2 -6
- package/dist/errors/invalid-client-error.js.map +1 -1
- package/dist/errors/invalid-client-id-error.js +2 -6
- package/dist/errors/invalid-client-id-error.js.map +1 -1
- package/dist/errors/invalid-client-metadata-error.js +7 -11
- package/dist/errors/invalid-client-metadata-error.js.map +1 -1
- package/dist/errors/invalid-credentials-error.js +2 -7
- package/dist/errors/invalid-credentials-error.js.map +1 -1
- package/dist/errors/invalid-dpop-key-binding-error.js +2 -6
- package/dist/errors/invalid-dpop-key-binding-error.js.map +1 -1
- package/dist/errors/invalid-dpop-proof-error.js +2 -6
- package/dist/errors/invalid-dpop-proof-error.js.map +1 -1
- package/dist/errors/invalid-grant-error.js +2 -6
- package/dist/errors/invalid-grant-error.js.map +1 -1
- package/dist/errors/invalid-invite-code-error.d.ts +1 -1
- package/dist/errors/invalid-invite-code-error.d.ts.map +1 -1
- package/dist/errors/invalid-invite-code-error.js +2 -6
- package/dist/errors/invalid-invite-code-error.js.map +1 -1
- package/dist/errors/invalid-redirect-uri-error.js +2 -6
- package/dist/errors/invalid-redirect-uri-error.js.map +1 -1
- package/dist/errors/invalid-request-error.js +3 -7
- package/dist/errors/invalid-request-error.js.map +1 -1
- package/dist/errors/invalid-scope-error.js +2 -6
- package/dist/errors/invalid-scope-error.js.map +1 -1
- package/dist/errors/invalid-token-error.js +10 -15
- package/dist/errors/invalid-token-error.js.map +1 -1
- package/dist/errors/login-required-error.js +2 -6
- package/dist/errors/login-required-error.js.map +1 -1
- package/dist/errors/oauth-error.js +1 -9
- package/dist/errors/oauth-error.js.map +1 -1
- package/dist/errors/second-authentication-factor-required-error.js +2 -8
- package/dist/errors/second-authentication-factor-required-error.js.map +1 -1
- package/dist/errors/unauthorized-client-error.js +2 -6
- package/dist/errors/unauthorized-client-error.js.map +1 -1
- package/dist/errors/use-dpop-nonce-error.js +4 -8
- package/dist/errors/use-dpop-nonce-error.js.map +1 -1
- package/dist/errors/www-authenticate-error.js +4 -9
- package/dist/errors/www-authenticate-error.js.map +1 -1
- package/dist/index.js +14 -30
- package/dist/index.js.map +1 -1
- package/dist/lexicon/lexicon-data.js +1 -2
- package/dist/lexicon/lexicon-getter.js +6 -10
- package/dist/lexicon/lexicon-getter.js.map +1 -1
- package/dist/lexicon/lexicon-manager.js +10 -30
- package/dist/lexicon/lexicon-manager.js.map +1 -1
- package/dist/lexicon/lexicon-store.js +5 -10
- package/dist/lexicon/lexicon-store.js.map +1 -1
- package/dist/lib/csp/index.js +3 -8
- package/dist/lib/csp/index.js.map +1 -1
- package/dist/lib/hcaptcha.js +33 -43
- package/dist/lib/hcaptcha.js.map +1 -1
- package/dist/lib/html/build-document.js +19 -24
- package/dist/lib/html/build-document.js.map +1 -1
- package/dist/lib/html/escapers.js +10 -16
- package/dist/lib/html/escapers.js.map +1 -1
- package/dist/lib/html/html.js +1 -5
- package/dist/lib/html/html.js.map +1 -1
- package/dist/lib/html/hydration-data.js +6 -10
- package/dist/lib/html/hydration-data.js.map +1 -1
- package/dist/lib/html/index.js +3 -19
- package/dist/lib/html/index.js.map +1 -1
- package/dist/lib/html/tags.js +14 -23
- package/dist/lib/html/tags.js.map +1 -1
- package/dist/lib/html/util.js +1 -4
- package/dist/lib/html/util.js.map +1 -1
- package/dist/lib/http/accept.d.ts.map +1 -1
- package/dist/lib/http/accept.js +8 -8
- package/dist/lib/http/accept.js.map +1 -1
- package/dist/lib/http/context.js +1 -4
- package/dist/lib/http/context.js.map +1 -1
- package/dist/lib/http/headers.js +1 -4
- package/dist/lib/http/headers.js.map +1 -1
- package/dist/lib/http/index.js +10 -26
- package/dist/lib/http/index.js.map +1 -1
- package/dist/lib/http/method.js +1 -4
- package/dist/lib/http/method.js.map +1 -1
- package/dist/lib/http/middleware.js +11 -17
- package/dist/lib/http/middleware.js.map +1 -1
- package/dist/lib/http/parser.js +13 -20
- package/dist/lib/http/parser.js.map +1 -1
- package/dist/lib/http/path.js +1 -4
- package/dist/lib/http/path.js.map +1 -1
- package/dist/lib/http/request.d.ts.map +1 -1
- package/dist/lib/http/request.js +32 -47
- package/dist/lib/http/request.js.map +1 -1
- package/dist/lib/http/response.js +14 -27
- package/dist/lib/http/response.js.map +1 -1
- package/dist/lib/http/route.js +9 -12
- package/dist/lib/http/route.js.map +1 -1
- package/dist/lib/http/router.js +8 -13
- package/dist/lib/http/router.js.map +1 -1
- package/dist/lib/http/security-headers.js +10 -15
- package/dist/lib/http/security-headers.js.map +1 -1
- package/dist/lib/http/stream.js +12 -20
- package/dist/lib/http/stream.js.map +1 -1
- package/dist/lib/http/types.js +1 -2
- package/dist/lib/http/url.js +1 -4
- package/dist/lib/http/url.js.map +1 -1
- package/dist/lib/nsid.js +4 -8
- package/dist/lib/nsid.js.map +1 -1
- package/dist/lib/redis.js +4 -7
- package/dist/lib/redis.js.map +1 -1
- package/dist/lib/util/authorization-header.js +11 -15
- package/dist/lib/util/authorization-header.js.map +1 -1
- package/dist/lib/util/cast.js +3 -8
- package/dist/lib/util/cast.js.map +1 -1
- package/dist/lib/util/color.js +23 -32
- package/dist/lib/util/color.js.map +1 -1
- package/dist/lib/util/crypto.js +5 -10
- package/dist/lib/util/crypto.js.map +1 -1
- package/dist/lib/util/date.js +2 -6
- package/dist/lib/util/date.js.map +1 -1
- package/dist/lib/util/error.js +5 -8
- package/dist/lib/util/error.js.map +1 -1
- package/dist/lib/util/function.js +3 -8
- package/dist/lib/util/function.js.map +1 -1
- package/dist/lib/util/locale.js +3 -6
- package/dist/lib/util/locale.js.map +1 -1
- package/dist/lib/util/object.js +1 -4
- package/dist/lib/util/object.js.map +1 -1
- package/dist/lib/util/redirect-uri.js +3 -6
- package/dist/lib/util/redirect-uri.js.map +1 -1
- package/dist/lib/util/time.js +5 -9
- package/dist/lib/util/time.js.map +1 -1
- package/dist/lib/util/type.d.ts.map +1 -1
- package/dist/lib/util/type.js +1 -5
- package/dist/lib/util/type.js.map +1 -1
- package/dist/lib/util/ui8.js +3 -8
- package/dist/lib/util/ui8.js.map +1 -1
- package/dist/lib/util/well-known.js +1 -4
- package/dist/lib/util/well-known.js.map +1 -1
- package/dist/lib/util/zod-error.js +4 -8
- package/dist/lib/util/zod-error.js.map +1 -1
- package/dist/lib/write-form-redirect.js +9 -12
- package/dist/lib/write-form-redirect.js.map +1 -1
- package/dist/lib/write-html.js +12 -15
- package/dist/lib/write-html.js.map +1 -1
- package/dist/metadata/build-metadata.js +9 -12
- package/dist/metadata/build-metadata.js.map +1 -1
- package/dist/oauth-client.js +2 -18
- package/dist/oauth-client.js.map +1 -1
- package/dist/oauth-dpop.js +2 -18
- package/dist/oauth-dpop.js.map +1 -1
- package/dist/oauth-errors.js +24 -42
- package/dist/oauth-errors.js.map +1 -1
- package/dist/oauth-hooks.js +8 -15
- package/dist/oauth-hooks.js.map +1 -1
- package/dist/oauth-middleware.js +13 -16
- package/dist/oauth-middleware.js.map +1 -1
- package/dist/oauth-provider.js +108 -125
- package/dist/oauth-provider.js.map +1 -1
- package/dist/oauth-store.js +7 -23
- package/dist/oauth-store.js.map +1 -1
- package/dist/oauth-verifier.js +41 -53
- package/dist/oauth-verifier.js.map +1 -1
- package/dist/oidc/sub.js +2 -5
- package/dist/oidc/sub.js.map +1 -1
- package/dist/replay/replay-manager.js +6 -11
- package/dist/replay/replay-manager.js.map +1 -1
- package/dist/replay/replay-store-memory.js +5 -7
- package/dist/replay/replay-store-memory.js.map +1 -1
- package/dist/replay/replay-store-redis.js +3 -8
- package/dist/replay/replay-store-redis.js.map +1 -1
- package/dist/replay/replay-store.js +3 -8
- package/dist/replay/replay-store.js.map +1 -1
- package/dist/request/code.js +10 -15
- package/dist/request/code.js.map +1 -1
- package/dist/request/request-data.js +1 -5
- package/dist/request/request-data.js.map +1 -1
- package/dist/request/request-id.js +9 -13
- package/dist/request/request-id.js.map +1 -1
- package/dist/request/request-manager.js +61 -71
- package/dist/request/request-manager.js.map +1 -1
- package/dist/request/request-store.js +9 -27
- package/dist/request/request-store.js.map +1 -1
- package/dist/request/request-uri.js +17 -23
- package/dist/request/request-uri.js.map +1 -1
- package/dist/result/authorization-redirect-parameters.js +1 -2
- package/dist/result/authorization-result-authorize-page.js +1 -2
- package/dist/result/authorization-result-redirect.js +1 -2
- package/dist/router/assets/assets-manifest.d.ts.map +1 -1
- package/dist/router/assets/assets-manifest.js +14 -15
- package/dist/router/assets/assets-manifest.js.map +1 -1
- package/dist/router/assets/assets.d.ts.map +1 -1
- package/dist/router/assets/assets.js +25 -27
- package/dist/router/assets/assets.js.map +1 -1
- package/dist/router/assets/csrf.js +16 -25
- package/dist/router/assets/csrf.js.map +1 -1
- package/dist/router/assets/send-account-page.js +3 -6
- package/dist/router/assets/send-account-page.js.map +1 -1
- package/dist/router/assets/send-authorization-page.js +3 -6
- package/dist/router/assets/send-authorization-page.js.map +1 -1
- package/dist/router/assets/send-cookie-error-page.js +3 -6
- package/dist/router/assets/send-cookie-error-page.js.map +1 -1
- package/dist/router/assets/send-error-page.js +6 -9
- package/dist/router/assets/send-error-page.js.map +1 -1
- package/dist/router/assets/send-redirect.js +12 -20
- package/dist/router/assets/send-redirect.js.map +1 -1
- package/dist/router/create-account-page-middleware.js +11 -14
- package/dist/router/create-account-page-middleware.js.map +1 -1
- package/dist/router/create-api-middleware.js +83 -90
- package/dist/router/create-api-middleware.js.map +1 -1
- package/dist/router/create-authorization-page-middleware.js +43 -46
- package/dist/router/create-authorization-page-middleware.js.map +1 -1
- package/dist/router/create-oauth-middleware.js +31 -34
- package/dist/router/create-oauth-middleware.js.map +1 -1
- package/dist/router/error-handler.js +1 -2
- package/dist/router/middleware-options.js +1 -2
- package/dist/signer/access-token-payload.js +12 -15
- package/dist/signer/access-token-payload.js.map +1 -1
- package/dist/signer/api-token-payload.js +8 -11
- package/dist/signer/api-token-payload.js.map +1 -1
- package/dist/signer/signer.js +11 -17
- package/dist/signer/signer.js.map +1 -1
- package/dist/token/refresh-token.js +10 -15
- package/dist/token/refresh-token.js.map +1 -1
- package/dist/token/token-claims.js +1 -2
- package/dist/token/token-data.js +1 -2
- package/dist/token/token-id.js +10 -15
- package/dist/token/token-id.js.map +1 -1
- package/dist/token/token-manager.js +40 -51
- package/dist/token/token-manager.js.map +1 -1
- package/dist/token/token-store.js +7 -25
- package/dist/token/token-store.js.map +1 -1
- package/dist/types/authorization-response-error.js +8 -12
- package/dist/types/authorization-response-error.js.map +1 -1
- package/dist/types/color-hue.js +2 -5
- package/dist/types/color-hue.js.map +1 -1
- package/dist/types/email-otp.js +2 -5
- package/dist/types/email-otp.js.map +1 -1
- package/dist/types/email.js +6 -9
- package/dist/types/email.js.map +1 -1
- package/dist/types/handle.js +6 -9
- package/dist/types/handle.js.map +1 -1
- package/dist/types/invite-code.js +2 -5
- package/dist/types/invite-code.js.map +1 -1
- package/dist/types/par-response-error.js +5 -9
- package/dist/types/par-response-error.js.map +1 -1
- package/dist/types/password.js +3 -6
- package/dist/types/password.js.map +1 -1
- package/dist/types/rgb-color.js +7 -10
- package/dist/types/rgb-color.js.map +1 -1
- package/package.json +20 -22
- package/src/dpop/dpop-nonce.ts +1 -1
- package/src/errors/invalid-invite-code-error.ts +1 -1
- package/src/lib/http/accept.ts +4 -1
- package/src/lib/http/request.ts +4 -1
- package/src/lib/util/type.ts +0 -1
- package/src/router/assets/assets-manifest.ts +3 -1
- package/src/router/assets/assets.ts +2 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-manager.js","sourceRoot":"","sources":["../../src/client/client-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { Jwks, Keyset, jwksPubSchema } from '@atproto/jwk'\nimport {\n OAuthAuthorizationServerMetadata,\n OAuthClientIdDiscoverable,\n OAuthClientIdLoopback,\n OAuthClientMetadata,\n OAuthClientMetadataInput,\n isLocalHostname,\n isOAuthClientIdDiscoverable,\n isOAuthClientIdLoopback,\n oauthClientMetadataSchema,\n} from '@atproto/oauth-types'\nimport {\n Fetch,\n bindFetch,\n fetchJsonProcessor,\n fetchJsonZodProcessor,\n fetchOkProcessor,\n} from '@atproto-labs/fetch'\nimport { pipe } from '@atproto-labs/pipe'\nimport {\n CachedGetter,\n GetCachedOptions,\n SimpleStore,\n} from '@atproto-labs/simple-store'\nimport { InvalidClientMetadataError } from '../errors/invalid-client-metadata-error.js'\nimport { InvalidRedirectUriError } from '../errors/invalid-redirect-uri-error.js'\nimport { callAsync } from '../lib/util/function.js'\nimport { Awaitable } from '../lib/util/type.js'\nimport { OAuthHooks } from '../oauth-hooks.js'\nimport { ClientId } from './client-id.js'\nimport { ClientStore } from './client-store.js'\nimport { parseDiscoverableClientId, parseRedirectUri } from './client-utils.js'\nimport { Client } from './client.js'\n\nconst fetchMetadataHandler = pipe(\n fetchOkProcessor(),\n // https://www.ietf.org/archive/id/draft-ietf-oauth-client-id-metadata-document-00.html#section-4.1\n fetchJsonProcessor('application/json', true),\n fetchJsonZodProcessor(oauthClientMetadataSchema),\n)\n\nconst fetchJwksHandler = pipe(\n fetchOkProcessor(),\n fetchJsonProcessor('application/json', false),\n fetchJsonZodProcessor(jwksPubSchema),\n)\n\nexport type LoopbackMetadataGetter = (\n url: string,\n) => Awaitable<OAuthClientMetadataInput>\n\nexport class ClientManager {\n protected readonly jwks: CachedGetter<string, Jwks>\n protected readonly metadataGetter: CachedGetter<string, OAuthClientMetadata>\n\n constructor(\n protected readonly serverMetadata: OAuthAuthorizationServerMetadata,\n protected readonly keyset: Keyset,\n protected readonly hooks: OAuthHooks,\n protected readonly store: ClientStore | null,\n protected readonly loopbackMetadata: LoopbackMetadataGetter | null = null,\n safeFetch: Fetch,\n clientJwksCache: SimpleStore<string, Jwks>,\n clientMetadataCache: SimpleStore<string, OAuthClientMetadata>,\n ) {\n const fetch = bindFetch(safeFetch)\n\n this.jwks = new CachedGetter(async (uri, options) => {\n const jwks = await fetch(buildJsonGetRequest(uri, options)).then(\n fetchJwksHandler,\n )\n\n return jwks\n }, clientJwksCache)\n\n this.metadataGetter = new CachedGetter(async (uri, options) => {\n const metadata = await fetch(buildJsonGetRequest(uri, options)).then(\n fetchMetadataHandler,\n )\n\n // Validate within the getter to avoid caching invalid metadata\n return this.validateClientMetadata(uri, metadata)\n }, clientMetadataCache)\n }\n\n /**\n *\n * @see {@link https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2 OIDC Client Registration}\n */\n public async getClient(clientId: ClientId) {\n const metadata = await this.getClientMetadata(clientId).catch((err) => {\n throw InvalidClientMetadataError.from(\n err,\n `Unable to obtain client metadata for \"${clientId}\"`,\n )\n })\n\n const jwks = metadata.jwks_uri\n ? await this.jwks.get(metadata.jwks_uri).catch((err) => {\n throw InvalidClientMetadataError.from(\n err,\n `Unable to obtain jwks from \"${metadata.jwks_uri}\" for \"${clientId}\"`,\n )\n })\n : undefined\n\n const partialInfo = await callAsync(this.hooks.getClientInfo, clientId, {\n metadata,\n jwks,\n }).catch((err) => {\n throw InvalidClientMetadataError.from(\n err,\n `Rejected client information for \"${clientId}\"`,\n )\n })\n\n const isFirstParty = partialInfo?.isFirstParty ?? false\n const isTrusted = partialInfo?.isTrusted ?? isFirstParty\n\n return new Client(clientId, metadata, jwks, { isFirstParty, isTrusted })\n }\n\n public async loadClients(\n clientIds: Iterable<ClientId>,\n {\n onError = (err) => {\n throw err\n },\n }: {\n onError?: (\n err: unknown,\n clientId: ClientId,\n ) => Awaitable<Client | null | undefined>\n } = {},\n ): Promise<Map<ClientId, Client>> {\n // Make sure we don't load the same client multiple times\n const uniqueClientIds =\n clientIds instanceof Set ? clientIds : new Set(clientIds)\n\n // Load all (unique) clients in parallel\n const clients = await Promise.all(\n Array.from(uniqueClientIds, async (clientId) =>\n this.getClient(clientId).catch((err) => onError(err, clientId)),\n ),\n )\n\n // Return a map for easy lookups\n return new Map(\n clients\n .filter((c) => c != null && c instanceof Client)\n .map((c) => [c.id, c]),\n )\n }\n\n protected async getClientMetadata(\n clientId: ClientId,\n ): Promise<OAuthClientMetadata> {\n if (isOAuthClientIdLoopback(clientId)) {\n return this.getLoopbackClientMetadata(clientId)\n } else if (isOAuthClientIdDiscoverable(clientId)) {\n return this.getDiscoverableClientMetadata(clientId)\n } else if (this.store) {\n return this.getStoredClientMetadata(clientId)\n }\n\n throw new InvalidClientMetadataError(`Invalid client ID \"${clientId}\"`)\n }\n\n protected async getLoopbackClientMetadata(\n clientId: OAuthClientIdLoopback,\n ): Promise<OAuthClientMetadata> {\n const { loopbackMetadata } = this\n if (!loopbackMetadata) {\n throw new InvalidClientMetadataError('Loopback clients are not allowed')\n }\n\n const metadataRaw = await callAsync(loopbackMetadata, clientId).catch(\n (err) => {\n throw InvalidClientMetadataError.from(\n err,\n `Invalid loopback client id \"${clientId}\"`,\n )\n },\n )\n\n const metadata = await oauthClientMetadataSchema\n .parseAsync(metadataRaw)\n .catch((err) => {\n throw InvalidClientMetadataError.from(\n err,\n `Invalid loopback client metadata for \"${clientId}\"`,\n )\n })\n\n return this.validateClientMetadata(clientId, metadata)\n }\n\n protected async getDiscoverableClientMetadata(\n clientId: OAuthClientIdDiscoverable,\n ): Promise<OAuthClientMetadata> {\n const metadataUrl = parseDiscoverableClientId(clientId)\n\n const metadata = await this.metadataGetter.get(metadataUrl.href)\n\n // Note: we do *not* re-validate the metadata here, as the metadata is\n // validated within the getter. This is to avoid double validation.\n //\n // return this.validateClientMetadata(metadataUrl.href, metadata)\n return metadata\n }\n\n protected async getStoredClientMetadata(\n clientId: ClientId,\n ): Promise<OAuthClientMetadata> {\n if (this.store) {\n const metadata = await this.store.findClient(clientId)\n return this.validateClientMetadata(clientId, metadata)\n }\n\n throw new InvalidClientMetadataError(`Invalid client ID \"${clientId}\"`)\n }\n\n /**\n * This method will ensure that the client metadata is valid w.r.t. the OAuth\n * and OIDC specifications. It will also ensure that the metadata is\n * compatible with the implementation of this library, and ATPROTO's\n * requirements.\n */\n protected validateClientMetadata(\n clientId: ClientId,\n metadata: OAuthClientMetadata,\n ): OAuthClientMetadata {\n // @TODO This method should only check for rules that are specific to this\n // implementation or the ATPROTO specification. All generic validation rules\n // should be moved to the @atproto/oauth-types package.\n\n if (metadata.jwks && metadata.jwks_uri) {\n throw new InvalidClientMetadataError(\n 'jwks_uri and jwks are mutually exclusive',\n )\n }\n\n // Known OIDC specific parameters\n for (const k of [\n 'default_max_age',\n 'userinfo_signed_response_alg',\n 'id_token_signed_response_alg',\n 'userinfo_encrypted_response_alg',\n ] as const) {\n if (metadata[k] != null) {\n throw new InvalidClientMetadataError(`Unsupported \"${k}\" parameter`)\n }\n }\n\n const clientUriUrl = metadata.client_uri\n ? new URL(metadata.client_uri)\n : null\n\n if (clientUriUrl && isLocalHostname(clientUriUrl.hostname)) {\n throw new InvalidClientMetadataError('client_uri hostname is invalid')\n }\n\n const scopes = metadata.scope?.split(' ')\n\n if (!scopes) {\n throw new InvalidClientMetadataError('Missing scope property')\n }\n\n if (!scopes.includes('atproto')) {\n throw new InvalidClientMetadataError('Missing \"atproto\" scope')\n }\n\n const dupScope = scopes?.find(isDuplicate)\n if (dupScope) {\n throw new InvalidClientMetadataError(`Duplicate scope \"${dupScope}\"`)\n }\n\n const dupGrantType = metadata.grant_types.find(isDuplicate)\n if (dupGrantType) {\n throw new InvalidClientMetadataError(\n `Duplicate grant type \"${dupGrantType}\"`,\n )\n }\n\n for (const grantType of metadata.grant_types) {\n switch (grantType) {\n case 'implicit':\n // Never allowed (unsafe)\n throw new InvalidClientMetadataError(\n `Grant type \"${grantType}\" is not allowed`,\n )\n\n // @TODO Add support (e.g. for first party client)\n // case 'client_credentials':\n // case 'password':\n case 'authorization_code':\n case 'refresh_token':\n if (!this.serverMetadata.grant_types_supported?.includes(grantType)) {\n throw new InvalidClientMetadataError(\n `Unsupported grant type \"${grantType}\"`,\n )\n }\n break\n\n default:\n throw new InvalidClientMetadataError(\n `Grant type \"${grantType}\" is not supported`,\n )\n }\n }\n\n if (metadata.client_id && metadata.client_id !== clientId) {\n throw new InvalidClientMetadataError('client_id does not match')\n }\n\n if (metadata.subject_type && metadata.subject_type !== 'public') {\n throw new InvalidClientMetadataError(\n 'Only \"public\" subject_type is supported',\n )\n }\n\n switch (metadata.token_endpoint_auth_method) {\n case 'none':\n if (metadata.token_endpoint_auth_signing_alg) {\n throw new InvalidClientMetadataError(\n `token_endpoint_auth_method \"none\" must not have token_endpoint_auth_signing_alg`,\n )\n }\n break\n\n case 'private_key_jwt':\n if (!metadata.jwks && !metadata.jwks_uri) {\n throw new InvalidClientMetadataError(\n `private_key_jwt auth method requires jwks or jwks_uri`,\n )\n }\n if (metadata.jwks?.keys.length === 0) {\n throw new InvalidClientMetadataError(\n `private_key_jwt auth method requires at least one key in jwks`,\n )\n }\n if (!metadata.token_endpoint_auth_signing_alg) {\n throw new InvalidClientMetadataError(\n `Missing token_endpoint_auth_signing_alg client metadata`,\n )\n }\n break\n\n default:\n throw new InvalidClientMetadataError(\n `Unsupported client authentication method \"${metadata.token_endpoint_auth_method}\". Make sure \"token_endpoint_auth_method\" is set to one of: \"${Client.AUTH_METHODS_SUPPORTED.join('\", \"')}\"`,\n )\n }\n\n if (metadata.authorization_encrypted_response_enc) {\n throw new InvalidClientMetadataError(\n 'Encrypted authorization response is not supported',\n )\n }\n\n if (metadata.tls_client_certificate_bound_access_tokens) {\n throw new InvalidClientMetadataError(\n 'Mutual-TLS bound access tokens are not supported',\n )\n }\n\n if (\n metadata.authorization_encrypted_response_enc &&\n !metadata.authorization_encrypted_response_alg\n ) {\n throw new InvalidClientMetadataError(\n 'authorization_encrypted_response_enc requires authorization_encrypted_response_alg',\n )\n }\n\n // ATPROTO spec requires the use of DPoP (OAuth spec defaults to false)\n if (metadata.dpop_bound_access_tokens !== true) {\n throw new InvalidClientMetadataError(\n '\"dpop_bound_access_tokens\" must be true',\n )\n }\n\n // ATPROTO spec requires the use of PKCE, does not support OIDC\n if (!metadata.response_types.includes('code')) {\n throw new InvalidClientMetadataError('response_types must include \"code\"')\n } else if (!metadata.grant_types.includes('authorization_code')) {\n // Consistency check\n throw new InvalidClientMetadataError(\n `The \"code\" response type requires that \"grant_types\" contains \"authorization_code\"`,\n )\n }\n\n if (metadata.authorization_details_types?.length) {\n const dupAuthDetailsType =\n metadata.authorization_details_types.find(isDuplicate)\n if (dupAuthDetailsType) {\n throw new InvalidClientMetadataError(\n `Duplicate authorization_details_type \"${dupAuthDetailsType}\"`,\n )\n }\n\n const authorizationDetailsTypesSupported =\n this.serverMetadata.authorization_details_types_supported\n if (!authorizationDetailsTypesSupported) {\n throw new InvalidClientMetadataError(\n 'authorization_details_types are not supported',\n )\n }\n for (const type of metadata.authorization_details_types) {\n if (!authorizationDetailsTypesSupported.includes(type)) {\n throw new InvalidClientMetadataError(\n `Unsupported authorization_details_type \"${type}\"`,\n )\n }\n }\n }\n\n if (!metadata.redirect_uris?.length) {\n // ATPROTO spec requires that at least one redirect URI is provided\n\n throw new InvalidClientMetadataError(\n 'At least one redirect_uri is required',\n )\n }\n\n if (\n metadata.application_type === 'native' &&\n metadata.token_endpoint_auth_method !== 'none'\n ) {\n // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4\n //\n // > Except when using a mechanism like Dynamic Client Registration\n // > [RFC7591] to provision per-instance secrets, native apps are\n // > classified as public clients, as defined by Section 2.1 of OAuth 2.0\n // > [RFC6749]; they MUST be registered with the authorization server as\n // > such. Authorization servers MUST record the client type in the client\n // > registration details in order to identify and process requests\n // > accordingly.\n\n // @NOTE We may want to remove this restriction in the future, for example\n // if https://github.com/bluesky-social/proposals/tree/main/0010-client-assertion-backend\n // gets adopted\n\n throw new InvalidClientMetadataError(\n 'Native clients must authenticate using \"none\" method',\n )\n }\n\n if (\n metadata.application_type === 'web' &&\n metadata.grant_types.includes('implicit')\n ) {\n // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2\n //\n // > Web Clients [as defined by \"application_type\"] using the OAuth\n // > Implicit Grant Type MUST only register URLs using the https\n // > scheme as redirect_uris; they MUST NOT use localhost as the\n // > hostname.\n\n for (const redirectUri of metadata.redirect_uris) {\n const url = parseRedirectUri(redirectUri)\n if (url.protocol !== 'https:') {\n throw new InvalidRedirectUriError(\n `Web clients must use HTTPS redirect URIs`,\n )\n }\n\n if (url.hostname === 'localhost') {\n throw new InvalidRedirectUriError(\n `Web clients must not use localhost as the hostname`,\n )\n }\n }\n }\n\n for (const redirectUri of metadata.redirect_uris) {\n const url = parseRedirectUri(redirectUri)\n\n if (url.username || url.password) {\n // Is this a valid concern? Should we allow credentials in the URI?\n throw new InvalidRedirectUriError(\n `Redirect URI ${url} must not contain credentials`,\n )\n }\n\n switch (true) {\n // FIRST: Loopback redirect URI exception (only for native apps)\n\n case url.hostname === 'localhost': {\n // https://datatracker.ietf.org/doc/html/rfc8252#section-8.3\n //\n // > While redirect URIs using localhost (i.e.,\n // > \"http://localhost:{port}/{path}\") function similarly to loopback IP\n // > redirects described in Section 7.3, the use of localhost is NOT\n // > RECOMMENDED. Specifying a redirect URI with the loopback IP literal\n // > rather than localhost avoids inadvertently listening on network\n // > interfaces other than the loopback interface. It is also less\n // > susceptible to client-side firewalls and misconfigured host name\n // > resolution on the user's device.\n throw new InvalidRedirectUriError(\n `Loopback redirect URI ${url} is not allowed (use explicit IPs instead)`,\n )\n }\n\n case url.hostname === '127.0.0.1':\n case url.hostname === '[::1]': {\n // Only allowed for native apps\n if (metadata.application_type !== 'native') {\n throw new InvalidRedirectUriError(\n `Loopback redirect URIs are only allowed for native apps`,\n )\n }\n\n if (url.port) {\n // https://datatracker.ietf.org/doc/html/rfc8252#section-7.3\n //\n // > The authorization server MUST allow any port to be specified at\n // > the time of the request for loopback IP redirect URIs, to\n // > accommodate clients that obtain an available ephemeral port\n // > from the operating system at the time of the request.\n //\n // Note: although validation of the redirect_uri will ignore the\n // port we still allow it to be specified, as the spec does not\n // forbid it. If a port number is specified, ports will need to\n // match when validating authorization requests. See\n // \"compareRedirectUri()\".\n }\n\n if (url.protocol !== 'http:') {\n // https://datatracker.ietf.org/doc/html/rfc8252#section-7.3\n //\n // > Loopback redirect URIs use the \"http\" scheme and are constructed\n // > with the loopback IP literal and whatever port the client is\n // > listening on. That is, \"http://127.0.0.1:{port}/{path}\" for IPv4,\n // > and \"http://[::1]:{port}/{path}\" for IPv6.\n throw new InvalidRedirectUriError(\n `Loopback redirect URI ${url} must use HTTP`,\n )\n }\n\n break\n }\n\n // SECOND: Protocol-based URI Redirection\n\n case url.protocol === 'http:': {\n // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2\n //\n // > request_uri [...] URLs MUST use the https scheme unless the\n // > target Request Object is signed in a way that is verifiable by\n // > the OP.\n //\n // OIDC/Request Object are not supported. ATproto spec should not\n // allow HTTP redirect URIs either.\n\n // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2\n //\n // > Authorization Servers MAY reject Redirection URI values using\n // > the http scheme, other than the loopback case for Native\n // > Clients.\n throw new InvalidRedirectUriError(\n 'Only loopback redirect URIs are allowed to use the \"http\" scheme',\n )\n }\n\n case url.protocol === 'https:': {\n if (isLocalHostname(url.hostname)) {\n throw new InvalidRedirectUriError(\n `Redirect URI \"${url}\"'s domain name must not be a local hostname`,\n )\n }\n\n // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4\n //\n // > In addition to the collision-resistant properties, requiring a\n // > URI scheme based on a domain name that is under the control of\n // > the app can help to prove ownership in the event of a dispute\n // > where two apps claim the same private-use URI scheme (where one\n // > app is acting maliciously).\n //\n // We can't enforce this here (in generic client validation) because\n // we don't have a concept of generic proven ownership.\n //\n // Discoverable clients, however, will have this check covered in the\n // `validateDiscoverableClientMetadata`, by using the client_id's\n // domain as \"proven ownership\".\n\n // The following restriction from OIDC is *not* enforced for clients\n // as it prevents \"App Links\" / \"Apple Universal Links\" from being\n // used as redirect URIs.\n //\n // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2\n //\n // > Native Clients [as defined by \"application_type\"] MUST only\n // > register redirect_uris using custom URI schemes or loopback URLs\n // > using the http scheme; loopback URLs use localhost or the IP\n // > loopback literals 127.0.0.1 or [::1] as the hostname.\n //\n // if (metadata.application_type === 'native') {\n // throw new InvalidRedirectUriError(\n // `Native clients must use custom URI schemes or loopback URLs`,\n // )\n // }\n\n break\n }\n\n case isPrivateUseUriScheme(url): {\n if (metadata.application_type !== 'native') {\n throw new InvalidRedirectUriError(\n `Private-Use URI Scheme redirect URI are only allowed for native apps`,\n )\n }\n\n break\n }\n\n default:\n // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4\n //\n // > At a minimum, any private-use URI scheme that doesn't contain a\n // > period character (\".\") SHOULD be rejected.\n throw new InvalidRedirectUriError(\n `Invalid redirect URI scheme \"${url.protocol}\"`,\n )\n }\n }\n\n if (isOAuthClientIdLoopback(clientId)) {\n return this.validateLoopbackClientMetadata(clientId, metadata)\n } else if (isOAuthClientIdDiscoverable(clientId)) {\n return this.validateDiscoverableClientMetadata(clientId, metadata)\n } else {\n return metadata\n }\n }\n\n validateLoopbackClientMetadata(\n clientId: OAuthClientIdLoopback,\n metadata: OAuthClientMetadata,\n ): OAuthClientMetadata {\n if (metadata.client_uri) {\n throw new InvalidClientMetadataError(\n 'client_uri is not allowed for loopback clients',\n )\n }\n\n if (metadata.application_type !== 'native') {\n throw new InvalidClientMetadataError(\n 'Loopback clients must have application_type \"native\"',\n )\n }\n\n const method = metadata.token_endpoint_auth_method\n if (method !== 'none') {\n throw new InvalidClientMetadataError(\n `Loopback clients are not allowed to use \"token_endpoint_auth_method\" ${method}`,\n )\n }\n\n return metadata\n }\n\n validateDiscoverableClientMetadata(\n clientId: OAuthClientIdDiscoverable,\n metadata: OAuthClientMetadata,\n ): OAuthClientMetadata {\n if (!metadata.client_id) {\n // https://www.ietf.org/archive/id/draft-ietf-oauth-client-id-metadata-document-00.html\n throw new InvalidClientMetadataError(\n `client_id is required for discoverable clients`,\n )\n }\n\n const clientIdUrl = parseDiscoverableClientId(clientId)\n\n if (metadata.client_uri) {\n // https://www.ietf.org/archive/id/draft-ietf-oauth-client-id-metadata-document-00.html\n //\n // The client_uri must be a parent of the client_id URL. This might be\n // relaxed in the future.\n\n const clientUriUrl = new URL(metadata.client_uri)\n\n if (clientUriUrl.origin !== clientIdUrl.origin) {\n throw new InvalidClientMetadataError(\n `client_uri must have the same origin as the client_id`,\n )\n }\n\n if (clientIdUrl.pathname !== clientUriUrl.pathname) {\n if (\n !clientIdUrl.pathname.startsWith(\n clientUriUrl.pathname.endsWith('/')\n ? clientUriUrl.pathname\n : `${clientUriUrl.pathname}/`,\n )\n ) {\n throw new InvalidClientMetadataError(\n `client_uri must be a parent URL of the client_id`,\n )\n }\n }\n }\n\n for (const redirectUri of metadata.redirect_uris) {\n // @NOTE at this point, all redirect URIs have already been validated by\n // oauthRedirectUriSchema\n\n const url = parseRedirectUri(redirectUri)\n\n if (isPrivateUseUriScheme(url)) {\n // https://datatracker.ietf.org/doc/html/rfc8252#section-7.1\n //\n // > When choosing a URI scheme to associate with the app, apps MUST use\n // > a URI scheme based on a domain name under their control, expressed\n // > in reverse order, as recommended by Section 3.8 of [RFC7595] for\n // > private-use URI schemes.\n\n // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4\n //\n // > In addition to the collision-resistant properties, requiring a\n // > URI scheme based on a domain name that is under the control of\n // > the app can help to prove ownership in the event of a dispute\n // > where two apps claim the same private-use URI scheme (where one\n // > app is acting maliciously).\n\n // https://atproto.com/specs/oauth\n //\n // > Any custom scheme must match the client_id hostname in\n // > reverse-domain order. The URI scheme must be followed by a single\n // > colon (:) then a single forward slash (/) and then a URI path\n // > component. For example, an app with client_id\n // > https://app.example.com/client-metadata.json could have a\n // > redirect_uri of com.example.app:/callback.\n const protocol = `${reverseDomain(clientIdUrl.hostname)}:`\n if (url.protocol !== protocol) {\n throw new InvalidRedirectUriError(\n `Private-Use URI Scheme redirect URI, for discoverable client metadata, must be the fully qualified domain name (FQDN) of the client_id, in reverse order (${protocol})`,\n )\n }\n }\n }\n\n return metadata\n }\n}\n\nfunction isDuplicate<\n T extends string | number | boolean | null | undefined | symbol,\n>(value: T, index: number, array: T[]) {\n return array.includes(value, index + 1)\n}\n\nfunction reverseDomain(domain: string) {\n return domain.split('.').reverse().join('.')\n}\n\nfunction isPrivateUseUriScheme(uri: URL) {\n return uri.protocol.includes('.')\n}\n\nfunction buildJsonGetRequest(uri: string, options?: GetCachedOptions) {\n return new Request(uri, {\n headers: { accept: 'application/json' },\n // @ts-expect-error invalid types in \"undici-types\"\n cache: options?.noCache ? 'no-cache' : undefined,\n signal: options?.signal,\n redirect: 'error',\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"client-manager.js","sourceRoot":"","sources":["../../src/client/client-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { Jwks, Keyset, jwksPubSchema } from '@atproto/jwk'\nimport {\n OAuthAuthorizationServerMetadata,\n OAuthClientIdDiscoverable,\n OAuthClientIdLoopback,\n OAuthClientMetadata,\n OAuthClientMetadataInput,\n isLocalHostname,\n isOAuthClientIdDiscoverable,\n isOAuthClientIdLoopback,\n oauthClientMetadataSchema,\n} from '@atproto/oauth-types'\nimport {\n Fetch,\n bindFetch,\n fetchJsonProcessor,\n fetchJsonZodProcessor,\n fetchOkProcessor,\n} from '@atproto-labs/fetch'\nimport { pipe } from '@atproto-labs/pipe'\nimport {\n CachedGetter,\n GetCachedOptions,\n SimpleStore,\n} from '@atproto-labs/simple-store'\nimport { InvalidClientMetadataError } from '../errors/invalid-client-metadata-error.js'\nimport { InvalidRedirectUriError } from '../errors/invalid-redirect-uri-error.js'\nimport { callAsync } from '../lib/util/function.js'\nimport { Awaitable } from '../lib/util/type.js'\nimport { OAuthHooks } from '../oauth-hooks.js'\nimport { ClientId } from './client-id.js'\nimport { ClientStore } from './client-store.js'\nimport { parseDiscoverableClientId, parseRedirectUri } from './client-utils.js'\nimport { Client } from './client.js'\n\nconst fetchMetadataHandler = pipe(\n fetchOkProcessor(),\n // https://www.ietf.org/archive/id/draft-ietf-oauth-client-id-metadata-document-00.html#section-4.1\n fetchJsonProcessor('application/json', true),\n fetchJsonZodProcessor(oauthClientMetadataSchema),\n)\n\nconst fetchJwksHandler = pipe(\n fetchOkProcessor(),\n fetchJsonProcessor('application/json', false),\n fetchJsonZodProcessor(jwksPubSchema),\n)\n\nexport type LoopbackMetadataGetter = (\n url: string,\n) => Awaitable<OAuthClientMetadataInput>\n\nexport class ClientManager {\n protected readonly jwks: CachedGetter<string, Jwks>\n protected readonly metadataGetter: CachedGetter<string, OAuthClientMetadata>\n\n constructor(\n protected readonly serverMetadata: OAuthAuthorizationServerMetadata,\n protected readonly keyset: Keyset,\n protected readonly hooks: OAuthHooks,\n protected readonly store: ClientStore | null,\n protected readonly loopbackMetadata: LoopbackMetadataGetter | null = null,\n safeFetch: Fetch,\n clientJwksCache: SimpleStore<string, Jwks>,\n clientMetadataCache: SimpleStore<string, OAuthClientMetadata>,\n ) {\n const fetch = bindFetch(safeFetch)\n\n this.jwks = new CachedGetter(async (uri, options) => {\n const jwks = await fetch(buildJsonGetRequest(uri, options)).then(\n fetchJwksHandler,\n )\n\n return jwks\n }, clientJwksCache)\n\n this.metadataGetter = new CachedGetter(async (uri, options) => {\n const metadata = await fetch(buildJsonGetRequest(uri, options)).then(\n fetchMetadataHandler,\n )\n\n // Validate within the getter to avoid caching invalid metadata\n return this.validateClientMetadata(uri, metadata)\n }, clientMetadataCache)\n }\n\n /**\n *\n * @see {@link https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2 OIDC Client Registration}\n */\n public async getClient(clientId: ClientId) {\n const metadata = await this.getClientMetadata(clientId).catch((err) => {\n throw InvalidClientMetadataError.from(\n err,\n `Unable to obtain client metadata for \"${clientId}\"`,\n )\n })\n\n const jwks = metadata.jwks_uri\n ? await this.jwks.get(metadata.jwks_uri).catch((err) => {\n throw InvalidClientMetadataError.from(\n err,\n `Unable to obtain jwks from \"${metadata.jwks_uri}\" for \"${clientId}\"`,\n )\n })\n : undefined\n\n const partialInfo = await callAsync(this.hooks.getClientInfo, clientId, {\n metadata,\n jwks,\n }).catch((err) => {\n throw InvalidClientMetadataError.from(\n err,\n `Rejected client information for \"${clientId}\"`,\n )\n })\n\n const isFirstParty = partialInfo?.isFirstParty ?? false\n const isTrusted = partialInfo?.isTrusted ?? isFirstParty\n\n return new Client(clientId, metadata, jwks, { isFirstParty, isTrusted })\n }\n\n public async loadClients(\n clientIds: Iterable<ClientId>,\n {\n onError = (err) => {\n throw err\n },\n }: {\n onError?: (\n err: unknown,\n clientId: ClientId,\n ) => Awaitable<Client | null | undefined>\n } = {},\n ): Promise<Map<ClientId, Client>> {\n // Make sure we don't load the same client multiple times\n const uniqueClientIds =\n clientIds instanceof Set ? clientIds : new Set(clientIds)\n\n // Load all (unique) clients in parallel\n const clients = await Promise.all(\n Array.from(uniqueClientIds, async (clientId) =>\n this.getClient(clientId).catch((err) => onError(err, clientId)),\n ),\n )\n\n // Return a map for easy lookups\n return new Map(\n clients\n .filter((c) => c != null && c instanceof Client)\n .map((c) => [c.id, c]),\n )\n }\n\n protected async getClientMetadata(\n clientId: ClientId,\n ): Promise<OAuthClientMetadata> {\n if (isOAuthClientIdLoopback(clientId)) {\n return this.getLoopbackClientMetadata(clientId)\n } else if (isOAuthClientIdDiscoverable(clientId)) {\n return this.getDiscoverableClientMetadata(clientId)\n } else if (this.store) {\n return this.getStoredClientMetadata(clientId)\n }\n\n throw new InvalidClientMetadataError(`Invalid client ID \"${clientId}\"`)\n }\n\n protected async getLoopbackClientMetadata(\n clientId: OAuthClientIdLoopback,\n ): Promise<OAuthClientMetadata> {\n const { loopbackMetadata } = this\n if (!loopbackMetadata) {\n throw new InvalidClientMetadataError('Loopback clients are not allowed')\n }\n\n const metadataRaw = await callAsync(loopbackMetadata, clientId).catch(\n (err) => {\n throw InvalidClientMetadataError.from(\n err,\n `Invalid loopback client id \"${clientId}\"`,\n )\n },\n )\n\n const metadata = await oauthClientMetadataSchema\n .parseAsync(metadataRaw)\n .catch((err) => {\n throw InvalidClientMetadataError.from(\n err,\n `Invalid loopback client metadata for \"${clientId}\"`,\n )\n })\n\n return this.validateClientMetadata(clientId, metadata)\n }\n\n protected async getDiscoverableClientMetadata(\n clientId: OAuthClientIdDiscoverable,\n ): Promise<OAuthClientMetadata> {\n const metadataUrl = parseDiscoverableClientId(clientId)\n\n const metadata = await this.metadataGetter.get(metadataUrl.href)\n\n // Note: we do *not* re-validate the metadata here, as the metadata is\n // validated within the getter. This is to avoid double validation.\n //\n // return this.validateClientMetadata(metadataUrl.href, metadata)\n return metadata\n }\n\n protected async getStoredClientMetadata(\n clientId: ClientId,\n ): Promise<OAuthClientMetadata> {\n if (this.store) {\n const metadata = await this.store.findClient(clientId)\n return this.validateClientMetadata(clientId, metadata)\n }\n\n throw new InvalidClientMetadataError(`Invalid client ID \"${clientId}\"`)\n }\n\n /**\n * This method will ensure that the client metadata is valid w.r.t. the OAuth\n * and OIDC specifications. It will also ensure that the metadata is\n * compatible with the implementation of this library, and ATPROTO's\n * requirements.\n */\n protected validateClientMetadata(\n clientId: ClientId,\n metadata: OAuthClientMetadata,\n ): OAuthClientMetadata {\n // @TODO This method should only check for rules that are specific to this\n // implementation or the ATPROTO specification. All generic validation rules\n // should be moved to the @atproto/oauth-types package.\n\n if (metadata.jwks && metadata.jwks_uri) {\n throw new InvalidClientMetadataError(\n 'jwks_uri and jwks are mutually exclusive',\n )\n }\n\n // Known OIDC specific parameters\n for (const k of [\n 'default_max_age',\n 'userinfo_signed_response_alg',\n 'id_token_signed_response_alg',\n 'userinfo_encrypted_response_alg',\n ] as const) {\n if (metadata[k] != null) {\n throw new InvalidClientMetadataError(`Unsupported \"${k}\" parameter`)\n }\n }\n\n const clientUriUrl = metadata.client_uri\n ? new URL(metadata.client_uri)\n : null\n\n if (clientUriUrl && isLocalHostname(clientUriUrl.hostname)) {\n throw new InvalidClientMetadataError('client_uri hostname is invalid')\n }\n\n const scopes = metadata.scope?.split(' ')\n\n if (!scopes) {\n throw new InvalidClientMetadataError('Missing scope property')\n }\n\n if (!scopes.includes('atproto')) {\n throw new InvalidClientMetadataError('Missing \"atproto\" scope')\n }\n\n const dupScope = scopes?.find(isDuplicate)\n if (dupScope) {\n throw new InvalidClientMetadataError(`Duplicate scope \"${dupScope}\"`)\n }\n\n const dupGrantType = metadata.grant_types.find(isDuplicate)\n if (dupGrantType) {\n throw new InvalidClientMetadataError(\n `Duplicate grant type \"${dupGrantType}\"`,\n )\n }\n\n for (const grantType of metadata.grant_types) {\n switch (grantType) {\n case 'implicit':\n // Never allowed (unsafe)\n throw new InvalidClientMetadataError(\n `Grant type \"${grantType}\" is not allowed`,\n )\n\n // @TODO Add support (e.g. for first party client)\n // case 'client_credentials':\n // case 'password':\n case 'authorization_code':\n case 'refresh_token':\n if (!this.serverMetadata.grant_types_supported?.includes(grantType)) {\n throw new InvalidClientMetadataError(\n `Unsupported grant type \"${grantType}\"`,\n )\n }\n break\n\n default:\n throw new InvalidClientMetadataError(\n `Grant type \"${grantType}\" is not supported`,\n )\n }\n }\n\n if (metadata.client_id && metadata.client_id !== clientId) {\n throw new InvalidClientMetadataError('client_id does not match')\n }\n\n if (metadata.subject_type && metadata.subject_type !== 'public') {\n throw new InvalidClientMetadataError(\n 'Only \"public\" subject_type is supported',\n )\n }\n\n switch (metadata.token_endpoint_auth_method) {\n case 'none':\n if (metadata.token_endpoint_auth_signing_alg) {\n throw new InvalidClientMetadataError(\n `token_endpoint_auth_method \"none\" must not have token_endpoint_auth_signing_alg`,\n )\n }\n break\n\n case 'private_key_jwt':\n if (!metadata.jwks && !metadata.jwks_uri) {\n throw new InvalidClientMetadataError(\n `private_key_jwt auth method requires jwks or jwks_uri`,\n )\n }\n if (metadata.jwks?.keys.length === 0) {\n throw new InvalidClientMetadataError(\n `private_key_jwt auth method requires at least one key in jwks`,\n )\n }\n if (!metadata.token_endpoint_auth_signing_alg) {\n throw new InvalidClientMetadataError(\n `Missing token_endpoint_auth_signing_alg client metadata`,\n )\n }\n break\n\n default:\n throw new InvalidClientMetadataError(\n `Unsupported client authentication method \"${metadata.token_endpoint_auth_method}\". Make sure \"token_endpoint_auth_method\" is set to one of: \"${Client.AUTH_METHODS_SUPPORTED.join('\", \"')}\"`,\n )\n }\n\n if (metadata.authorization_encrypted_response_enc) {\n throw new InvalidClientMetadataError(\n 'Encrypted authorization response is not supported',\n )\n }\n\n if (metadata.tls_client_certificate_bound_access_tokens) {\n throw new InvalidClientMetadataError(\n 'Mutual-TLS bound access tokens are not supported',\n )\n }\n\n if (\n metadata.authorization_encrypted_response_enc &&\n !metadata.authorization_encrypted_response_alg\n ) {\n throw new InvalidClientMetadataError(\n 'authorization_encrypted_response_enc requires authorization_encrypted_response_alg',\n )\n }\n\n // ATPROTO spec requires the use of DPoP (OAuth spec defaults to false)\n if (metadata.dpop_bound_access_tokens !== true) {\n throw new InvalidClientMetadataError(\n '\"dpop_bound_access_tokens\" must be true',\n )\n }\n\n // ATPROTO spec requires the use of PKCE, does not support OIDC\n if (!metadata.response_types.includes('code')) {\n throw new InvalidClientMetadataError('response_types must include \"code\"')\n } else if (!metadata.grant_types.includes('authorization_code')) {\n // Consistency check\n throw new InvalidClientMetadataError(\n `The \"code\" response type requires that \"grant_types\" contains \"authorization_code\"`,\n )\n }\n\n if (metadata.authorization_details_types?.length) {\n const dupAuthDetailsType =\n metadata.authorization_details_types.find(isDuplicate)\n if (dupAuthDetailsType) {\n throw new InvalidClientMetadataError(\n `Duplicate authorization_details_type \"${dupAuthDetailsType}\"`,\n )\n }\n\n const authorizationDetailsTypesSupported =\n this.serverMetadata.authorization_details_types_supported\n if (!authorizationDetailsTypesSupported) {\n throw new InvalidClientMetadataError(\n 'authorization_details_types are not supported',\n )\n }\n for (const type of metadata.authorization_details_types) {\n if (!authorizationDetailsTypesSupported.includes(type)) {\n throw new InvalidClientMetadataError(\n `Unsupported authorization_details_type \"${type}\"`,\n )\n }\n }\n }\n\n if (!metadata.redirect_uris?.length) {\n // ATPROTO spec requires that at least one redirect URI is provided\n\n throw new InvalidClientMetadataError(\n 'At least one redirect_uri is required',\n )\n }\n\n if (\n metadata.application_type === 'native' &&\n metadata.token_endpoint_auth_method !== 'none'\n ) {\n // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4\n //\n // > Except when using a mechanism like Dynamic Client Registration\n // > [RFC7591] to provision per-instance secrets, native apps are\n // > classified as public clients, as defined by Section 2.1 of OAuth 2.0\n // > [RFC6749]; they MUST be registered with the authorization server as\n // > such. Authorization servers MUST record the client type in the client\n // > registration details in order to identify and process requests\n // > accordingly.\n\n // @NOTE We may want to remove this restriction in the future, for example\n // if https://github.com/bluesky-social/proposals/tree/main/0010-client-assertion-backend\n // gets adopted\n\n throw new InvalidClientMetadataError(\n 'Native clients must authenticate using \"none\" method',\n )\n }\n\n if (\n metadata.application_type === 'web' &&\n metadata.grant_types.includes('implicit')\n ) {\n // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2\n //\n // > Web Clients [as defined by \"application_type\"] using the OAuth\n // > Implicit Grant Type MUST only register URLs using the https\n // > scheme as redirect_uris; they MUST NOT use localhost as the\n // > hostname.\n\n for (const redirectUri of metadata.redirect_uris) {\n const url = parseRedirectUri(redirectUri)\n if (url.protocol !== 'https:') {\n throw new InvalidRedirectUriError(\n `Web clients must use HTTPS redirect URIs`,\n )\n }\n\n if (url.hostname === 'localhost') {\n throw new InvalidRedirectUriError(\n `Web clients must not use localhost as the hostname`,\n )\n }\n }\n }\n\n for (const redirectUri of metadata.redirect_uris) {\n const url = parseRedirectUri(redirectUri)\n\n if (url.username || url.password) {\n // Is this a valid concern? Should we allow credentials in the URI?\n throw new InvalidRedirectUriError(\n `Redirect URI ${url} must not contain credentials`,\n )\n }\n\n switch (true) {\n // FIRST: Loopback redirect URI exception (only for native apps)\n\n case url.hostname === 'localhost': {\n // https://datatracker.ietf.org/doc/html/rfc8252#section-8.3\n //\n // > While redirect URIs using localhost (i.e.,\n // > \"http://localhost:{port}/{path}\") function similarly to loopback IP\n // > redirects described in Section 7.3, the use of localhost is NOT\n // > RECOMMENDED. Specifying a redirect URI with the loopback IP literal\n // > rather than localhost avoids inadvertently listening on network\n // > interfaces other than the loopback interface. It is also less\n // > susceptible to client-side firewalls and misconfigured host name\n // > resolution on the user's device.\n throw new InvalidRedirectUriError(\n `Loopback redirect URI ${url} is not allowed (use explicit IPs instead)`,\n )\n }\n\n case url.hostname === '127.0.0.1':\n case url.hostname === '[::1]': {\n // Only allowed for native apps\n if (metadata.application_type !== 'native') {\n throw new InvalidRedirectUriError(\n `Loopback redirect URIs are only allowed for native apps`,\n )\n }\n\n if (url.port) {\n // https://datatracker.ietf.org/doc/html/rfc8252#section-7.3\n //\n // > The authorization server MUST allow any port to be specified at\n // > the time of the request for loopback IP redirect URIs, to\n // > accommodate clients that obtain an available ephemeral port\n // > from the operating system at the time of the request.\n //\n // Note: although validation of the redirect_uri will ignore the\n // port we still allow it to be specified, as the spec does not\n // forbid it. If a port number is specified, ports will need to\n // match when validating authorization requests. See\n // \"compareRedirectUri()\".\n }\n\n if (url.protocol !== 'http:') {\n // https://datatracker.ietf.org/doc/html/rfc8252#section-7.3\n //\n // > Loopback redirect URIs use the \"http\" scheme and are constructed\n // > with the loopback IP literal and whatever port the client is\n // > listening on. That is, \"http://127.0.0.1:{port}/{path}\" for IPv4,\n // > and \"http://[::1]:{port}/{path}\" for IPv6.\n throw new InvalidRedirectUriError(\n `Loopback redirect URI ${url} must use HTTP`,\n )\n }\n\n break\n }\n\n // SECOND: Protocol-based URI Redirection\n\n case url.protocol === 'http:': {\n // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2\n //\n // > request_uri [...] URLs MUST use the https scheme unless the\n // > target Request Object is signed in a way that is verifiable by\n // > the OP.\n //\n // OIDC/Request Object are not supported. ATproto spec should not\n // allow HTTP redirect URIs either.\n\n // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2\n //\n // > Authorization Servers MAY reject Redirection URI values using\n // > the http scheme, other than the loopback case for Native\n // > Clients.\n throw new InvalidRedirectUriError(\n 'Only loopback redirect URIs are allowed to use the \"http\" scheme',\n )\n }\n\n case url.protocol === 'https:': {\n if (isLocalHostname(url.hostname)) {\n throw new InvalidRedirectUriError(\n `Redirect URI \"${url}\"'s domain name must not be a local hostname`,\n )\n }\n\n // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4\n //\n // > In addition to the collision-resistant properties, requiring a\n // > URI scheme based on a domain name that is under the control of\n // > the app can help to prove ownership in the event of a dispute\n // > where two apps claim the same private-use URI scheme (where one\n // > app is acting maliciously).\n //\n // We can't enforce this here (in generic client validation) because\n // we don't have a concept of generic proven ownership.\n //\n // Discoverable clients, however, will have this check covered in the\n // `validateDiscoverableClientMetadata`, by using the client_id's\n // domain as \"proven ownership\".\n\n // The following restriction from OIDC is *not* enforced for clients\n // as it prevents \"App Links\" / \"Apple Universal Links\" from being\n // used as redirect URIs.\n //\n // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2\n //\n // > Native Clients [as defined by \"application_type\"] MUST only\n // > register redirect_uris using custom URI schemes or loopback URLs\n // > using the http scheme; loopback URLs use localhost or the IP\n // > loopback literals 127.0.0.1 or [::1] as the hostname.\n //\n // if (metadata.application_type === 'native') {\n // throw new InvalidRedirectUriError(\n // `Native clients must use custom URI schemes or loopback URLs`,\n // )\n // }\n\n break\n }\n\n case isPrivateUseUriScheme(url): {\n if (metadata.application_type !== 'native') {\n throw new InvalidRedirectUriError(\n `Private-Use URI Scheme redirect URI are only allowed for native apps`,\n )\n }\n\n break\n }\n\n default:\n // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4\n //\n // > At a minimum, any private-use URI scheme that doesn't contain a\n // > period character (\".\") SHOULD be rejected.\n throw new InvalidRedirectUriError(\n `Invalid redirect URI scheme \"${url.protocol}\"`,\n )\n }\n }\n\n if (isOAuthClientIdLoopback(clientId)) {\n return this.validateLoopbackClientMetadata(clientId, metadata)\n } else if (isOAuthClientIdDiscoverable(clientId)) {\n return this.validateDiscoverableClientMetadata(clientId, metadata)\n } else {\n return metadata\n }\n }\n\n validateLoopbackClientMetadata(\n clientId: OAuthClientIdLoopback,\n metadata: OAuthClientMetadata,\n ): OAuthClientMetadata {\n if (metadata.client_uri) {\n throw new InvalidClientMetadataError(\n 'client_uri is not allowed for loopback clients',\n )\n }\n\n if (metadata.application_type !== 'native') {\n throw new InvalidClientMetadataError(\n 'Loopback clients must have application_type \"native\"',\n )\n }\n\n const method = metadata.token_endpoint_auth_method\n if (method !== 'none') {\n throw new InvalidClientMetadataError(\n `Loopback clients are not allowed to use \"token_endpoint_auth_method\" ${method}`,\n )\n }\n\n return metadata\n }\n\n validateDiscoverableClientMetadata(\n clientId: OAuthClientIdDiscoverable,\n metadata: OAuthClientMetadata,\n ): OAuthClientMetadata {\n if (!metadata.client_id) {\n // https://www.ietf.org/archive/id/draft-ietf-oauth-client-id-metadata-document-00.html\n throw new InvalidClientMetadataError(\n `client_id is required for discoverable clients`,\n )\n }\n\n const clientIdUrl = parseDiscoverableClientId(clientId)\n\n if (metadata.client_uri) {\n // https://www.ietf.org/archive/id/draft-ietf-oauth-client-id-metadata-document-00.html\n //\n // The client_uri must be a parent of the client_id URL. This might be\n // relaxed in the future.\n\n const clientUriUrl = new URL(metadata.client_uri)\n\n if (clientUriUrl.origin !== clientIdUrl.origin) {\n throw new InvalidClientMetadataError(\n `client_uri must have the same origin as the client_id`,\n )\n }\n\n if (clientIdUrl.pathname !== clientUriUrl.pathname) {\n if (\n !clientIdUrl.pathname.startsWith(\n clientUriUrl.pathname.endsWith('/')\n ? clientUriUrl.pathname\n : `${clientUriUrl.pathname}/`,\n )\n ) {\n throw new InvalidClientMetadataError(\n `client_uri must be a parent URL of the client_id`,\n )\n }\n }\n }\n\n for (const redirectUri of metadata.redirect_uris) {\n // @NOTE at this point, all redirect URIs have already been validated by\n // oauthRedirectUriSchema\n\n const url = parseRedirectUri(redirectUri)\n\n if (isPrivateUseUriScheme(url)) {\n // https://datatracker.ietf.org/doc/html/rfc8252#section-7.1\n //\n // > When choosing a URI scheme to associate with the app, apps MUST use\n // > a URI scheme based on a domain name under their control, expressed\n // > in reverse order, as recommended by Section 3.8 of [RFC7595] for\n // > private-use URI schemes.\n\n // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4\n //\n // > In addition to the collision-resistant properties, requiring a\n // > URI scheme based on a domain name that is under the control of\n // > the app can help to prove ownership in the event of a dispute\n // > where two apps claim the same private-use URI scheme (where one\n // > app is acting maliciously).\n\n // https://atproto.com/specs/oauth\n //\n // > Any custom scheme must match the client_id hostname in\n // > reverse-domain order. The URI scheme must be followed by a single\n // > colon (:) then a single forward slash (/) and then a URI path\n // > component. For example, an app with client_id\n // > https://app.example.com/client-metadata.json could have a\n // > redirect_uri of com.example.app:/callback.\n const protocol = `${reverseDomain(clientIdUrl.hostname)}:`\n if (url.protocol !== protocol) {\n throw new InvalidRedirectUriError(\n `Private-Use URI Scheme redirect URI, for discoverable client metadata, must be the fully qualified domain name (FQDN) of the client_id, in reverse order (${protocol})`,\n )\n }\n }\n }\n\n return metadata\n }\n}\n\nfunction isDuplicate<\n T extends string | number | boolean | null | undefined | symbol,\n>(value: T, index: number, array: T[]) {\n return array.includes(value, index + 1)\n}\n\nfunction reverseDomain(domain: string) {\n return domain.split('.').reverse().join('.')\n}\n\nfunction isPrivateUseUriScheme(uri: URL) {\n return uri.protocol.includes('.')\n}\n\nfunction buildJsonGetRequest(uri: string, options?: GetCachedOptions) {\n return new Request(uri, {\n headers: { accept: 'application/json' },\n // @ts-expect-error invalid types in \"undici-types\"\n cache: options?.noCache ? 'no-cache' : undefined,\n signal: options?.signal,\n redirect: 'error',\n })\n}\n"]}
|
|
@@ -1,36 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.isClientStore = void 0;
|
|
18
|
-
exports.ifClientStore = ifClientStore;
|
|
19
|
-
exports.asClientStore = asClientStore;
|
|
20
|
-
const type_js_1 = require("../lib/util/type.js");
|
|
1
|
+
import { buildInterfaceChecker } from '../lib/util/type.js';
|
|
21
2
|
// Export all types needed to implement the ClientStore interface
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
3
|
+
export * from './client-data.js';
|
|
4
|
+
export * from './client-id.js';
|
|
5
|
+
export const isClientStore = buildInterfaceChecker([
|
|
25
6
|
'findClient', //
|
|
26
7
|
]);
|
|
27
|
-
function ifClientStore(implementation) {
|
|
28
|
-
if (implementation &&
|
|
8
|
+
export function ifClientStore(implementation) {
|
|
9
|
+
if (implementation && isClientStore(implementation)) {
|
|
29
10
|
return implementation;
|
|
30
11
|
}
|
|
31
12
|
return undefined;
|
|
32
13
|
}
|
|
33
|
-
function asClientStore(implementation) {
|
|
14
|
+
export function asClientStore(implementation) {
|
|
34
15
|
const store = ifClientStore(implementation);
|
|
35
16
|
if (store)
|
|
36
17
|
return store;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-store.js","sourceRoot":"","sources":["../../src/client/client-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client-store.js","sourceRoot":"","sources":["../../src/client/client-store.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAGtE,iEAAiE;AACjE,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAO9B,MAAM,CAAC,MAAM,aAAa,GAAG,qBAAqB,CAAc;IAC9D,YAAY,EAAE,EAAE;CACjB,CAAC,CAAA;AAEF,MAAM,UAAU,aAAa,CAC3B,cAAkB;IAElB,IAAI,cAAc,IAAI,aAAa,CAAC,cAAc,CAAC,EAAE,CAAC;QACpD,OAAO,cAAc,CAAA;IACvB,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,cAAkB;IAElB,MAAM,KAAK,GAAG,aAAa,CAAC,cAAc,CAAC,CAAA;IAC3C,IAAI,KAAK;QAAE,OAAO,KAAK,CAAA;IAEvB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;AACvD,CAAC","sourcesContent":["import { OAuthClientMetadata } from '@atproto/oauth-types'\nimport { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'\nimport { ClientId } from './client-id.js'\n\n// Export all types needed to implement the ClientStore interface\nexport * from './client-data.js'\nexport * from './client-id.js'\nexport type { Awaitable, OAuthClientMetadata }\n\nexport interface ClientStore {\n findClient(clientId: ClientId): Awaitable<OAuthClientMetadata>\n}\n\nexport const isClientStore = buildInterfaceChecker<ClientStore>([\n 'findClient', //\n])\n\nexport function ifClientStore<V extends Partial<ClientStore>>(\n implementation?: V,\n): (V & ClientStore) | undefined {\n if (implementation && isClientStore(implementation)) {\n return implementation\n }\n\n return undefined\n}\n\nexport function asClientStore<V extends Partial<ClientStore>>(\n implementation?: V,\n): V & ClientStore {\n const store = ifClientStore(implementation)\n if (store) return store\n\n throw new Error('Invalid ClientStore implementation')\n}\n"]}
|
|
@@ -1,29 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const oauth_types_1 = require("@atproto/oauth-types");
|
|
6
|
-
const invalid_client_id_error_js_1 = require("../errors/invalid-client-id-error.js");
|
|
7
|
-
const invalid_redirect_uri_error_js_1 = require("../errors/invalid-redirect-uri-error.js");
|
|
8
|
-
function parseRedirectUri(redirectUri) {
|
|
1
|
+
import { isLocalHostname, parseOAuthDiscoverableClientId, } from '@atproto/oauth-types';
|
|
2
|
+
import { InvalidClientIdError } from '../errors/invalid-client-id-error.js';
|
|
3
|
+
import { InvalidRedirectUriError } from '../errors/invalid-redirect-uri-error.js';
|
|
4
|
+
export function parseRedirectUri(redirectUri) {
|
|
9
5
|
try {
|
|
10
6
|
return new URL(redirectUri);
|
|
11
7
|
}
|
|
12
8
|
catch (err) {
|
|
13
|
-
throw
|
|
9
|
+
throw InvalidRedirectUriError.from(err);
|
|
14
10
|
}
|
|
15
11
|
}
|
|
16
|
-
function parseDiscoverableClientId(clientId) {
|
|
12
|
+
export function parseDiscoverableClientId(clientId) {
|
|
17
13
|
try {
|
|
18
|
-
const url =
|
|
14
|
+
const url = parseOAuthDiscoverableClientId(clientId);
|
|
19
15
|
// Extra validation, prevent usage of invalid internet domain names.
|
|
20
|
-
if (
|
|
21
|
-
throw new
|
|
16
|
+
if (isLocalHostname(url.hostname)) {
|
|
17
|
+
throw new InvalidClientIdError("The client_id's TLD must not be a local hostname");
|
|
22
18
|
}
|
|
23
19
|
return url;
|
|
24
20
|
}
|
|
25
21
|
catch (err) {
|
|
26
|
-
throw
|
|
22
|
+
throw InvalidClientIdError.from(err, 'Invalid discoverable client identifier');
|
|
27
23
|
}
|
|
28
24
|
}
|
|
29
25
|
//# sourceMappingURL=client-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-utils.js","sourceRoot":"","sources":["../../src/client/client-utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client-utils.js","sourceRoot":"","sources":["../../src/client/client-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,8BAA8B,GAC/B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAA;AAC3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAA;AAEjF,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,WAAW,CAAC,CAAA;IAC7B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,uBAAuB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACzC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,QAAmC;IAEnC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,8BAA8B,CAAC,QAAQ,CAAC,CAAA;QAEpD,oEAAoE;QACpE,IAAI,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,oBAAoB,CAC5B,kDAAkD,CACnD,CAAA;QACH,CAAC;QAED,OAAO,GAAG,CAAA;IACZ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,oBAAoB,CAAC,IAAI,CAC7B,GAAG,EACH,wCAAwC,CACzC,CAAA;IACH,CAAC;AACH,CAAC","sourcesContent":["import {\n OAuthClientIdDiscoverable,\n isLocalHostname,\n parseOAuthDiscoverableClientId,\n} from '@atproto/oauth-types'\nimport { InvalidClientIdError } from '../errors/invalid-client-id-error.js'\nimport { InvalidRedirectUriError } from '../errors/invalid-redirect-uri-error.js'\n\nexport function parseRedirectUri(redirectUri: string): URL {\n try {\n return new URL(redirectUri)\n } catch (err) {\n throw InvalidRedirectUriError.from(err)\n }\n}\n\nexport function parseDiscoverableClientId(\n clientId: OAuthClientIdDiscoverable,\n): URL {\n try {\n const url = parseOAuthDiscoverableClientId(clientId)\n\n // Extra validation, prevent usage of invalid internet domain names.\n if (isLocalHostname(url.hostname)) {\n throw new InvalidClientIdError(\n \"The client_id's TLD must not be a local hostname\",\n )\n }\n\n return url\n } catch (err) {\n throw InvalidClientIdError.from(\n err,\n 'Invalid discoverable client identifier',\n )\n }\n}\n"]}
|
package/dist/client/client.js
CHANGED
|
@@ -1,29 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const cast_js_1 = require("../lib/util/cast.js");
|
|
15
|
-
const redirect_uri_js_1 = require("../lib/util/redirect-uri.js");
|
|
16
|
-
const { JOSEError } = jose_1.errors;
|
|
17
|
-
class Client {
|
|
18
|
-
id;
|
|
19
|
-
metadata;
|
|
20
|
-
jwks;
|
|
21
|
-
info;
|
|
1
|
+
import { UnsecuredJWT, calculateJwkThumbprint, createLocalJWKSet, createRemoteJWKSet, errors, exportJWK, jwtVerify, } from 'jose';
|
|
2
|
+
import { CLIENT_ASSERTION_TYPE_JWT_BEARER, } from '@atproto/oauth-types';
|
|
3
|
+
import { CLIENT_ASSERTION_MAX_AGE, JAR_MAX_AGE } from '../constants.js';
|
|
4
|
+
import { AuthorizationError } from '../errors/authorization-error.js';
|
|
5
|
+
import { InvalidAuthorizationDetailsError } from '../errors/invalid-authorization-details-error.js';
|
|
6
|
+
import { InvalidClientError } from '../errors/invalid-client-error.js';
|
|
7
|
+
import { InvalidClientMetadataError } from '../errors/invalid-client-metadata-error.js';
|
|
8
|
+
import { InvalidRequestError } from '../errors/invalid-request-error.js';
|
|
9
|
+
import { InvalidScopeError } from '../errors/invalid-scope-error.js';
|
|
10
|
+
import { asArray } from '../lib/util/cast.js';
|
|
11
|
+
import { compareRedirectUri } from '../lib/util/redirect-uri.js';
|
|
12
|
+
const { JOSEError } = errors;
|
|
13
|
+
export class Client {
|
|
22
14
|
/**
|
|
23
15
|
* @see {@link https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#token-endpoint-auth-method}
|
|
24
16
|
*/
|
|
25
|
-
static AUTH_METHODS_SUPPORTED = ['none', 'private_key_jwt'];
|
|
26
|
-
keyGetter;
|
|
17
|
+
static { this.AUTH_METHODS_SUPPORTED = ['none', 'private_key_jwt']; }
|
|
27
18
|
constructor(id, metadata, jwks = metadata.jwks, info) {
|
|
28
19
|
this.id = id;
|
|
29
20
|
this.metadata = metadata;
|
|
@@ -32,8 +23,8 @@ class Client {
|
|
|
32
23
|
// If the remote JWKS content is provided, we don't need to fetch it again.
|
|
33
24
|
this.keyGetter =
|
|
34
25
|
jwks || !metadata.jwks_uri
|
|
35
|
-
?
|
|
36
|
-
:
|
|
26
|
+
? createLocalJWKSet(jwks || { keys: [] })
|
|
27
|
+
: createRemoteJWKSet(new URL(metadata.jwks_uri), {});
|
|
37
28
|
}
|
|
38
29
|
/**
|
|
39
30
|
* @see {@link https://www.rfc-editor.org/rfc/rfc9101.html#name-request-object-2}
|
|
@@ -51,14 +42,14 @@ class Client {
|
|
|
51
42
|
if (this.metadata.request_object_signing_alg === 'none') {
|
|
52
43
|
return await this.jwtVerifyUnsecured(jar, {
|
|
53
44
|
audience,
|
|
54
|
-
maxTokenAge:
|
|
45
|
+
maxTokenAge: JAR_MAX_AGE / 1e3,
|
|
55
46
|
allowMissingAudience: true,
|
|
56
47
|
allowMissingIssuer: true,
|
|
57
48
|
});
|
|
58
49
|
}
|
|
59
50
|
return await this.jwtVerify(jar, {
|
|
60
51
|
audience,
|
|
61
|
-
maxTokenAge:
|
|
52
|
+
maxTokenAge: JAR_MAX_AGE / 1e3,
|
|
62
53
|
algorithms: this.metadata.request_object_signing_alg
|
|
63
54
|
? [this.metadata.request_object_signing_alg]
|
|
64
55
|
: // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2
|
|
@@ -72,14 +63,14 @@ class Client {
|
|
|
72
63
|
const message = err instanceof JOSEError
|
|
73
64
|
? `Invalid "request" object: ${err.message}`
|
|
74
65
|
: `Invalid "request" object`;
|
|
75
|
-
throw new
|
|
66
|
+
throw new InvalidRequestError(message, err);
|
|
76
67
|
}
|
|
77
68
|
}
|
|
78
69
|
async jwtVerifyUnsecured(token, { audience, allowMissingAudience = false, allowMissingIssuer = false, ...options } = {}) {
|
|
79
70
|
// jose does not support `allowMissingAudience` and `allowMissingIssuer`
|
|
80
71
|
// options, so we need to handle audience and issuer checks manually (see
|
|
81
72
|
// bellow).
|
|
82
|
-
const result =
|
|
73
|
+
const result = UnsecuredJWT.decode(token, options);
|
|
83
74
|
if (!allowMissingIssuer || result.payload.iss != null) {
|
|
84
75
|
if (result.payload.iss !== this.id) {
|
|
85
76
|
throw new JOSEError(`Invalid "iss" claim "${result.payload.iss}"`);
|
|
@@ -87,8 +78,8 @@ class Client {
|
|
|
87
78
|
}
|
|
88
79
|
if (!allowMissingAudience || result.payload.aud != null) {
|
|
89
80
|
if (audience != null) {
|
|
90
|
-
const payloadAud =
|
|
91
|
-
if (!
|
|
81
|
+
const payloadAud = asArray(result.payload.aud);
|
|
82
|
+
if (!asArray(audience).some((aud) => payloadAud.includes(aud))) {
|
|
92
83
|
throw new JOSEError(`Invalid "aud" claim "${result.payload.aud}"`);
|
|
93
84
|
}
|
|
94
85
|
}
|
|
@@ -96,7 +87,7 @@ class Client {
|
|
|
96
87
|
return result;
|
|
97
88
|
}
|
|
98
89
|
async jwtVerify(token, options) {
|
|
99
|
-
return
|
|
90
|
+
return jwtVerify(token, this.keyGetter, {
|
|
100
91
|
...options,
|
|
101
92
|
issuer: this.id,
|
|
102
93
|
});
|
|
@@ -113,9 +104,9 @@ class Client {
|
|
|
113
104
|
}
|
|
114
105
|
if (method === 'private_key_jwt') {
|
|
115
106
|
if (!('client_assertion' in input)) {
|
|
116
|
-
throw new
|
|
107
|
+
throw new InvalidRequestError(`client authentication method "${method}" required a "client_assertion"`);
|
|
117
108
|
}
|
|
118
|
-
if (input.client_assertion_type ===
|
|
109
|
+
if (input.client_assertion_type === CLIENT_ASSERTION_TYPE_JWT_BEARER) {
|
|
119
110
|
// https://www.rfc-editor.org/rfc/rfc7523.html#section-3
|
|
120
111
|
const result = await this.jwtVerify(input.client_assertion, {
|
|
121
112
|
// > 1. The JWT MUST contain an "iss" (issuer) claim that contains a
|
|
@@ -160,15 +151,15 @@ class Client {
|
|
|
160
151
|
// > the time at which the JWT was issued. Note that the
|
|
161
152
|
// > authorization server may reject JWTs with an "iat" claim value
|
|
162
153
|
// > that is unreasonably far in the past.
|
|
163
|
-
maxTokenAge:
|
|
154
|
+
maxTokenAge: CLIENT_ASSERTION_MAX_AGE / 1000,
|
|
164
155
|
}).catch((err) => {
|
|
165
156
|
const msg = err instanceof JOSEError
|
|
166
157
|
? `Validation of "client_assertion" failed: ${err.message}`
|
|
167
158
|
: `Unable to verify "client_assertion" JWT`;
|
|
168
|
-
throw new
|
|
159
|
+
throw new InvalidClientError(msg, err);
|
|
169
160
|
});
|
|
170
161
|
if (!result.protectedHeader.kid) {
|
|
171
|
-
throw new
|
|
162
|
+
throw new InvalidClientError(`"kid" required in client_assertion`);
|
|
172
163
|
}
|
|
173
164
|
return {
|
|
174
165
|
method: 'private_key_jwt',
|
|
@@ -179,7 +170,7 @@ class Client {
|
|
|
179
170
|
kid: result.protectedHeader.kid,
|
|
180
171
|
};
|
|
181
172
|
}
|
|
182
|
-
throw new
|
|
173
|
+
throw new InvalidClientError(`Unsupported client_assertion_type "${input.client_assertion_type}"`);
|
|
183
174
|
}
|
|
184
175
|
// @ts-expect-error Ensure to keep Client.AUTH_METHODS_SUPPORTED in sync
|
|
185
176
|
// with the implementation of this function.
|
|
@@ -188,40 +179,40 @@ class Client {
|
|
|
188
179
|
Client.AUTH_METHODS_SUPPORTED,
|
|
189
180
|
]}`);
|
|
190
181
|
}
|
|
191
|
-
throw new
|
|
182
|
+
throw new InvalidClientMetadataError(`Unsupported token_endpoint_auth_method "${method}"`);
|
|
192
183
|
}
|
|
193
184
|
/**
|
|
194
185
|
* Validates the request parameters against the client metadata.
|
|
195
186
|
*/
|
|
196
187
|
validateRequest(parameters) {
|
|
197
188
|
if (parameters.client_id !== this.id) {
|
|
198
|
-
throw new
|
|
189
|
+
throw new AuthorizationError(parameters, 'The "client_id" parameter field does not match the value used to authenticate the client');
|
|
199
190
|
}
|
|
200
191
|
if (parameters.scope !== undefined) {
|
|
201
192
|
// Any scope requested by the client must be registered in the client
|
|
202
193
|
// metadata.
|
|
203
194
|
const declaredScopes = this.metadata.scope?.split(' ');
|
|
204
195
|
if (!declaredScopes) {
|
|
205
|
-
throw new
|
|
196
|
+
throw new InvalidScopeError(parameters, 'Client has no declared scopes in its metadata');
|
|
206
197
|
}
|
|
207
198
|
for (const scope of parameters.scope.split(' ')) {
|
|
208
199
|
if (!declaredScopes.includes(scope)) {
|
|
209
|
-
throw new
|
|
200
|
+
throw new InvalidScopeError(parameters, `Scope "${scope}" is not declared in the client metadata`);
|
|
210
201
|
}
|
|
211
202
|
}
|
|
212
203
|
}
|
|
213
204
|
if (!this.metadata.response_types.includes(parameters.response_type)) {
|
|
214
|
-
throw new
|
|
205
|
+
throw new AuthorizationError(parameters, `Invalid response_type "${parameters.response_type}" requested by the client`);
|
|
215
206
|
}
|
|
216
207
|
if (parameters.response_type.includes('code')) {
|
|
217
208
|
if (!this.metadata.grant_types.includes('authorization_code')) {
|
|
218
|
-
throw new
|
|
209
|
+
throw new AuthorizationError(parameters, `This client is not allowed to use the "authorization_code" grant type`);
|
|
219
210
|
}
|
|
220
211
|
}
|
|
221
212
|
const { redirect_uri } = parameters;
|
|
222
213
|
if (redirect_uri) {
|
|
223
|
-
if (!this.metadata.redirect_uris.some((uri) =>
|
|
224
|
-
throw new
|
|
214
|
+
if (!this.metadata.redirect_uris.some((uri) => compareRedirectUri(uri, redirect_uri))) {
|
|
215
|
+
throw new AuthorizationError(parameters, `Invalid redirect_uri ${redirect_uri}`);
|
|
225
216
|
}
|
|
226
217
|
}
|
|
227
218
|
else {
|
|
@@ -235,17 +226,17 @@ class Client {
|
|
|
235
226
|
// > "redirect_uri": OPTIONAL if only one redirect URI is registered for
|
|
236
227
|
// > this client. REQUIRED if multiple redirect URIs are registered for this
|
|
237
228
|
// > client.
|
|
238
|
-
throw new
|
|
229
|
+
throw new AuthorizationError(parameters, 'redirect_uri is required');
|
|
239
230
|
}
|
|
240
231
|
}
|
|
241
232
|
if (parameters.authorization_details) {
|
|
242
233
|
const { authorization_details_types } = this.metadata;
|
|
243
234
|
if (!authorization_details_types) {
|
|
244
|
-
throw new
|
|
235
|
+
throw new InvalidAuthorizationDetailsError(parameters, 'Client Metadata does not declare any "authorization_details"');
|
|
245
236
|
}
|
|
246
237
|
for (const detail of parameters.authorization_details) {
|
|
247
238
|
if (!authorization_details_types?.includes(detail.type)) {
|
|
248
|
-
throw new
|
|
239
|
+
throw new InvalidAuthorizationDetailsError(parameters, `Client Metadata does not declare any "authorization_details" of type "${detail.type}"`);
|
|
249
240
|
}
|
|
250
241
|
}
|
|
251
242
|
}
|
|
@@ -256,13 +247,12 @@ class Client {
|
|
|
256
247
|
return redirect_uris.length === 1 ? redirect_uris[0] : undefined;
|
|
257
248
|
}
|
|
258
249
|
}
|
|
259
|
-
|
|
260
|
-
async function authJwkThumbprint(key) {
|
|
250
|
+
export async function authJwkThumbprint(key) {
|
|
261
251
|
try {
|
|
262
|
-
return await
|
|
252
|
+
return await calculateJwkThumbprint(await exportJWK(key), 'sha512');
|
|
263
253
|
}
|
|
264
254
|
catch (err) {
|
|
265
|
-
throw new
|
|
255
|
+
throw new InvalidClientError('Unable to compute JWK thumbprint', err);
|
|
266
256
|
}
|
|
267
257
|
}
|
|
268
258
|
//# sourceMappingURL=client.js.map
|