@atproto/oauth-provider 0.9.2 → 0.10.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 (154) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/client/client-manager.d.ts.map +1 -1
  3. package/dist/client/client-manager.js +0 -7
  4. package/dist/client/client-manager.js.map +1 -1
  5. package/dist/client/client.js +6 -6
  6. package/dist/client/client.js.map +1 -1
  7. package/dist/device/device-manager.js +1 -1
  8. package/dist/device/device-manager.js.map +1 -1
  9. package/dist/dpop/dpop-manager.js +15 -15
  10. package/dist/dpop/dpop-manager.js.map +1 -1
  11. package/dist/errors/access-denied-error.d.ts +4 -7
  12. package/dist/errors/access-denied-error.d.ts.map +1 -1
  13. package/dist/errors/access-denied-error.js +4 -13
  14. package/dist/errors/access-denied-error.js.map +1 -1
  15. package/dist/errors/account-selection-required-error.d.ts +2 -2
  16. package/dist/errors/account-selection-required-error.d.ts.map +1 -1
  17. package/dist/errors/account-selection-required-error.js +2 -2
  18. package/dist/errors/account-selection-required-error.js.map +1 -1
  19. package/dist/errors/authorization-error.d.ts +10 -0
  20. package/dist/errors/authorization-error.d.ts.map +1 -0
  21. package/dist/errors/authorization-error.js +31 -0
  22. package/dist/errors/authorization-error.js.map +1 -0
  23. package/dist/errors/consent-required-error.d.ts +2 -2
  24. package/dist/errors/consent-required-error.d.ts.map +1 -1
  25. package/dist/errors/consent-required-error.js +2 -2
  26. package/dist/errors/consent-required-error.js.map +1 -1
  27. package/dist/errors/error-parser.d.ts.map +1 -1
  28. package/dist/errors/error-parser.js +2 -1
  29. package/dist/errors/error-parser.js.map +1 -1
  30. package/dist/errors/invalid-authorization-details-error.d.ts +2 -2
  31. package/dist/errors/invalid-authorization-details-error.d.ts.map +1 -1
  32. package/dist/errors/invalid-authorization-details-error.js +2 -2
  33. package/dist/errors/invalid-authorization-details-error.js.map +1 -1
  34. package/dist/errors/invalid-scope-error.d.ts +2 -2
  35. package/dist/errors/invalid-scope-error.d.ts.map +1 -1
  36. package/dist/errors/invalid-scope-error.js +2 -2
  37. package/dist/errors/invalid-scope-error.js.map +1 -1
  38. package/dist/errors/login-required-error.d.ts +2 -3
  39. package/dist/errors/login-required-error.d.ts.map +1 -1
  40. package/dist/errors/login-required-error.js +2 -7
  41. package/dist/errors/login-required-error.js.map +1 -1
  42. package/dist/lib/http/response.d.ts +4 -4
  43. package/dist/lib/http/response.d.ts.map +1 -1
  44. package/dist/lib/http/response.js +8 -7
  45. package/dist/lib/http/response.js.map +1 -1
  46. package/dist/lib/http/stream.d.ts +1 -0
  47. package/dist/lib/http/stream.d.ts.map +1 -1
  48. package/dist/lib/http/stream.js +6 -0
  49. package/dist/lib/http/stream.js.map +1 -1
  50. package/dist/lib/util/error.d.ts +2 -0
  51. package/dist/lib/util/error.d.ts.map +1 -0
  52. package/dist/lib/util/error.js +11 -0
  53. package/dist/lib/util/error.js.map +1 -0
  54. package/dist/lib/util/zod-error.d.ts +3 -1
  55. package/dist/lib/util/zod-error.d.ts.map +1 -1
  56. package/dist/lib/util/zod-error.js +20 -10
  57. package/dist/lib/util/zod-error.js.map +1 -1
  58. package/dist/metadata/build-metadata.d.ts +0 -1
  59. package/dist/metadata/build-metadata.d.ts.map +1 -1
  60. package/dist/metadata/build-metadata.js +6 -2
  61. package/dist/metadata/build-metadata.js.map +1 -1
  62. package/dist/oauth-errors.d.ts +1 -1
  63. package/dist/oauth-errors.d.ts.map +1 -1
  64. package/dist/oauth-errors.js +1 -1
  65. package/dist/oauth-errors.js.map +1 -1
  66. package/dist/oauth-hooks.d.ts +17 -3
  67. package/dist/oauth-hooks.d.ts.map +1 -1
  68. package/dist/oauth-hooks.js +7 -4
  69. package/dist/oauth-hooks.js.map +1 -1
  70. package/dist/oauth-provider.d.ts +1 -0
  71. package/dist/oauth-provider.d.ts.map +1 -1
  72. package/dist/oauth-provider.js +35 -49
  73. package/dist/oauth-provider.js.map +1 -1
  74. package/dist/oauth-verifier.d.ts +2 -1
  75. package/dist/oauth-verifier.d.ts.map +1 -1
  76. package/dist/oauth-verifier.js.map +1 -1
  77. package/dist/request/request-manager.d.ts +5 -5
  78. package/dist/request/request-manager.d.ts.map +1 -1
  79. package/dist/request/request-manager.js +63 -45
  80. package/dist/request/request-manager.js.map +1 -1
  81. package/dist/request/request-store.d.ts +6 -6
  82. package/dist/request/request-store.d.ts.map +1 -1
  83. package/dist/result/authorization-result-authorize-page.d.ts +2 -3
  84. package/dist/result/authorization-result-authorize-page.d.ts.map +1 -1
  85. package/dist/router/assets/send-authorization-page.js +3 -2
  86. package/dist/router/assets/send-authorization-page.js.map +1 -1
  87. package/dist/router/create-api-middleware.d.ts.map +1 -1
  88. package/dist/router/create-api-middleware.js +68 -48
  89. package/dist/router/create-api-middleware.js.map +1 -1
  90. package/dist/router/create-authorization-page-middleware.d.ts.map +1 -1
  91. package/dist/router/create-authorization-page-middleware.js +19 -17
  92. package/dist/router/create-authorization-page-middleware.js.map +1 -1
  93. package/dist/router/create-oauth-middleware.d.ts.map +1 -1
  94. package/dist/router/create-oauth-middleware.js +21 -18
  95. package/dist/router/create-oauth-middleware.js.map +1 -1
  96. package/dist/router/send-redirect.js +2 -2
  97. package/dist/router/send-redirect.js.map +1 -1
  98. package/dist/token/token-manager.js +1 -1
  99. package/dist/token/verify-token-claims.d.ts +1 -0
  100. package/dist/token/verify-token-claims.d.ts.map +1 -1
  101. package/dist/token/verify-token-claims.js.map +1 -1
  102. package/dist/types/authorization-response-error.d.ts +5 -0
  103. package/dist/types/authorization-response-error.d.ts.map +1 -0
  104. package/dist/types/authorization-response-error.js +21 -0
  105. package/dist/types/authorization-response-error.js.map +1 -0
  106. package/dist/types/par-response-error.d.ts +5 -0
  107. package/dist/types/par-response-error.d.ts.map +1 -0
  108. package/dist/types/par-response-error.js +22 -0
  109. package/dist/types/par-response-error.js.map +1 -0
  110. package/package.json +7 -6
  111. package/src/client/client-manager.ts +0 -8
  112. package/src/client/client.ts +6 -6
  113. package/src/device/device-manager.ts +1 -1
  114. package/src/dpop/dpop-manager.ts +16 -16
  115. package/src/errors/access-denied-error.ts +6 -33
  116. package/src/errors/account-selection-required-error.ts +2 -2
  117. package/src/errors/authorization-error.ts +45 -0
  118. package/src/errors/consent-required-error.ts +2 -2
  119. package/src/errors/error-parser.ts +2 -1
  120. package/src/errors/invalid-authorization-details-error.ts +2 -2
  121. package/src/errors/invalid-scope-error.ts +2 -2
  122. package/src/errors/login-required-error.ts +2 -12
  123. package/src/lib/http/response.ts +14 -13
  124. package/src/lib/http/stream.ts +6 -0
  125. package/src/lib/util/error.ts +7 -0
  126. package/src/lib/util/zod-error.ts +23 -11
  127. package/src/metadata/build-metadata.ts +8 -3
  128. package/src/oauth-errors.ts +1 -1
  129. package/src/oauth-hooks.ts +18 -2
  130. package/src/oauth-provider.ts +37 -58
  131. package/src/oauth-verifier.ts +3 -1
  132. package/src/request/request-manager.ts +76 -55
  133. package/src/request/request-store.ts +6 -6
  134. package/src/result/authorization-result-authorize-page.ts +2 -3
  135. package/src/router/assets/send-authorization-page.ts +3 -3
  136. package/src/router/create-api-middleware.ts +92 -64
  137. package/src/router/create-authorization-page-middleware.ts +19 -21
  138. package/src/router/create-oauth-middleware.ts +28 -27
  139. package/src/router/send-redirect.ts +2 -2
  140. package/src/token/token-manager.ts +1 -1
  141. package/src/token/verify-token-claims.ts +8 -0
  142. package/src/types/authorization-response-error.ts +27 -0
  143. package/src/types/par-response-error.ts +25 -0
  144. package/tsconfig.build.tsbuildinfo +1 -1
  145. package/dist/errors/invalid-parameters-error.d.ts +0 -6
  146. package/dist/errors/invalid-parameters-error.d.ts.map +0 -1
  147. package/dist/errors/invalid-parameters-error.js +0 -11
  148. package/dist/errors/invalid-parameters-error.js.map +0 -1
  149. package/dist/request/request-info.d.ts +0 -14
  150. package/dist/request/request-info.d.ts.map +0 -1
  151. package/dist/request/request-info.js +0 -3
  152. package/dist/request/request-info.js.map +0 -1
  153. package/src/errors/invalid-parameters-error.ts +0 -12
  154. package/src/request/request-info.ts +0 -14
@@ -1,14 +1,26 @@
1
- import { ZodError } from 'zod'
2
-
3
- export function extractZodErrorMessage(err: unknown): string | undefined {
4
- if (err instanceof ZodError) {
5
- const issue = err.issues[0]
6
- if (issue?.path.length) {
7
- // "part" will typically be "body" or "query"
8
- const [part, ...path] = issue.path
9
- return `Validation of "${path.join('.')}" ${part} parameter failed: ${issue.message}`
10
- }
1
+ import { ZodError, ZodIssue, ZodIssueCode } from 'zod'
2
+
3
+ export function formatZodError(err: ZodError, prefix?: string): string {
4
+ const message = err.issues.length
5
+ ? err.issues.map(formatZodIssue).join('; ')
6
+ : err.message // Should never happen (issues should never be empty)
7
+ return prefix ? `${prefix}: ${message}` : message
8
+ }
9
+
10
+ export function formatZodIssue(issue: ZodIssue): string {
11
+ if (issue.code === ZodIssueCode.invalid_union) {
12
+ return issue.unionErrors
13
+ .map((err) => err.issues.map(formatZodIssue).join('; '))
14
+ .join(', or ')
15
+ }
16
+
17
+ if (issue.path.length === 1 && typeof issue.path[0] === 'number') {
18
+ return `${issue.message} at index ${issue.path[0]}`
19
+ }
20
+
21
+ if (issue.path.length) {
22
+ return `${issue.message} at ${issue.path.join('.')}`
11
23
  }
12
24
 
13
- return undefined
25
+ return issue.message
14
26
  }
@@ -8,7 +8,6 @@ import { Client } from '../client/client.js'
8
8
  import { VERIFY_ALGOS } from '../lib/util/crypto.js'
9
9
 
10
10
  export type CustomMetadata = {
11
- scopes_supported?: string[]
12
11
  authorization_details_types_supported?: string[]
13
12
  protected_resources?: string[]
14
13
  }
@@ -27,8 +26,14 @@ export function buildMetadata(
27
26
 
28
27
  scopes_supported: [
29
28
  'atproto',
30
- //
31
- ...(customMetadata?.scopes_supported ?? []),
29
+
30
+ // These serve as hint that this server supports the transitional scopes.
31
+ // This is not a specced behavior.
32
+ 'transition:email',
33
+ 'transition:generic',
34
+ 'transition:chat.bsky',
35
+
36
+ // Other atproto scopes can't be enumerated as they are dynamic.
32
37
  ],
33
38
  subject_types_supported: [
34
39
  //
@@ -3,6 +3,7 @@ export { OAuthError } from './errors/oauth-error.js'
3
3
 
4
4
  export * from './errors/access-denied-error.js'
5
5
  export * from './errors/account-selection-required-error.js'
6
+ export * from './errors/authorization-error.js'
6
7
  export * from './errors/consent-required-error.js'
7
8
  export * from './errors/handle-unavailable-error.js'
8
9
  export * from './errors/invalid-authorization-details-error.js'
@@ -13,7 +14,6 @@ export * from './errors/invalid-dpop-key-binding-error.js'
13
14
  export * from './errors/invalid-dpop-proof-error.js'
14
15
  export * from './errors/invalid-grant-error.js'
15
16
  export * from './errors/invalid-invite-code-error.js'
16
- export * from './errors/invalid-parameters-error.js'
17
17
  export * from './errors/invalid-redirect-uri-error.js'
18
18
  export * from './errors/invalid-request-error.js'
19
19
  export * from './errors/invalid-scope-error.js'
@@ -12,7 +12,10 @@ import { ClientAuth } from './client/client-auth.js'
12
12
  import { ClientId } from './client/client-id.js'
13
13
  import { ClientInfo } from './client/client-info.js'
14
14
  import { Client } from './client/client.js'
15
+ import { AccessDeniedError } from './errors/access-denied-error.js'
16
+ import { AuthorizationError } from './errors/authorization-error.js'
15
17
  import { InvalidRequestError } from './errors/invalid-request-error.js'
18
+ import { OAuthError } from './errors/oauth-error.js'
16
19
  import {
17
20
  HcaptchaClientTokens,
18
21
  HcaptchaConfig,
@@ -20,7 +23,6 @@ import {
20
23
  } from './lib/hcaptcha.js'
21
24
  import { RequestMetadata } from './lib/http/request.js'
22
25
  import { Awaitable } from './lib/util/type.js'
23
- import { AccessDeniedError, OAuthError } from './oauth-errors.js'
24
26
  import { DeviceId, SignUpData } from './oauth-store.js'
25
27
  import { RequestId } from './request/request-id.js'
26
28
 
@@ -28,6 +30,7 @@ import { RequestId } from './request/request-id.js'
28
30
  export {
29
31
  AccessDeniedError,
30
32
  type Account,
33
+ AuthorizationError,
31
34
  type Awaitable,
32
35
  Client,
33
36
  type ClientAuth,
@@ -115,10 +118,23 @@ export type OAuthHooks = {
115
118
  deviceMetadata: RequestMetadata
116
119
  }) => Awaitable<void>
117
120
 
121
+ /**
122
+ * Allows validating an authorization request (typically the requested scopes)
123
+ * before it is created. Note that the validity against the client metadata is
124
+ * already enforced by the OAuth provider.
125
+ *
126
+ * @throws {AuthorizationError}
127
+ */
128
+ onAuthorizationRequest?: (data: {
129
+ client: Client
130
+ clientAuth: null | ClientAuth
131
+ parameters: Readonly<OAuthAuthorizationRequestParameters>
132
+ }) => Awaitable<void>
133
+
118
134
  /**
119
135
  * This hook is called when a client is authorized.
120
136
  *
121
- * @throws {AccessDeniedError} to deny the authorization request and redirect
137
+ * @throws {AuthorizationError} to deny the authorization request and redirect
122
138
  * the user to the client with an OAuth error (other errors will result in an
123
139
  * internal server error being displayed to the user)
124
140
  *
@@ -1,6 +1,5 @@
1
1
  import { createHash } from 'node:crypto'
2
2
  import type { Redis, RedisOptions } from 'ioredis'
3
- import { ZodError } from 'zod'
4
3
  import { Jwks, Keyset } from '@atproto/jwk'
5
4
  import type { Account } from '@atproto/oauth-provider-api'
6
5
  import {
@@ -64,8 +63,8 @@ import {
64
63
  deviceManagerOptionsSchema,
65
64
  } from './device/device-manager.js'
66
65
  import { DeviceStore, asDeviceStore } from './device/device-store.js'
67
- import { AccessDeniedError } from './errors/access-denied-error.js'
68
66
  import { AccountSelectionRequiredError } from './errors/account-selection-required-error.js'
67
+ import { AuthorizationError } from './errors/authorization-error.js'
69
68
  import { ConsentRequiredError } from './errors/consent-required-error.js'
70
69
  import { InvalidDpopKeyBindingError } from './errors/invalid-dpop-key-binding-error.js'
71
70
  import { InvalidDpopProofError } from './errors/invalid-dpop-proof-error.js'
@@ -75,8 +74,8 @@ import { LoginRequiredError } from './errors/login-required-error.js'
75
74
  import { HcaptchaConfig } from './lib/hcaptcha.js'
76
75
  import { RequestMetadata } from './lib/http/request.js'
77
76
  import { dateToRelativeSeconds } from './lib/util/date.js'
77
+ import { formatError } from './lib/util/error.js'
78
78
  import { LocalizedString, MultiLangString } from './lib/util/locale.js'
79
- import { extractZodErrorMessage } from './lib/util/zod-error.js'
80
79
  import { CustomMetadata, buildMetadata } from './metadata/build-metadata.js'
81
80
  import { OAuthHooks } from './oauth-hooks.js'
82
81
  import {
@@ -104,6 +103,7 @@ import {
104
103
  VerifyTokenClaimsOptions,
105
104
  VerifyTokenClaimsResult,
106
105
  } from './token/verify-token-claims.js'
106
+ import { isPARResponseError } from './types/par-response-error.js'
107
107
 
108
108
  export { AccessTokenMode, Keyset }
109
109
  export type {
@@ -233,6 +233,7 @@ export type OAuthProviderOptions = OAuthProviderConfig &
233
233
 
234
234
  export class OAuthProvider extends OAuthVerifier {
235
235
  protected readonly accessTokenMode: AccessTokenMode
236
+ protected readonly hooks: OAuthHooks
236
237
 
237
238
  public readonly metadata: OAuthAuthorizationServerMetadata
238
239
  public readonly customization: Customization
@@ -286,21 +287,19 @@ export class OAuthProvider extends OAuthVerifier {
286
287
  const deviceManagerOptions: DeviceManagerOptions =
287
288
  deviceManagerOptionsSchema.parse(rest)
288
289
 
289
- // @NOTE: hooks don't really need a type parser, as all zod can actually
290
- // check at runtime is the fact that the values are functions. The only way
291
- // we would benefit from zod here would be to wrap the functions with a
292
- // validator for the provided function's return types, which we do not add
293
- // because it would impact runtime performance and we trust the users of
294
- // this lib (basically ourselves) to rely on the typing system to ensure the
295
- // correct types are returned.
296
- const hooks: OAuthHooks = rest
297
-
298
290
  // @NOTE: validation of super params (if we wanted to implement it) should
299
291
  // be the responsibility of the super class.
300
292
  const superOptions: OAuthVerifierOptions = rest
301
293
 
302
294
  super({ replayStore, ...superOptions })
303
295
 
296
+ // @NOTE: hooks don't really need a type parser, as all zod can actually
297
+ // check at runtime is the fact that the values are functions. The only way
298
+ // we would benefit from zod here would be to wrap the functions with a
299
+ // validator for the provided function's return types, which we don't
300
+ // really need if types are respected.
301
+ this.hooks = rest
302
+
304
303
  this.accessTokenMode = accessTokenMode
305
304
  this.authenticationMaxAge = authenticationMaxAge
306
305
  this.metadata = buildMetadata(this.issuer, this.keyset, metadata)
@@ -310,13 +309,13 @@ export class OAuthProvider extends OAuthVerifier {
310
309
  this.accountManager = new AccountManager(
311
310
  this.issuer,
312
311
  accountStore,
313
- hooks,
312
+ this.hooks,
314
313
  this.customization,
315
314
  )
316
315
  this.clientManager = new ClientManager(
317
316
  this.metadata,
318
317
  this.keyset,
319
- hooks,
318
+ this.hooks,
320
319
  clientStore || null,
321
320
  loopbackMetadata || null,
322
321
  safeFetch,
@@ -327,12 +326,12 @@ export class OAuthProvider extends OAuthVerifier {
327
326
  requestStore,
328
327
  this.signer,
329
328
  this.metadata,
330
- hooks,
329
+ this.hooks,
331
330
  )
332
331
  this.tokenManager = new TokenManager(
333
332
  tokenStore,
334
333
  this.signer,
335
- hooks,
334
+ this.hooks,
336
335
  this.accessTokenMode,
337
336
  tokenMaxAge,
338
337
  )
@@ -448,11 +447,8 @@ export class OAuthProvider extends OAuthVerifier {
448
447
  const parameters = await oauthAuthorizationRequestParametersSchema
449
448
  .parseAsync(payload)
450
449
  .catch((err) => {
451
- const message =
452
- err instanceof ZodError
453
- ? `Invalid request parameters: ${err.message}`
454
- : `Invalid "request" object`
455
- throw InvalidRequestError.from(err, message)
450
+ const msg = formatError(err, 'Invalid parameters in JAR')
451
+ throw new InvalidRequestError(msg, err)
456
452
  })
457
453
 
458
454
  return parameters
@@ -505,7 +501,7 @@ export class OAuthProvider extends OAuthVerifier {
505
501
  }
506
502
  }
507
503
 
508
- const { uri, expiresAt } =
504
+ const { requestUri, expiresAt } =
509
505
  await this.requestManager.createAuthorizationRequest(
510
506
  client,
511
507
  clientAuth,
@@ -514,7 +510,7 @@ export class OAuthProvider extends OAuthVerifier {
514
510
  )
515
511
 
516
512
  return {
517
- request_uri: uri,
513
+ request_uri: requestUri,
518
514
  expires_in: dateToRelativeSeconds(expiresAt),
519
515
  }
520
516
  } catch (err) {
@@ -522,7 +518,7 @@ export class OAuthProvider extends OAuthVerifier {
522
518
  // > Since initial processing of the pushed authorization request does not
523
519
  // > involve resource owner interaction, error codes related to user
524
520
  // > interaction, such as "access_denied", are never returned.
525
- if (err instanceof AccessDeniedError) {
521
+ if (err instanceof AuthorizationError && !isPARResponseError(err.error)) {
526
522
  throw new InvalidRequestError(err.error_description, err)
527
523
  }
528
524
  throw err
@@ -539,10 +535,8 @@ export class OAuthProvider extends OAuthVerifier {
539
535
  const requestUri = await requestUriSchema
540
536
  .parseAsync(query.request_uri, { path: ['query', 'request_uri'] })
541
537
  .catch((err) => {
542
- throw new InvalidRequestError(
543
- extractZodErrorMessage(err) ?? 'Input validation error',
544
- err,
545
- )
538
+ const msg = formatError(err, 'Invalid "request_uri" query parameter')
539
+ throw new InvalidRequestError(msg, err)
546
540
  })
547
541
 
548
542
  return this.requestManager.get(requestUri, deviceId, client.id)
@@ -592,24 +586,24 @@ export class OAuthProvider extends OAuthVerifier {
592
586
  const { issuer } = this
593
587
 
594
588
  // If there is a chance to redirect the user to the client, let's do
595
- // it by wrapping the error in an AccessDeniedError.
596
- const accessDeniedCatcher =
589
+ // it by wrapping the error in an AuthorizationError.
590
+ const throwAuthorizationError =
597
591
  'redirect_uri' in query
598
592
  ? (err: unknown): never => {
599
593
  // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-4.1.2.1
600
- throw AccessDeniedError.from(query, err, 'invalid_request')
594
+ throw AuthorizationError.from(query, err)
601
595
  }
602
596
  : null
603
597
 
604
598
  const client = await this.clientManager
605
599
  .getClient(clientCredentials.client_id)
606
- .catch(accessDeniedCatcher)
600
+ .catch(throwAuthorizationError)
607
601
 
608
- const { parameters, uri } = await this.processAuthorizationRequest(
602
+ const { parameters, requestUri } = await this.processAuthorizationRequest(
609
603
  client,
610
604
  deviceId,
611
605
  query,
612
- ).catch(accessDeniedCatcher)
606
+ ).catch(throwAuthorizationError)
613
607
 
614
608
  try {
615
609
  const sessions = await this.getSessions(client.id, deviceId, parameters)
@@ -632,7 +626,7 @@ export class OAuthProvider extends OAuthVerifier {
632
626
  }
633
627
 
634
628
  const code = await this.requestManager.setAuthorized(
635
- uri,
629
+ requestUri,
636
630
  client,
637
631
  ssoSession.account,
638
632
  deviceId,
@@ -649,7 +643,7 @@ export class OAuthProvider extends OAuthVerifier {
649
643
  const ssoSession = ssoSessions[0]!
650
644
  if (!ssoSession.loginRequired && !ssoSession.consentRequired) {
651
645
  const code = await this.requestManager.setAuthorized(
652
- uri,
646
+ requestUri,
653
647
  client,
654
648
  ssoSession.account,
655
649
  deviceId,
@@ -665,7 +659,7 @@ export class OAuthProvider extends OAuthVerifier {
665
659
  issuer,
666
660
  client,
667
661
  parameters,
668
- uri,
662
+ requestUri,
669
663
  sessions: sessions.map((session) => ({
670
664
  // Map to avoid leaking other data that might be present in the session
671
665
  account: session.account,
@@ -673,20 +667,10 @@ export class OAuthProvider extends OAuthVerifier {
673
667
  loginRequired: session.loginRequired,
674
668
  consentRequired: session.consentRequired,
675
669
  })),
676
- scopeDetails: parameters.scope
677
- ?.split(/\s+/)
678
- .filter(Boolean)
679
- .sort((a, b) => a.localeCompare(b))
680
- .map((scope) => ({
681
- scope,
682
- // @TODO Allow to customize the scope descriptions (e.g.
683
- // using a hook)
684
- description: undefined,
685
- })),
686
670
  }
687
671
  } catch (err) {
688
672
  try {
689
- await this.requestManager.delete(uri)
673
+ await this.requestManager.delete(requestUri)
690
674
  } catch {
691
675
  // There are two error here. Better keep the outer one.
692
676
  //
@@ -694,9 +678,7 @@ export class OAuthProvider extends OAuthVerifier {
694
678
  // (allowing to log this error)
695
679
  }
696
680
 
697
- // Not using accessDeniedCatcher here because "parameters" will most
698
- // likely contain the redirect_uri (using the client default).
699
- throw AccessDeniedError.from(parameters, err, 'server_error')
681
+ throw AuthorizationError.from(parameters, err)
700
682
  }
701
683
  }
702
684
 
@@ -872,12 +854,8 @@ export class OAuthProvider extends OAuthVerifier {
872
854
  const code = await codeSchema
873
855
  .parseAsync(input.code, { path: ['code'] })
874
856
  .catch((err) => {
875
- throw InvalidGrantError.from(
876
- err,
877
- err instanceof ZodError
878
- ? `Invalid code: ${err.message}`
879
- : `Invalid code`,
880
- )
857
+ const msg = formatError(err, 'Invalid code')
858
+ throw new InvalidGrantError(msg, err)
881
859
  })
882
860
 
883
861
  const data = await this.requestManager
@@ -999,7 +977,8 @@ export class OAuthProvider extends OAuthVerifier {
999
977
  const refreshToken = await refreshTokenSchema
1000
978
  .parseAsync(input.refresh_token, { path: ['refresh_token'] })
1001
979
  .catch((err) => {
1002
- throw InvalidGrantError.from(err, `Invalid refresh token`)
980
+ const msg = formatError(err, 'Invalid refresh token')
981
+ throw new InvalidGrantError(msg, err)
1003
982
  })
1004
983
 
1005
984
  const tokenInfo = await this.tokenManager.consumeRefreshToken(refreshToken)
@@ -26,6 +26,8 @@ import {
26
26
  verifyTokenClaims,
27
27
  } from './token/verify-token-claims.js'
28
28
 
29
+ export type * from './token/verify-token-claims.js'
30
+
29
31
  export type OAuthVerifierOptions = Override<
30
32
  DpopManagerOptions,
31
33
  {
@@ -51,7 +53,7 @@ export type OAuthVerifierOptions = Override<
51
53
  >
52
54
 
53
55
  export { DpopNonce, Key, Keyset }
54
- export type { DpopProof, RedisOptions, ReplayStore, VerifyTokenClaimsOptions }
56
+ export type { DpopProof, RedisOptions, ReplayStore }
55
57
 
56
58
  export class OAuthVerifier {
57
59
  public readonly issuer: OAuthIssuerIdentifier