@atproto/oauth-provider 0.18.3 → 0.19.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.
Files changed (197) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/account/account-manager.d.ts +11 -7
  3. package/dist/account/account-manager.d.ts.map +1 -1
  4. package/dist/account/account-manager.js +82 -19
  5. package/dist/account/account-manager.js.map +1 -1
  6. package/dist/account/account-store.d.ts +47 -13
  7. package/dist/account/account-store.d.ts.map +1 -1
  8. package/dist/account/account-store.js +12 -9
  9. package/dist/account/account-store.js.map +1 -1
  10. package/dist/account/sign-in-data.d.ts +2 -2
  11. package/dist/account/sign-up-input.d.ts +5 -5
  12. package/dist/client/client-manager.d.ts.map +1 -1
  13. package/dist/client/client-manager.js.map +1 -1
  14. package/dist/client/client.d.ts +1 -1
  15. package/dist/client/client.d.ts.map +1 -1
  16. package/dist/client/client.js.map +1 -1
  17. package/dist/customization/branding.d.ts +52 -52
  18. package/dist/customization/colors.d.ts +24 -24
  19. package/dist/customization/colors.d.ts.map +1 -1
  20. package/dist/customization/customization.d.ts +77 -77
  21. package/dist/customization/links.d.ts +4 -4
  22. package/dist/device/device-manager.d.ts +20 -20
  23. package/dist/device/device-manager.d.ts.map +1 -1
  24. package/dist/device/device-manager.js.map +1 -1
  25. package/dist/device/device-store.js +1 -1
  26. package/dist/device/device-store.js.map +1 -1
  27. package/dist/dpop/dpop-manager.d.ts.map +1 -1
  28. package/dist/dpop/dpop-manager.js.map +1 -1
  29. package/dist/dpop/dpop-nonce.d.ts.map +1 -1
  30. package/dist/dpop/dpop-nonce.js +1 -1
  31. package/dist/dpop/dpop-nonce.js.map +1 -1
  32. package/dist/errors/access-denied-error.d.ts.map +1 -1
  33. package/dist/errors/account-selection-required-error.d.ts.map +1 -1
  34. package/dist/errors/authorization-error.d.ts.map +1 -1
  35. package/dist/errors/authorization-error.js.map +1 -1
  36. package/dist/errors/consent-required-error.d.ts.map +1 -1
  37. package/dist/errors/handle-unavailable-error.d.ts +1 -1
  38. package/dist/errors/handle-unavailable-error.d.ts.map +1 -1
  39. package/dist/errors/handle-unavailable-error.js.map +1 -1
  40. package/dist/errors/invalid-authorization-details-error.d.ts.map +1 -1
  41. package/dist/errors/invalid-client-error.d.ts.map +1 -1
  42. package/dist/errors/invalid-client-id-error.d.ts.map +1 -1
  43. package/dist/errors/invalid-client-metadata-error.d.ts.map +1 -1
  44. package/dist/errors/invalid-credentials-error.d.ts +9 -9
  45. package/dist/errors/invalid-credentials-error.d.ts.map +1 -1
  46. package/dist/errors/invalid-credentials-error.js +8 -8
  47. package/dist/errors/invalid-credentials-error.js.map +1 -1
  48. package/dist/errors/invalid-dpop-key-binding-error.d.ts.map +1 -1
  49. package/dist/errors/invalid-dpop-proof-error.d.ts.map +1 -1
  50. package/dist/errors/invalid-grant-error.d.ts.map +1 -1
  51. package/dist/errors/invalid-invite-code-error.d.ts.map +1 -1
  52. package/dist/errors/invalid-redirect-uri-error.d.ts.map +1 -1
  53. package/dist/errors/invalid-request-error.d.ts.map +1 -1
  54. package/dist/errors/invalid-scope-error.d.ts.map +1 -1
  55. package/dist/errors/invalid-token-error.d.ts.map +1 -1
  56. package/dist/errors/invalid-token-error.js.map +1 -1
  57. package/dist/errors/login-required-error.d.ts.map +1 -1
  58. package/dist/errors/oauth-error.d.ts.map +1 -1
  59. package/dist/errors/oauth-error.js.map +1 -1
  60. package/dist/errors/second-authentication-factor-required-error.d.ts +2 -2
  61. package/dist/errors/second-authentication-factor-required-error.d.ts.map +1 -1
  62. package/dist/errors/second-authentication-factor-required-error.js.map +1 -1
  63. package/dist/errors/unauthorized-client-error.d.ts.map +1 -1
  64. package/dist/errors/use-dpop-nonce-error.d.ts.map +1 -1
  65. package/dist/errors/www-authenticate-error.d.ts.map +1 -1
  66. package/dist/lexicon/lexicon-getter.d.ts.map +1 -1
  67. package/dist/lexicon/lexicon-manager.d.ts.map +1 -1
  68. package/dist/lexicon/lexicon-store.js +1 -1
  69. package/dist/lexicon/lexicon-store.js.map +1 -1
  70. package/dist/lib/csp/index.d.ts +3 -3
  71. package/dist/lib/csp/index.d.ts.map +1 -1
  72. package/dist/lib/hcaptcha.d.ts +3 -3
  73. package/dist/lib/hcaptcha.d.ts.map +1 -1
  74. package/dist/lib/hcaptcha.js.map +1 -1
  75. package/dist/lib/html/build-document.d.ts.map +1 -1
  76. package/dist/lib/html/html.d.ts.map +1 -1
  77. package/dist/lib/html/tags.d.ts.map +1 -1
  78. package/dist/lib/http/accept.js.map +1 -1
  79. package/dist/lib/http/context.js.map +1 -1
  80. package/dist/lib/http/middleware.js.map +1 -1
  81. package/dist/lib/http/parser.d.ts +5 -5
  82. package/dist/lib/http/parser.d.ts.map +1 -1
  83. package/dist/lib/http/response.js.map +1 -1
  84. package/dist/lib/http/router.d.ts.map +1 -1
  85. package/dist/lib/http/stream.d.ts +5 -5
  86. package/dist/lib/http/stream.d.ts.map +1 -1
  87. package/dist/lib/util/authorization-header.d.ts +1 -1
  88. package/dist/lib/util/authorization-header.d.ts.map +1 -1
  89. package/dist/lib/util/color.js.map +1 -1
  90. package/dist/lib/util/crypto.d.ts +1 -1
  91. package/dist/lib/util/crypto.d.ts.map +1 -1
  92. package/dist/lib/util/date.js.map +1 -1
  93. package/dist/lib/util/function.js +1 -1
  94. package/dist/lib/util/function.js.map +1 -1
  95. package/dist/lib/util/type.d.ts.map +1 -1
  96. package/dist/oauth-hooks.d.ts +77 -4
  97. package/dist/oauth-hooks.d.ts.map +1 -1
  98. package/dist/oauth-hooks.js.map +1 -1
  99. package/dist/oauth-middleware.js.map +1 -1
  100. package/dist/oauth-provider.d.ts +31 -31
  101. package/dist/oauth-provider.d.ts.map +1 -1
  102. package/dist/oauth-provider.js +15 -9
  103. package/dist/oauth-provider.js.map +1 -1
  104. package/dist/oauth-verifier.d.ts.map +1 -1
  105. package/dist/replay/replay-manager.d.ts.map +1 -1
  106. package/dist/replay/replay-manager.js.map +1 -1
  107. package/dist/replay/replay-store-memory.d.ts.map +1 -1
  108. package/dist/replay/replay-store-redis.d.ts.map +1 -1
  109. package/dist/request/code.d.ts.map +1 -1
  110. package/dist/request/request-data.d.ts +4 -4
  111. package/dist/request/request-data.d.ts.map +1 -1
  112. package/dist/request/request-data.js +1 -1
  113. package/dist/request/request-data.js.map +1 -1
  114. package/dist/request/request-manager.d.ts +32 -32
  115. package/dist/request/request-manager.d.ts.map +1 -1
  116. package/dist/request/request-manager.js +7 -4
  117. package/dist/request/request-manager.js.map +1 -1
  118. package/dist/request/request-store.d.ts +1 -1
  119. package/dist/request/request-store.js +2 -2
  120. package/dist/request/request-store.js.map +1 -1
  121. package/dist/result/authorization-result-authorize-page.d.ts +1 -1
  122. package/dist/result/authorization-result-authorize-page.js.map +1 -1
  123. package/dist/router/assets/assets-manifest.js.map +1 -1
  124. package/dist/router/assets/assets.d.ts +1 -1
  125. package/dist/router/assets/assets.d.ts.map +1 -1
  126. package/dist/router/assets/assets.js.map +1 -1
  127. package/dist/router/assets/send-account-page.d.ts.map +1 -1
  128. package/dist/router/assets/send-authorization-page.d.ts.map +1 -1
  129. package/dist/router/assets/send-authorization-page.js +1 -1
  130. package/dist/router/assets/send-authorization-page.js.map +1 -1
  131. package/dist/router/assets/send-cookie-error-page.d.ts.map +1 -1
  132. package/dist/router/assets/send-error-page.d.ts.map +1 -1
  133. package/dist/router/assets/send-redirect.d.ts +2 -2
  134. package/dist/router/assets/send-redirect.d.ts.map +1 -1
  135. package/dist/router/create-api-middleware.d.ts.map +1 -1
  136. package/dist/router/create-api-middleware.js +87 -51
  137. package/dist/router/create-api-middleware.js.map +1 -1
  138. package/dist/signer/access-token-payload.d.ts +1762 -1762
  139. package/dist/signer/access-token-payload.d.ts.map +1 -1
  140. package/dist/signer/access-token-payload.js +2 -2
  141. package/dist/signer/access-token-payload.js.map +1 -1
  142. package/dist/signer/api-token-payload.d.ts +1738 -1738
  143. package/dist/signer/api-token-payload.d.ts.map +1 -1
  144. package/dist/signer/api-token-payload.js +2 -2
  145. package/dist/signer/api-token-payload.js.map +1 -1
  146. package/dist/signer/signer.d.ts +6 -187
  147. package/dist/signer/signer.d.ts.map +1 -1
  148. package/dist/signer/signer.js.map +1 -1
  149. package/dist/token/refresh-token.d.ts.map +1 -1
  150. package/dist/token/token-claims.d.ts +2 -1
  151. package/dist/token/token-claims.d.ts.map +1 -1
  152. package/dist/token/token-claims.js.map +1 -1
  153. package/dist/token/token-data.d.ts +3 -3
  154. package/dist/token/token-data.d.ts.map +1 -1
  155. package/dist/token/token-data.js.map +1 -1
  156. package/dist/token/token-id.d.ts.map +1 -1
  157. package/dist/token/token-manager.d.ts +3 -3
  158. package/dist/token/token-manager.d.ts.map +1 -1
  159. package/dist/token/token-manager.js +14 -14
  160. package/dist/token/token-manager.js.map +1 -1
  161. package/dist/token/token-store.d.ts +3 -3
  162. package/dist/token/token-store.d.ts.map +1 -1
  163. package/dist/token/token-store.js +3 -3
  164. package/dist/token/token-store.js.map +1 -1
  165. package/dist/types/handle.d.ts +5 -1
  166. package/dist/types/handle.d.ts.map +1 -1
  167. package/dist/types/handle.js +9 -8
  168. package/dist/types/handle.js.map +1 -1
  169. package/package.json +19 -19
  170. package/src/account/account-manager.ts +123 -20
  171. package/src/account/account-store.ts +67 -19
  172. package/src/device/device-store.ts +1 -1
  173. package/src/errors/invalid-credentials-error.ts +8 -8
  174. package/src/lexicon/lexicon-store.ts +1 -1
  175. package/src/lib/util/function.ts +2 -2
  176. package/src/oauth-hooks.ts +85 -3
  177. package/src/oauth-provider.ts +17 -9
  178. package/src/request/request-data.ts +5 -5
  179. package/src/request/request-manager.ts +11 -4
  180. package/src/request/request-store.ts +3 -3
  181. package/src/result/authorization-result-authorize-page.ts +1 -1
  182. package/src/router/assets/send-authorization-page.ts +1 -1
  183. package/src/router/create-api-middleware.ts +128 -67
  184. package/src/signer/access-token-payload.ts +2 -2
  185. package/src/signer/api-token-payload.ts +2 -2
  186. package/src/signer/signer.ts +13 -4
  187. package/src/token/token-claims.ts +2 -1
  188. package/src/token/token-data.ts +3 -3
  189. package/src/token/token-manager.ts +15 -15
  190. package/src/token/token-store.ts +6 -6
  191. package/src/types/handle.ts +21 -16
  192. package/tsconfig.build.tsbuildinfo +1 -1
  193. package/dist/oidc/sub.d.ts +0 -4
  194. package/dist/oidc/sub.d.ts.map +0 -1
  195. package/dist/oidc/sub.js +0 -3
  196. package/dist/oidc/sub.js.map +0 -1
  197. package/src/oidc/sub.ts +0 -4
@@ -1 +1 @@
1
- {"version":3,"file":"account-store.js","sourceRoot":"","sources":["../../src/account/account-store.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAa,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AACtE,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,uCAAuC,GACxC,MAAM,oBAAoB,CAAA;AAK3B,kEAAkE;AAElE,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,wBAAwB,CAAA;AACtC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,0BAA0B,CAAA;AAUxC,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,uCAAuC,GACxC,CAAA;AAqLD,MAAM,CAAC,MAAM,cAAc,GAAG,qBAAqB,CAAe;IAChE,eAAe;IACf,qBAAqB;IACrB,qBAAqB;IACrB,YAAY;IACZ,qBAAqB;IACrB,kBAAkB;IAClB,qBAAqB;IACrB,oBAAoB;IACpB,sBAAsB;IACtB,sBAAsB;IACtB,oBAAoB;IACpB,oBAAoB;IACpB,oBAAoB;IACpB,oBAAoB;IACpB,0BAA0B;IAC1B,cAAc;CACf,CAAC,CAAA;AAEF,MAAM,UAAU,cAAc,CAAI,cAAiB;IACjD,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,CAAC;IACD,OAAO,cAAc,CAAA;AACvB,CAAC","sourcesContent":["import type {\n Account,\n ConfirmEmailUpdateInput,\n ConfirmEmailVerificationInput,\n ConfirmResetPasswordInput,\n InitiateEmailUpdateInput,\n InitiateEmailUpdateOutput,\n InitiateEmailVerificationInput,\n InitiatePasswordResetInput,\n UpdateHandleInput,\n} from '@atproto/oauth-provider-api'\nimport { OAuthScope } from '@atproto/oauth-types'\nimport { ClientId } from '../client/client-id.js'\nimport { DeviceId } from '../device/device-id.js'\nimport { DeviceData } from '../device/device-store.js'\nimport { HcaptchaVerifyResult } from '../lib/hcaptcha.js'\nimport { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'\nimport {\n HandleUnavailableError,\n InvalidCredentialsError,\n InvalidRequestError,\n SecondAuthenticationFactorRequiredError,\n} from '../oauth-errors.js'\nimport { Sub } from '../oidc/sub.js'\nimport { InviteCode } from '../types/invite-code.js'\nimport { SignUpInput } from './sign-up-input.js'\n\n// Export all types needed to implement the AccountStore interface\n\nexport * from '../client/client-id.js'\nexport * from '../device/device-data.js'\nexport * from '../device/device-id.js'\nexport * from '../oidc/sub.js'\nexport * from '../request/request-id.js'\n\nexport type {\n Account,\n HcaptchaVerifyResult,\n InviteCode,\n OAuthScope,\n SignUpInput,\n}\n\nexport {\n HandleUnavailableError,\n InvalidCredentialsError,\n InvalidRequestError,\n SecondAuthenticationFactorRequiredError,\n}\n\nexport type ResetPasswordRequestInput = InitiatePasswordResetInput\nexport type ResetPasswordConfirmInput = ConfirmResetPasswordInput\n\nexport type UpdateEmailRequestInput = InitiateEmailUpdateInput\nexport type UpdateEmailRequestOutput = InitiateEmailUpdateOutput\nexport type UpdateEmailConfirmInput = ConfirmEmailUpdateInput\nexport type VerifyEmailRequestInput = InitiateEmailVerificationInput\nexport type VerifyEmailConfirmInput = ConfirmEmailVerificationInput\nexport type UpdateHandleData = UpdateHandleInput\n\nexport type CreateAccountData = {\n locale: string\n email: string\n password: string\n handle: string\n inviteCode?: string | undefined\n}\n\nexport type AuthenticateAccountData = {\n locale: string\n password: string\n username: string\n emailOtp?: string | undefined\n}\n\nexport type AuthorizedClientData = { authorizedScopes: readonly string[] }\nexport type AuthorizedClients = Map<ClientId, AuthorizedClientData>\n\nexport type DeviceAccount = {\n deviceId: DeviceId\n\n /**\n * The data associated with the device, created through the\n * {@link DeviceStore}. This data is used to identify devices on which a user\n * has logged in.\n */\n deviceData: DeviceData\n\n /**\n * The account associated with the device account.\n */\n account: Account\n\n /**\n * The list of clients that are authorized by the account, as created through\n * the {@link AccountStore.setAuthorizedClient} method.\n */\n authorizedClients: AuthorizedClients\n\n /**\n * The date at which the device account was created. This value is currently\n * not used.\n */\n createdAt: Date\n\n /**\n * The date at which the device account was last updated. This value is used\n * to determine the date at which the user last authenticated on a device\n */\n updatedAt: Date\n}\n\nexport type SignUpData = SignUpInput & {\n hcaptchaResult?: HcaptchaVerifyResult\n inviteCode?: InviteCode\n}\n\nexport interface AccountStore {\n /**\n * @throws {HandleUnavailableError} - To indicate that the handle is already taken\n * @throws {InvalidRequestError} - To indicate that some data is invalid\n */\n createAccount(data: CreateAccountData): Awaitable<Account>\n\n /**\n * @throws {InvalidCredentialsError} - When the credentials are not valid.\n * Populate {@link InvalidCredentialsError.sub} with the subject identifier\n * when the identifier matched an existing account (e.g. wrong password for\n * a known user); omit it when the identifier was not found. Throwing the\n * generic {@link InvalidRequestError} is also accepted for backward\n * compatibility but prevents the `onSignInFailed` hook from distinguishing\n * the two cases.\n * @throws {SecondAuthenticationFactorRequiredError} - To indicate that an {@link SecondAuthenticationFactorRequiredError.type} is required in the credentials\n */\n authenticateAccount(data: AuthenticateAccountData): Awaitable<Account>\n\n /**\n * Add a client & scopes to the list of authorized clients for the given account.\n */\n setAuthorizedClient(\n sub: Sub,\n clientId: ClientId,\n data: AuthorizedClientData,\n ): Awaitable<void>\n\n /**\n * @throws {InvalidRequestError} - When the credentials are not valid\n */\n getAccount(sub: Sub): Awaitable<{\n account: Account\n authorizedClients: AuthorizedClients\n }>\n\n /**\n * @param data.requestId - If provided, the inserted account must be bound to\n * that particular requestId.\n *\n * @note Whenever a particular device account is created, all **unbound**\n * device accounts for the same `deviceId` & `sub` should be deleted.\n *\n * @note When a particular request is deleted (through\n * {@link RequestStore.deleteRequest}), all accounts bound to that request\n * should be deleted as well.\n */\n upsertDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<void>\n\n /**\n * @param requestId - If provided, the result must either have the same\n * requestId, or not be bound to a particular requestId. If `null`, the\n * result must not be bound to a particular requestId.\n * @throws {InvalidRequestError} - Instead of returning `null` in order to\n * provide a custom error message\n */\n getDeviceAccount(\n deviceId: DeviceId,\n sub: Sub,\n ): Awaitable<DeviceAccount | null>\n\n /**\n * Removes *all* the unbound device-accounts associated with the given device\n * & account.\n *\n * @note Noop if the device-account is not found.\n */\n removeDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<void>\n\n /**\n * @returns **all** the device accounts that match the {@link requestId}\n * criteria and given {@link filter}.\n */\n listDeviceAccounts(\n filter: { sub: Sub } | { deviceId: DeviceId },\n ): Awaitable<DeviceAccount[]>\n\n resetPasswordRequest(\n data: ResetPasswordRequestInput,\n ): Awaitable<null | Account>\n\n resetPasswordConfirm(\n data: ResetPasswordConfirmInput,\n ): Awaitable<null | Account>\n\n updateEmailRequest(\n data: UpdateEmailRequestInput,\n ): Awaitable<UpdateEmailRequestOutput>\n /**\n * Must trigger a verification email to be sent to the new email address, that\n * will then be confirmed through {@link updateEmailConfirm}. The account's\n * `email_verified` field is expected to become `false` until the new email is\n * confirmed.\n */\n updateEmailConfirm(data: UpdateEmailConfirmInput): Awaitable<Account | null>\n\n verifyEmailRequest(data: VerifyEmailRequestInput): Awaitable<void>\n verifyEmailConfirm(data: VerifyEmailConfirmInput): Awaitable<Account | null>\n\n /**\n * @throws {HandleUnavailableError} - To indicate that the handle is already taken\n */\n verifyHandleAvailability(handle: string): Awaitable<void>\n\n /**\n * @throws {HandleUnavailableError} - To indicate that the handle is already taken\n * @throws {InvalidRequestError} - To indicate that the handle is invalid or\n * cannot be used\n */\n updateHandle(data: UpdateHandleData): Awaitable<Account>\n}\n\nexport const isAccountStore = buildInterfaceChecker<AccountStore>([\n 'createAccount',\n 'authenticateAccount',\n 'setAuthorizedClient',\n 'getAccount',\n 'upsertDeviceAccount',\n 'getDeviceAccount',\n 'removeDeviceAccount',\n 'listDeviceAccounts',\n 'resetPasswordRequest',\n 'resetPasswordConfirm',\n 'updateEmailRequest',\n 'updateEmailConfirm',\n 'verifyEmailRequest',\n 'verifyEmailConfirm',\n 'verifyHandleAvailability',\n 'updateHandle',\n])\n\nexport function asAccountStore<V>(implementation: V): V & AccountStore {\n if (!implementation || !isAccountStore(implementation)) {\n throw new Error('Invalid AccountStore implementation')\n }\n return implementation\n}\n"]}
1
+ {"version":3,"file":"account-store.js","sourceRoot":"","sources":["../../src/account/account-store.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAa,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AACtE,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,uCAAuC,GACxC,MAAM,oBAAoB,CAAA;AAI3B,kEAAkE;AAElE,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AACxC,cAAc,wBAAwB,CAAA;AACtC,cAAc,0BAA0B,CAAA;AAWxC,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,uCAAuC,GACxC,CAAA;AA6ND,MAAM,CAAC,MAAM,cAAc,GAAG,qBAAqB,CAAe;IAChE,qBAAqB;IACrB,eAAe;IACf,mBAAmB;IACnB,sBAAsB;IACtB,sBAAsB;IACtB,YAAY;IACZ,kBAAkB;IAClB,oBAAoB;IACpB,mBAAmB;IACnB,qBAAqB;IACrB,sBAAsB;IACtB,sBAAsB;IACtB,qBAAqB;IACrB,oBAAoB;IACpB,oBAAoB;IACpB,cAAc;IACd,qBAAqB;IACrB,oBAAoB;IACpB,oBAAoB;IACpB,0BAA0B;CAC3B,CAAC,CAAA;AAEF,MAAM,UAAU,cAAc,CAAI,cAAiB;IACjD,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,CAAC;IACD,OAAO,cAAc,CAAA;AACvB,CAAC","sourcesContent":["import { Did } from '@atproto/did'\nimport type {\n Account,\n ConfirmAccountDeletionInput,\n ConfirmEmailUpdateInput,\n ConfirmEmailVerificationInput,\n ConfirmResetPasswordInput,\n DeactivateAccountInput,\n InitiateAccountDeletionInput,\n InitiateEmailUpdateInput,\n InitiateEmailUpdateOutput,\n InitiateEmailVerificationInput,\n InitiatePasswordResetInput,\n ReactivateAccountInput,\n UpdateHandleInput,\n} from '@atproto/oauth-provider-api'\nimport { OAuthScope } from '@atproto/oauth-types'\nimport { ClientId } from '../client/client-id.js'\nimport { DeviceId } from '../device/device-id.js'\nimport { DeviceData } from '../device/device-store.js'\nimport { HcaptchaVerifyResult } from '../lib/hcaptcha.js'\nimport { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'\nimport {\n HandleUnavailableError,\n InvalidCredentialsError,\n InvalidRequestError,\n SecondAuthenticationFactorRequiredError,\n} from '../oauth-errors.js'\nimport { InviteCode } from '../types/invite-code.js'\nimport { SignUpInput } from './sign-up-input.js'\n\n// Export all types needed to implement the AccountStore interface\n\nexport * from '../client/client-id.js'\nexport * from '../device/device-data.js'\nexport * from '../device/device-id.js'\nexport * from '../request/request-id.js'\n\nexport type {\n Account,\n Did,\n HcaptchaVerifyResult,\n InviteCode,\n OAuthScope,\n SignUpInput,\n}\n\nexport {\n HandleUnavailableError,\n InvalidCredentialsError,\n InvalidRequestError,\n SecondAuthenticationFactorRequiredError,\n}\n\nexport type ResetPasswordRequestInput = InitiatePasswordResetInput\nexport type ResetPasswordConfirmInput = ConfirmResetPasswordInput\n\nexport type UpdateEmailRequestInput = InitiateEmailUpdateInput\nexport type UpdateEmailRequestOutput = InitiateEmailUpdateOutput\nexport type UpdateEmailConfirmInput = ConfirmEmailUpdateInput\nexport type VerifyEmailRequestInput = InitiateEmailVerificationInput\nexport type VerifyEmailConfirmInput = ConfirmEmailVerificationInput\nexport type UpdateHandleData = UpdateHandleInput\n\nexport type DeactivateAccountData = DeactivateAccountInput\nexport type ReactivateAccountData = ReactivateAccountInput\nexport type DeleteAccountRequestInput = InitiateAccountDeletionInput\nexport type DeleteAccountConfirmInput = ConfirmAccountDeletionInput\n\nexport type CreateAccountData = {\n locale: string\n email: string\n password: string\n handle: string\n inviteCode?: string | undefined\n}\n\nexport type AuthenticateAccountData = {\n locale: string\n password: string\n username: string\n emailOtp?: string | undefined\n}\n\nexport type AuthorizedClientData = { authorizedScopes: readonly string[] }\nexport type AuthorizedClients = Map<ClientId, AuthorizedClientData>\n\nexport type DeviceAccount = {\n deviceId: DeviceId\n\n /**\n * The data associated with the device, created through the\n * {@link DeviceStore}. This data is used to identify devices on which a user\n * has logged in.\n */\n deviceData: DeviceData\n\n /**\n * The account associated with the device account.\n */\n account: Account\n\n /**\n * The list of clients that are authorized by the account, as created through\n * the {@link AccountStore.setAuthorizedClient} method.\n */\n authorizedClients: AuthorizedClients\n\n /**\n * The date at which the device account was created. This value is currently\n * not used.\n */\n createdAt: Date\n\n /**\n * The date at which the device account was last updated. This value is used\n * to determine the date at which the user last authenticated on a device\n */\n updatedAt: Date\n}\n\nexport type SignUpData = SignUpInput & {\n hcaptchaResult?: HcaptchaVerifyResult\n inviteCode?: InviteCode\n}\n\nexport interface AccountStore {\n /**\n * @throws {HandleUnavailableError} - To indicate that the handle is already taken\n * @throws {InvalidRequestError} - To indicate that some data is invalid\n */\n createAccount(data: CreateAccountData): Awaitable<Account>\n\n /**\n * @throws {InvalidCredentialsError} - When the credentials are not valid.\n * Populate {@link InvalidCredentialsError.did} with the subject identifier\n * when the identifier matched an existing account (e.g. wrong password for\n * a known user); omit it when the identifier was not found. Throwing the\n * generic {@link InvalidRequestError} is also accepted for backward\n * compatibility but prevents the `onSignInFailed` hook from distinguishing\n * the two cases.\n * @throws {SecondAuthenticationFactorRequiredError} - To indicate that an {@link SecondAuthenticationFactorRequiredError.type} is required in the credentials\n */\n authenticateAccount(data: AuthenticateAccountData): Awaitable<Account>\n\n /**\n * Add a client & scopes to the list of authorized clients for the given account.\n */\n setAuthorizedClient(\n did: Did,\n clientId: ClientId,\n data: AuthorizedClientData,\n ): Awaitable<void>\n\n /**\n * @throws {InvalidRequestError} - When the credentials are not valid\n */\n getAccount(did: Did): Awaitable<{\n account: Account\n authorizedClients: AuthorizedClients\n }>\n\n /**\n * @param data.requestId - If provided, the inserted account must be bound to\n * that particular requestId.\n *\n * @note Whenever a particular device account is created, all **unbound**\n * device accounts for the same `deviceId` & `sub` should be deleted.\n *\n * @note When a particular request is deleted (through\n * {@link RequestStore.deleteRequest}), all accounts bound to that request\n * should be deleted as well.\n */\n upsertDeviceAccount(deviceId: DeviceId, did: Did): Awaitable<void>\n\n /**\n * @param requestId - If provided, the result must either have the same\n * requestId, or not be bound to a particular requestId. If `null`, the\n * result must not be bound to a particular requestId.\n * @throws {InvalidRequestError} - Instead of returning `null` in order to\n * provide a custom error message\n */\n getDeviceAccount(\n deviceId: DeviceId,\n did: Did,\n ): Awaitable<DeviceAccount | null>\n\n /**\n * Removes *all* the unbound device-accounts associated with the given device\n * & account.\n *\n * @note Noop if the device-account is not found.\n */\n removeDeviceAccount(deviceId: DeviceId, did: Did): Awaitable<void>\n\n /**\n * @returns **all** the device accounts that match the {@link requestId}\n * criteria and given {@link filter}.\n */\n listDeviceAccounts(\n filter: { did: Did } | { deviceId: DeviceId },\n ): Awaitable<DeviceAccount[]>\n\n resetPasswordRequest(\n data: ResetPasswordRequestInput,\n ): Awaitable<null | Account>\n\n resetPasswordConfirm(\n data: ResetPasswordConfirmInput,\n ): Awaitable<null | Account>\n\n updateEmailRequest(\n data: UpdateEmailRequestInput,\n ): Awaitable<UpdateEmailRequestOutput>\n /**\n * Must trigger a verification email to be sent to the new email address, that\n * will then be confirmed through {@link updateEmailConfirm}. The account's\n * {@link Account['emailVerified'] emailVerified} field is expected to become\n * `false` until the new email is confirmed.\n */\n updateEmailConfirm(data: UpdateEmailConfirmInput): Awaitable<Account | null>\n\n verifyEmailRequest(data: VerifyEmailRequestInput): Awaitable<void>\n verifyEmailConfirm(data: VerifyEmailConfirmInput): Awaitable<Account | null>\n\n /**\n * @throws {HandleUnavailableError} - To indicate that the handle is already taken\n */\n verifyHandleAvailability(handle: string): Awaitable<void>\n\n /**\n * @throws {HandleUnavailableError} - To indicate that the handle is already taken\n * @throws {InvalidRequestError} - To indicate that the handle is invalid or\n * cannot be used\n */\n updateHandle(data: UpdateHandleData): Awaitable<Account>\n\n /**\n * Mark the account as deactivated. The account remains recoverable. Should\n * be a no-op when the account is already deactivated.\n *\n * @throws {InvalidRequestError} - When the account cannot be deactivated\n * (e.g. unknown account)\n */\n deactivateAccount(data: DeactivateAccountData): Awaitable<Account>\n\n /**\n * Reactivate a previously-deactivated account. Should be a no-op when the\n * account is already active.\n *\n * @throws {InvalidRequestError} - When the account cannot be reactivated\n * (e.g. unknown account)\n */\n reactivateAccount(data: ReactivateAccountData): Awaitable<Account>\n\n /**\n * Initiate account deletion: typically sends a confirmation token to the\n * account's email address. The account is NOT deleted until\n * {@link deleteAccountConfirm} is called with the matching token and the\n * user's current password.\n */\n deleteAccountRequest(data: DeleteAccountRequestInput): Awaitable<void>\n\n /**\n * Finalize account deletion. Implementations MUST verify both the email\n * confirmation `token` issued by {@link deleteAccountRequest} and the user's\n * current `password` before deleting any data. Deletion is irreversible.\n *\n * @throws {InvalidRequestError} - When the token or password is invalid.\n */\n deleteAccountConfirm(data: DeleteAccountConfirmInput): Awaitable<void>\n}\n\nexport const isAccountStore = buildInterfaceChecker<AccountStore>([\n 'authenticateAccount',\n 'createAccount',\n 'deactivateAccount',\n 'deleteAccountConfirm',\n 'deleteAccountRequest',\n 'getAccount',\n 'getDeviceAccount',\n 'listDeviceAccounts',\n 'reactivateAccount',\n 'removeDeviceAccount',\n 'resetPasswordConfirm',\n 'resetPasswordRequest',\n 'setAuthorizedClient',\n 'updateEmailConfirm',\n 'updateEmailRequest',\n 'updateHandle',\n 'upsertDeviceAccount',\n 'verifyEmailConfirm',\n 'verifyEmailRequest',\n 'verifyHandleAvailability',\n])\n\nexport function asAccountStore<V>(implementation: V): V & AccountStore {\n if (!implementation || !isAccountStore(implementation)) {\n throw new Error('Invalid AccountStore implementation')\n }\n return implementation\n}\n"]}
@@ -6,13 +6,13 @@ export declare const signInDataSchema: z.ZodObject<{
6
6
  emailOtp: z.ZodOptional<z.ZodString>;
7
7
  }, "strict", z.ZodTypeAny, {
8
8
  locale: string;
9
- password: string;
10
9
  username: string;
10
+ password: string;
11
11
  emailOtp?: string | undefined;
12
12
  }, {
13
13
  locale: string;
14
- password: string;
15
14
  username: string;
15
+ password: string;
16
16
  emailOtp?: string | undefined;
17
17
  }>;
18
18
  export type SignInData = z.output<typeof signInDataSchema>;
@@ -1,23 +1,23 @@
1
1
  import { z } from 'zod';
2
2
  export declare const signUpInputSchema: z.ZodObject<{
3
3
  locale: z.ZodString;
4
- handle: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
4
+ handle: z.ZodEffects<z.ZodString, `${string}.${string}`, string>;
5
5
  email: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>, string, string>;
6
6
  password: z.ZodString;
7
7
  inviteCode: z.ZodOptional<z.ZodString>;
8
8
  hcaptchaToken: z.ZodOptional<z.ZodString>;
9
9
  }, "strict", z.ZodTypeAny, {
10
- email: string;
11
10
  locale: string;
11
+ handle: `${string}.${string}`;
12
+ email: string;
12
13
  password: string;
13
- handle: string;
14
14
  inviteCode?: string | undefined;
15
15
  hcaptchaToken?: string | undefined;
16
16
  }, {
17
- email: string;
18
17
  locale: string;
19
- password: string;
20
18
  handle: string;
19
+ email: string;
20
+ password: string;
21
21
  inviteCode?: string | undefined;
22
22
  hcaptchaToken?: string | undefined;
23
23
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"client-manager.d.ts","sourceRoot":"","sources":["../../src/client/client-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAiB,MAAM,cAAc,CAAA;AAC1D,OAAO,EACL,gCAAgC,EAChC,yBAAyB,EACzB,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,EAKzB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,KAAK,EAKN,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EACL,YAAY,EAEZ,WAAW,EACZ,MAAM,4BAA4B,CAAA;AAInC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAepC,MAAM,MAAM,sBAAsB,GAAG,CACnC,GAAG,EAAE,MAAM,KACR,SAAS,CAAC,wBAAwB,CAAC,CAAA;AAExC,qBAAa,aAAa;IAKtB,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,gCAAgC;IACnE,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACjC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,UAAU;IACpC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAC5C,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,sBAAsB,GAAG,IAAI;IARpE,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IACnD,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,YAAY,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;gBAGvD,cAAc,EAAE,gCAAgC,EAChD,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,WAAW,GAAG,IAAI,EACzB,gBAAgB,GAAE,sBAAsB,GAAG,IAAI,aAAO,EACzE,SAAS,EAAE,KAAK,EAChB,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,EAC1C,mBAAmB,EAAE,WAAW,CAAC,MAAM,EAAE,mBAAmB,CAAC;IAsB/D;;;OAGG;IACU,SAAS,CAAC,QAAQ,EAAE,QAAQ;IAiC5B,WAAW,CACtB,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC7B,EACE,OAEC,GACF,GAAE;QACD,OAAO,CAAC,EAAE,CACR,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,QAAQ,KACf,SAAS,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;KACrC,GACL,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;cAoBjB,iBAAiB,CAC/B,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,mBAAmB,CAAC;cAYf,yBAAyB,CACvC,QAAQ,EAAE,qBAAqB,GAC9B,OAAO,CAAC,mBAAmB,CAAC;cA2Bf,6BAA6B,CAC3C,QAAQ,EAAE,yBAAyB,GAClC,OAAO,CAAC,mBAAmB,CAAC;cAYf,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,mBAAmB,CAAC;IAS/B;;;;;OAKG;IACH,SAAS,CAAC,sBAAsB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,mBAAmB,GAC5B,mBAAmB;IAsZtB,8BAA8B,CAC5B,QAAQ,EAAE,qBAAqB,EAC/B,QAAQ,EAAE,mBAAmB,GAC5B,mBAAmB;IAuBtB,kCAAkC,CAChC,QAAQ,EAAE,yBAAyB,EACnC,QAAQ,EAAE,mBAAmB,GAC5B,mBAAmB;CAgFvB"}
1
+ {"version":3,"file":"client-manager.d.ts","sourceRoot":"","sources":["../../src/client/client-manager.ts"],"names":[],"mappings":"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"}
@@ -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"]}
@@ -12,7 +12,7 @@ export declare class Client {
12
12
  /**
13
13
  * @see {@link https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#token-endpoint-auth-method}
14
14
  */
15
- static readonly AUTH_METHODS_SUPPORTED: readonly ["none", "private_key_jwt"];
15
+ static readonly AUTH_METHODS_SUPPORTED: readonly ['none', 'private_key_jwt'];
16
16
  private readonly keyGetter;
17
17
  constructor(id: ClientId, metadata: OAuthClientMetadata, jwks: undefined | Jwks, info: ClientInfo);
18
18
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAE3B,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAEhB,KAAK,eAAe,EAOrB,MAAM,MAAM,CAAA;AACb,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAEL,mCAAmC,EACnC,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,sBAAsB,CAAA;AAW7B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAI7C,qBAAa,MAAM;aAWC,EAAE,EAAE,QAAQ;aACZ,QAAQ,EAAE,mBAAmB;aAC7B,IAAI,EAAE,SAAS,GAAG,IAAI;aACtB,IAAI,EAAE,UAAU;IAblC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,sBAAsB,uCAAuC;IAE7E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAEU;gBAGlB,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,mBAAmB,EAC7B,IAAI,EAAE,SAAS,GAAG,IAAoB,EACtC,IAAI,EAAE,UAAU;IASlC;;OAEG;IACU,mBAAmB,CAC9B,GAAG,EAAE,SAAS,GAAG,WAAW,EAC5B,QAAQ,EAAE,MAAM;cAyCF,kBAAkB,CAAC,WAAW,GAAG,UAAU,EACzD,KAAK,EAAE,MAAM,EACb,EACE,QAAQ,EACR,oBAA4B,EAC5B,kBAA0B,EAC1B,GAAG,OAAO,EACX,GAAE,IAAI,CAAC,2BAA2B,EAAE,QAAQ,CAAC,GAAG;QAC/C,kBAAkB,CAAC,EAAE,OAAO,CAAA;QAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAA;KAC1B,GACL,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;cAyBxB,SAAS,CAAC,WAAW,GAAG,UAAU,EAChD,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,GACzC,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IAO/D;;;;OAIG;IACU,YAAY,CACvB,KAAK,EAAE,sBAAsB,EAC7B,MAAM,EAAE;QACN,6BAA6B,EAAE,MAAM,CAAA;KACtC,GACA,OAAO,CAAC,UAAU,CAAC;IAkHtB;;OAEG;IACI,eAAe,CACpB,UAAU,EAAE,QAAQ,CAAC,mCAAmC,CAAC,GACxD,QAAQ,CAAC,mCAAmC,CAAC;IA8FhD,IAAI,kBAAkB,IAAI,gBAAgB,GAAG,SAAS,CAGrD;CACF;AAED,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,UAAU,GAAG,OAAO,GACxB,OAAO,CAAC,MAAM,CAAC,CAMjB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAE3B,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAEhB,KAAK,eAAe,EAOrB,MAAM,MAAM,CAAA;AACb,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAEL,mCAAmC,EACnC,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,sBAAsB,CAAA;AAW7B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAI7C,qBAAa,MAAM;aAWC,EAAE,EAAE,QAAQ;aACZ,QAAQ,EAAE,mBAAmB;aAC7B,IAAI,EAAE,SAAS,GAAG,IAAI;aACtB,IAAI,EAAE,UAAU;IAblC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,sBAAsB,YAAI,MAAM,EAAE,iBAAiB,EAAU;IAE7E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAEU;IAEpC,YACkB,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,mBAAmB,EAC7B,IAAI,EAAE,SAAS,GAAG,IAAoB,EACtC,IAAI,EAAE,UAAU,EAOjC;IAED;;OAEG;IACU,mBAAmB,CAC9B,GAAG,EAAE,SAAS,GAAG,WAAW,EAC5B,QAAQ,EAAE,MAAM,+FAuCjB;IAED,UAAgB,kBAAkB,CAAC,WAAW,GAAG,UAAU,EACzD,KAAK,EAAE,MAAM,EACb,EACE,QAAQ,EACR,oBAA4B,EAC5B,kBAA0B,EAC1B,GAAG,OAAO,EACX,GAAE,IAAI,CAAC,2BAA2B,EAAE,QAAQ,CAAC,GAAG;QAC/C,kBAAkB,CAAC,EAAE,OAAO,CAAA;QAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAA;KAC1B,GACL,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAuBvC;IAED,UAAgB,SAAS,CAAC,WAAW,GAAG,UAAU,EAChD,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,GACzC,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAK9D;IAED;;;;OAIG;IACU,YAAY,CACvB,KAAK,EAAE,sBAAsB,EAC7B,MAAM,EAAE;QACN,6BAA6B,EAAE,MAAM,CAAA;KACtC,GACA,OAAO,CAAC,UAAU,CAAC,CAgHrB;IAED;;OAEG;IACI,eAAe,CACpB,UAAU,EAAE,QAAQ,CAAC,mCAAmC,CAAC,GACxD,QAAQ,CAAC,mCAAmC,CAAC,CA4F/C;IAED,IAAI,kBAAkB,IAAI,gBAAgB,GAAG,SAAS,CAGrD;CACF;AAED,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,UAAU,GAAG,OAAO,GACxB,OAAO,CAAC,MAAM,CAAC,CAMjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n JWTClaimVerificationOptions,\n type JWTHeaderParameters,\n type JWTPayload,\n type JWTVerifyOptions,\n type JWTVerifyResult,\n type KeyLike,\n type ResolvedKey,\n UnsecuredJWT,\n type UnsecuredResult,\n calculateJwkThumbprint,\n createLocalJWKSet,\n createRemoteJWKSet,\n errors,\n exportJWK,\n jwtVerify,\n} from 'jose'\nimport { Jwks, SignedJwt, UnsignedJwt } from '@atproto/jwk'\nimport {\n CLIENT_ASSERTION_TYPE_JWT_BEARER,\n OAuthAuthorizationRequestParameters,\n OAuthClientCredentials,\n OAuthClientMetadata,\n OAuthRedirectUri,\n} from '@atproto/oauth-types'\nimport { CLIENT_ASSERTION_MAX_AGE, JAR_MAX_AGE } from '../constants.js'\nimport { AuthorizationError } from '../errors/authorization-error.js'\nimport { InvalidAuthorizationDetailsError } from '../errors/invalid-authorization-details-error.js'\nimport { InvalidClientError } from '../errors/invalid-client-error.js'\nimport { InvalidClientMetadataError } from '../errors/invalid-client-metadata-error.js'\nimport { InvalidRequestError } from '../errors/invalid-request-error.js'\nimport { InvalidScopeError } from '../errors/invalid-scope-error.js'\nimport { asArray } from '../lib/util/cast.js'\nimport { compareRedirectUri } from '../lib/util/redirect-uri.js'\nimport { Awaitable } from '../lib/util/type.js'\nimport { ClientAuth } from './client-auth.js'\nimport { ClientId } from './client-id.js'\nimport { ClientInfo } from './client-info.js'\n\nconst { JOSEError } = errors\n\nexport class Client {\n /**\n * @see {@link https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#token-endpoint-auth-method}\n */\n static readonly AUTH_METHODS_SUPPORTED = ['none', 'private_key_jwt'] as const\n\n private readonly keyGetter: (\n protectedHeader: JWTHeaderParameters,\n ) => Awaitable<KeyLike | Uint8Array>\n\n constructor(\n public readonly id: ClientId,\n public readonly metadata: OAuthClientMetadata,\n public readonly jwks: undefined | Jwks = metadata.jwks,\n public readonly info: ClientInfo,\n ) {\n // If the remote JWKS content is provided, we don't need to fetch it again.\n this.keyGetter =\n jwks || !metadata.jwks_uri\n ? createLocalJWKSet(jwks || { keys: [] })\n : createRemoteJWKSet(new URL(metadata.jwks_uri), {})\n }\n\n /**\n * @see {@link https://www.rfc-editor.org/rfc/rfc9101.html#name-request-object-2}\n */\n public async decodeRequestObject(\n jar: SignedJwt | UnsignedJwt,\n audience: string,\n ) {\n // https://www.rfc-editor.org/rfc/rfc9101.html#name-request-object-2\n // > If signed, the Authorization Request Object SHOULD contain the Claims\n // > iss (issuer) and aud (audience) as members with their semantics being\n // > the same as defined in the JWT [RFC7519] specification. The value of\n // > aud should be the value of the authorization server (AS) issuer, as\n // > defined in RFC 8414 [RFC8414].\n try {\n // We need to special case the \"none\" algorithm, as the validation method\n // is different for signed and unsigned JWTs.\n if (this.metadata.request_object_signing_alg === 'none') {\n return await this.jwtVerifyUnsecured(jar, {\n audience,\n maxTokenAge: JAR_MAX_AGE / 1e3,\n allowMissingAudience: true,\n allowMissingIssuer: true,\n })\n }\n\n return await this.jwtVerify(jar, {\n audience,\n maxTokenAge: JAR_MAX_AGE / 1e3,\n algorithms: this.metadata.request_object_signing_alg\n ? [this.metadata.request_object_signing_alg]\n : // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2\n //\n // > The default, if omitted, is that any algorithm supported by the OP\n // > and the RP MAY be used.\n undefined,\n })\n } catch (err) {\n const message =\n err instanceof JOSEError\n ? `Invalid \"request\" object: ${err.message}`\n : `Invalid \"request\" object`\n\n throw new InvalidRequestError(message, err)\n }\n }\n\n protected async jwtVerifyUnsecured<PayloadType = JWTPayload>(\n token: string,\n {\n audience,\n allowMissingAudience = false,\n allowMissingIssuer = false,\n ...options\n }: Omit<JWTClaimVerificationOptions, 'issuer'> & {\n allowMissingIssuer?: boolean\n allowMissingAudience?: boolean\n } = {},\n ): Promise<UnsecuredResult<PayloadType>> {\n // jose does not support `allowMissingAudience` and `allowMissingIssuer`\n // options, so we need to handle audience and issuer checks manually (see\n // bellow).\n\n const result = UnsecuredJWT.decode<PayloadType>(token, options)\n\n if (!allowMissingIssuer || result.payload.iss != null) {\n if (result.payload.iss !== this.id) {\n throw new JOSEError(`Invalid \"iss\" claim \"${result.payload.iss}\"`)\n }\n }\n\n if (!allowMissingAudience || result.payload.aud != null) {\n if (audience != null) {\n const payloadAud = asArray(result.payload.aud)\n if (!asArray(audience).some((aud) => payloadAud.includes(aud))) {\n throw new JOSEError(`Invalid \"aud\" claim \"${result.payload.aud}\"`)\n }\n }\n }\n\n return result\n }\n\n protected async jwtVerify<PayloadType = JWTPayload>(\n token: string,\n options?: Omit<JWTVerifyOptions, 'issuer'>,\n ): Promise<JWTVerifyResult<PayloadType> & ResolvedKey<KeyLike>> {\n return jwtVerify<PayloadType>(token, this.keyGetter, {\n ...options,\n issuer: this.id,\n })\n }\n\n /**\n * @see {@link https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1}\n * @see {@link https://datatracker.ietf.org/doc/html/rfc7523#section-3}\n * @see {@link https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#token-endpoint-auth-method}\n */\n public async authenticate(\n input: OAuthClientCredentials,\n checks: {\n authorizationServerIdentifier: string\n },\n ): Promise<ClientAuth> {\n const method = this.metadata.token_endpoint_auth_method\n\n if (method === 'none') {\n return { method: 'none' }\n }\n\n if (method === 'private_key_jwt') {\n if (!('client_assertion' in input)) {\n throw new InvalidRequestError(\n `client authentication method \"${method}\" required a \"client_assertion\"`,\n )\n }\n\n if (input.client_assertion_type === CLIENT_ASSERTION_TYPE_JWT_BEARER) {\n // https://www.rfc-editor.org/rfc/rfc7523.html#section-3\n\n const result = await this.jwtVerify<{\n jti: string\n exp?: number\n }>(input.client_assertion, {\n // > 1. The JWT MUST contain an \"iss\" (issuer) claim that contains a\n // > unique identifier for the entity that issued the JWT.\n //\n // The \"issuer\" is already checked by jwtVerify()\n\n // > 2. The JWT MUST contain a \"sub\" (subject) claim identifying the\n // > principal that is the subject of the JWT. Two cases need to be\n // > differentiated: [...] For client authentication, the subject\n // > MUST be the \"client_id\" of the OAuth client.\n subject: this.id,\n\n // > 3. The JWT MUST contain an \"aud\" (audience) claim containing a\n // > value that identifies the authorization server as an intended\n // > audience. The token endpoint URL of the authorization server\n // > MAY be used as a value for an \"aud\" element to identify the\n // > authorization server as an intended audience of the JWT.\n audience: checks.authorizationServerIdentifier,\n\n requiredClaims: [\n // > 4. The JWT MUST contain an \"exp\" (expiration time) claim that\n // > limits the time window during which the JWT can be used.\n //\n // @TODO The presence of \"exp\" didn't use to be enforced by this\n // implementation (or provided by the oauth-client). This is mostly\n // fine because \"iat\" *is* required, but this makes this\n // implementation non compliant with RFC7523. We can't just make it\n // required as it might break existing clients.\n\n // 'exp',\n\n // > 7. The JWT MAY contain a \"jti\" (JWT ID) claim that provides a\n // > unique identifier for the token. The authorization server\n // > MAY ensure that JWTs are not replayed by maintaining the set\n // > of used \"jti\" values for the length of time for which the\n // > JWT would be considered valid based on the applicable \"exp\"\n // > instant.\n 'jti',\n ],\n\n // > 5. The JWT MAY contain an \"nbf\" (not before) claim that\n // > identifies the time before which the token MUST NOT be\n // > accepted for processing.\n //\n // This is already enforced by jose\n\n // > 6. The JWT MAY contain an \"iat\" (issued at) claim that identifies\n // > the time at which the JWT was issued. Note that the\n // > authorization server may reject JWTs with an \"iat\" claim value\n // > that is unreasonably far in the past.\n maxTokenAge: CLIENT_ASSERTION_MAX_AGE / 1000,\n }).catch((err) => {\n const msg =\n err instanceof JOSEError\n ? `Validation of \"client_assertion\" failed: ${err.message}`\n : `Unable to verify \"client_assertion\" JWT`\n\n throw new InvalidClientError(msg, err)\n })\n\n if (!result.protectedHeader.kid) {\n throw new InvalidClientError(`\"kid\" required in client_assertion`)\n }\n\n return {\n method: 'private_key_jwt',\n jti: result.payload.jti,\n exp: result.payload.exp,\n jkt: await authJwkThumbprint(result.key),\n alg: result.protectedHeader.alg,\n kid: result.protectedHeader.kid,\n }\n }\n\n throw new InvalidClientError(\n `Unsupported client_assertion_type \"${input.client_assertion_type}\"`,\n )\n }\n\n // @ts-expect-error Ensure to keep Client.AUTH_METHODS_SUPPORTED in sync\n // with the implementation of this function.\n if (Client.AUTH_METHODS_SUPPORTED.includes(method)) {\n throw new Error(\n `verifyCredentials() should implement all of ${[\n Client.AUTH_METHODS_SUPPORTED,\n ]}`,\n )\n }\n\n throw new InvalidClientMetadataError(\n `Unsupported token_endpoint_auth_method \"${method}\"`,\n )\n }\n\n /**\n * Validates the request parameters against the client metadata.\n */\n public validateRequest(\n parameters: Readonly<OAuthAuthorizationRequestParameters>,\n ): Readonly<OAuthAuthorizationRequestParameters> {\n if (parameters.client_id !== this.id) {\n throw new AuthorizationError(\n parameters,\n 'The \"client_id\" parameter field does not match the value used to authenticate the client',\n )\n }\n\n if (parameters.scope !== undefined) {\n // Any scope requested by the client must be registered in the client\n // metadata.\n const declaredScopes = this.metadata.scope?.split(' ')\n\n if (!declaredScopes) {\n throw new InvalidScopeError(\n parameters,\n 'Client has no declared scopes in its metadata',\n )\n }\n\n for (const scope of parameters.scope.split(' ')) {\n if (!declaredScopes.includes(scope)) {\n throw new InvalidScopeError(\n parameters,\n `Scope \"${scope}\" is not declared in the client metadata`,\n )\n }\n }\n }\n\n if (!this.metadata.response_types.includes(parameters.response_type)) {\n throw new AuthorizationError(\n parameters,\n `Invalid response_type \"${parameters.response_type}\" requested by the client`,\n )\n }\n\n if (parameters.response_type.includes('code')) {\n if (!this.metadata.grant_types.includes('authorization_code')) {\n throw new AuthorizationError(\n parameters,\n `This client is not allowed to use the \"authorization_code\" grant type`,\n )\n }\n }\n\n const { redirect_uri } = parameters\n if (redirect_uri) {\n if (\n !this.metadata.redirect_uris.some((uri) =>\n compareRedirectUri(uri, redirect_uri),\n )\n ) {\n throw new AuthorizationError(\n parameters,\n `Invalid redirect_uri ${redirect_uri}`,\n )\n }\n } else {\n const { defaultRedirectUri } = this\n if (defaultRedirectUri) {\n parameters = { ...parameters, redirect_uri: defaultRedirectUri }\n } else {\n // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10#authorization-request\n //\n // > \"redirect_uri\": OPTIONAL if only one redirect URI is registered for\n // > this client. REQUIRED if multiple redirect URIs are registered for this\n // > client.\n throw new AuthorizationError(parameters, 'redirect_uri is required')\n }\n }\n\n if (parameters.authorization_details) {\n const { authorization_details_types } = this.metadata\n if (!authorization_details_types) {\n throw new InvalidAuthorizationDetailsError(\n parameters,\n 'Client Metadata does not declare any \"authorization_details\"',\n )\n }\n\n for (const detail of parameters.authorization_details) {\n if (!authorization_details_types?.includes(detail.type)) {\n throw new InvalidAuthorizationDetailsError(\n parameters,\n `Client Metadata does not declare any \"authorization_details\" of type \"${detail.type}\"`,\n )\n }\n }\n }\n\n return parameters\n }\n\n get defaultRedirectUri(): OAuthRedirectUri | undefined {\n const { redirect_uris } = this.metadata\n return redirect_uris.length === 1 ? redirect_uris[0] : undefined\n }\n}\n\nexport async function authJwkThumbprint(\n key: Uint8Array | KeyLike,\n): Promise<string> {\n try {\n return await calculateJwkThumbprint(await exportJWK(key), 'sha512')\n } catch (err) {\n throw new InvalidClientError('Unable to compute JWK thumbprint', err)\n }\n}\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n JWTClaimVerificationOptions,\n type JWTHeaderParameters,\n type JWTPayload,\n type JWTVerifyOptions,\n type JWTVerifyResult,\n type KeyLike,\n type ResolvedKey,\n UnsecuredJWT,\n type UnsecuredResult,\n calculateJwkThumbprint,\n createLocalJWKSet,\n createRemoteJWKSet,\n errors,\n exportJWK,\n jwtVerify,\n} from 'jose'\nimport { Jwks, SignedJwt, UnsignedJwt } from '@atproto/jwk'\nimport {\n CLIENT_ASSERTION_TYPE_JWT_BEARER,\n OAuthAuthorizationRequestParameters,\n OAuthClientCredentials,\n OAuthClientMetadata,\n OAuthRedirectUri,\n} from '@atproto/oauth-types'\nimport { CLIENT_ASSERTION_MAX_AGE, JAR_MAX_AGE } from '../constants.js'\nimport { AuthorizationError } from '../errors/authorization-error.js'\nimport { InvalidAuthorizationDetailsError } from '../errors/invalid-authorization-details-error.js'\nimport { InvalidClientError } from '../errors/invalid-client-error.js'\nimport { InvalidClientMetadataError } from '../errors/invalid-client-metadata-error.js'\nimport { InvalidRequestError } from '../errors/invalid-request-error.js'\nimport { InvalidScopeError } from '../errors/invalid-scope-error.js'\nimport { asArray } from '../lib/util/cast.js'\nimport { compareRedirectUri } from '../lib/util/redirect-uri.js'\nimport { Awaitable } from '../lib/util/type.js'\nimport { ClientAuth } from './client-auth.js'\nimport { ClientId } from './client-id.js'\nimport { ClientInfo } from './client-info.js'\n\nconst { JOSEError } = errors\n\nexport class Client {\n /**\n * @see {@link https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#token-endpoint-auth-method}\n */\n static readonly AUTH_METHODS_SUPPORTED = ['none', 'private_key_jwt'] as const\n\n private readonly keyGetter: (\n protectedHeader: JWTHeaderParameters,\n ) => Awaitable<KeyLike | Uint8Array>\n\n constructor(\n public readonly id: ClientId,\n public readonly metadata: OAuthClientMetadata,\n public readonly jwks: undefined | Jwks = metadata.jwks,\n public readonly info: ClientInfo,\n ) {\n // If the remote JWKS content is provided, we don't need to fetch it again.\n this.keyGetter =\n jwks || !metadata.jwks_uri\n ? createLocalJWKSet(jwks || { keys: [] })\n : createRemoteJWKSet(new URL(metadata.jwks_uri), {})\n }\n\n /**\n * @see {@link https://www.rfc-editor.org/rfc/rfc9101.html#name-request-object-2}\n */\n public async decodeRequestObject(\n jar: SignedJwt | UnsignedJwt,\n audience: string,\n ) {\n // https://www.rfc-editor.org/rfc/rfc9101.html#name-request-object-2\n // > If signed, the Authorization Request Object SHOULD contain the Claims\n // > iss (issuer) and aud (audience) as members with their semantics being\n // > the same as defined in the JWT [RFC7519] specification. The value of\n // > aud should be the value of the authorization server (AS) issuer, as\n // > defined in RFC 8414 [RFC8414].\n try {\n // We need to special case the \"none\" algorithm, as the validation method\n // is different for signed and unsigned JWTs.\n if (this.metadata.request_object_signing_alg === 'none') {\n return await this.jwtVerifyUnsecured(jar, {\n audience,\n maxTokenAge: JAR_MAX_AGE / 1e3,\n allowMissingAudience: true,\n allowMissingIssuer: true,\n })\n }\n\n return await this.jwtVerify(jar, {\n audience,\n maxTokenAge: JAR_MAX_AGE / 1e3,\n algorithms: this.metadata.request_object_signing_alg\n ? [this.metadata.request_object_signing_alg]\n : // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2\n //\n // > The default, if omitted, is that any algorithm supported by the OP\n // > and the RP MAY be used.\n undefined,\n })\n } catch (err) {\n const message =\n err instanceof JOSEError\n ? `Invalid \"request\" object: ${err.message}`\n : `Invalid \"request\" object`\n\n throw new InvalidRequestError(message, err)\n }\n }\n\n protected async jwtVerifyUnsecured<PayloadType = JWTPayload>(\n token: string,\n {\n audience,\n allowMissingAudience = false,\n allowMissingIssuer = false,\n ...options\n }: Omit<JWTClaimVerificationOptions, 'issuer'> & {\n allowMissingIssuer?: boolean\n allowMissingAudience?: boolean\n } = {},\n ): Promise<UnsecuredResult<PayloadType>> {\n // jose does not support `allowMissingAudience` and `allowMissingIssuer`\n // options, so we need to handle audience and issuer checks manually (see\n // bellow).\n\n const result = UnsecuredJWT.decode<PayloadType>(token, options)\n\n if (!allowMissingIssuer || result.payload.iss != null) {\n if (result.payload.iss !== this.id) {\n throw new JOSEError(`Invalid \"iss\" claim \"${result.payload.iss}\"`)\n }\n }\n\n if (!allowMissingAudience || result.payload.aud != null) {\n if (audience != null) {\n const payloadAud = asArray(result.payload.aud)\n if (!asArray(audience).some((aud) => payloadAud.includes(aud))) {\n throw new JOSEError(`Invalid \"aud\" claim \"${result.payload.aud}\"`)\n }\n }\n }\n\n return result\n }\n\n protected async jwtVerify<PayloadType = JWTPayload>(\n token: string,\n options?: Omit<JWTVerifyOptions, 'issuer'>,\n ): Promise<JWTVerifyResult<PayloadType> & ResolvedKey<KeyLike>> {\n return jwtVerify<PayloadType>(token, this.keyGetter, {\n ...options,\n issuer: this.id,\n })\n }\n\n /**\n * @see {@link https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1}\n * @see {@link https://datatracker.ietf.org/doc/html/rfc7523#section-3}\n * @see {@link https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#token-endpoint-auth-method}\n */\n public async authenticate(\n input: OAuthClientCredentials,\n checks: {\n authorizationServerIdentifier: string\n },\n ): Promise<ClientAuth> {\n const method = this.metadata.token_endpoint_auth_method\n\n if (method === 'none') {\n return { method: 'none' }\n }\n\n if (method === 'private_key_jwt') {\n if (!('client_assertion' in input)) {\n throw new InvalidRequestError(\n `client authentication method \"${method}\" required a \"client_assertion\"`,\n )\n }\n\n if (input.client_assertion_type === CLIENT_ASSERTION_TYPE_JWT_BEARER) {\n // https://www.rfc-editor.org/rfc/rfc7523.html#section-3\n\n const result = await this.jwtVerify<{\n jti: string\n exp?: number\n }>(input.client_assertion, {\n // > 1. The JWT MUST contain an \"iss\" (issuer) claim that contains a\n // > unique identifier for the entity that issued the JWT.\n //\n // The \"issuer\" is already checked by jwtVerify()\n\n // > 2. The JWT MUST contain a \"sub\" (subject) claim identifying the\n // > principal that is the subject of the JWT. Two cases need to be\n // > differentiated: [...] For client authentication, the subject\n // > MUST be the \"client_id\" of the OAuth client.\n subject: this.id,\n\n // > 3. The JWT MUST contain an \"aud\" (audience) claim containing a\n // > value that identifies the authorization server as an intended\n // > audience. The token endpoint URL of the authorization server\n // > MAY be used as a value for an \"aud\" element to identify the\n // > authorization server as an intended audience of the JWT.\n audience: checks.authorizationServerIdentifier,\n\n requiredClaims: [\n // > 4. The JWT MUST contain an \"exp\" (expiration time) claim that\n // > limits the time window during which the JWT can be used.\n //\n // @TODO The presence of \"exp\" didn't use to be enforced by this\n // implementation (or provided by the oauth-client). This is mostly\n // fine because \"iat\" *is* required, but this makes this\n // implementation non compliant with RFC7523. We can't just make it\n // required as it might break existing clients.\n\n // 'exp',\n\n // > 7. The JWT MAY contain a \"jti\" (JWT ID) claim that provides a\n // > unique identifier for the token. The authorization server\n // > MAY ensure that JWTs are not replayed by maintaining the set\n // > of used \"jti\" values for the length of time for which the\n // > JWT would be considered valid based on the applicable \"exp\"\n // > instant.\n 'jti',\n ],\n\n // > 5. The JWT MAY contain an \"nbf\" (not before) claim that\n // > identifies the time before which the token MUST NOT be\n // > accepted for processing.\n //\n // This is already enforced by jose\n\n // > 6. The JWT MAY contain an \"iat\" (issued at) claim that identifies\n // > the time at which the JWT was issued. Note that the\n // > authorization server may reject JWTs with an \"iat\" claim value\n // > that is unreasonably far in the past.\n maxTokenAge: CLIENT_ASSERTION_MAX_AGE / 1000,\n }).catch((err) => {\n const msg =\n err instanceof JOSEError\n ? `Validation of \"client_assertion\" failed: ${err.message}`\n : `Unable to verify \"client_assertion\" JWT`\n\n throw new InvalidClientError(msg, err)\n })\n\n if (!result.protectedHeader.kid) {\n throw new InvalidClientError(`\"kid\" required in client_assertion`)\n }\n\n return {\n method: 'private_key_jwt',\n jti: result.payload.jti,\n exp: result.payload.exp,\n jkt: await authJwkThumbprint(result.key),\n alg: result.protectedHeader.alg,\n kid: result.protectedHeader.kid,\n }\n }\n\n throw new InvalidClientError(\n `Unsupported client_assertion_type \"${input.client_assertion_type}\"`,\n )\n }\n\n // @ts-expect-error Ensure to keep Client.AUTH_METHODS_SUPPORTED in sync\n // with the implementation of this function.\n if (Client.AUTH_METHODS_SUPPORTED.includes(method)) {\n throw new Error(\n `verifyCredentials() should implement all of ${[\n Client.AUTH_METHODS_SUPPORTED,\n ]}`,\n )\n }\n\n throw new InvalidClientMetadataError(\n `Unsupported token_endpoint_auth_method \"${method}\"`,\n )\n }\n\n /**\n * Validates the request parameters against the client metadata.\n */\n public validateRequest(\n parameters: Readonly<OAuthAuthorizationRequestParameters>,\n ): Readonly<OAuthAuthorizationRequestParameters> {\n if (parameters.client_id !== this.id) {\n throw new AuthorizationError(\n parameters,\n 'The \"client_id\" parameter field does not match the value used to authenticate the client',\n )\n }\n\n if (parameters.scope !== undefined) {\n // Any scope requested by the client must be registered in the client\n // metadata.\n const declaredScopes = this.metadata.scope?.split(' ')\n\n if (!declaredScopes) {\n throw new InvalidScopeError(\n parameters,\n 'Client has no declared scopes in its metadata',\n )\n }\n\n for (const scope of parameters.scope.split(' ')) {\n if (!declaredScopes.includes(scope)) {\n throw new InvalidScopeError(\n parameters,\n `Scope \"${scope}\" is not declared in the client metadata`,\n )\n }\n }\n }\n\n if (!this.metadata.response_types.includes(parameters.response_type)) {\n throw new AuthorizationError(\n parameters,\n `Invalid response_type \"${parameters.response_type}\" requested by the client`,\n )\n }\n\n if (parameters.response_type.includes('code')) {\n if (!this.metadata.grant_types.includes('authorization_code')) {\n throw new AuthorizationError(\n parameters,\n `This client is not allowed to use the \"authorization_code\" grant type`,\n )\n }\n }\n\n const { redirect_uri } = parameters\n if (redirect_uri) {\n if (\n !this.metadata.redirect_uris.some((uri) =>\n compareRedirectUri(uri, redirect_uri),\n )\n ) {\n throw new AuthorizationError(\n parameters,\n `Invalid redirect_uri ${redirect_uri}`,\n )\n }\n } else {\n const { defaultRedirectUri } = this\n if (defaultRedirectUri) {\n parameters = { ...parameters, redirect_uri: defaultRedirectUri }\n } else {\n // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10#authorization-request\n //\n // > \"redirect_uri\": OPTIONAL if only one redirect URI is registered for\n // > this client. REQUIRED if multiple redirect URIs are registered for this\n // > client.\n throw new AuthorizationError(parameters, 'redirect_uri is required')\n }\n }\n\n if (parameters.authorization_details) {\n const { authorization_details_types } = this.metadata\n if (!authorization_details_types) {\n throw new InvalidAuthorizationDetailsError(\n parameters,\n 'Client Metadata does not declare any \"authorization_details\"',\n )\n }\n\n for (const detail of parameters.authorization_details) {\n if (!authorization_details_types?.includes(detail.type)) {\n throw new InvalidAuthorizationDetailsError(\n parameters,\n `Client Metadata does not declare any \"authorization_details\" of type \"${detail.type}\"`,\n )\n }\n }\n }\n\n return parameters\n }\n\n get defaultRedirectUri(): OAuthRedirectUri | undefined {\n const { redirect_uris } = this.metadata\n return redirect_uris.length === 1 ? redirect_uris[0] : undefined\n }\n}\n\nexport async function authJwkThumbprint(\n key: Uint8Array | KeyLike,\n): Promise<string> {\n try {\n return await calculateJwkThumbprint(await exportJWK(key), 'sha512')\n } catch (err) {\n throw new InvalidClientError('Unable to compute JWK thumbprint', err)\n }\n}\n"]}