@atproto/oauth-provider 0.1.3 → 0.2.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 (121) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/account/account.d.ts +6 -2
  3. package/dist/account/account.d.ts.map +1 -1
  4. package/dist/assets/app/bundle-manifest.json +3 -3
  5. package/dist/assets/app/main.css +1 -1
  6. package/dist/assets/app/main.js +1 -1
  7. package/dist/assets/app/main.js.map +1 -1
  8. package/dist/assets/assets-middleware.d.ts +2 -1
  9. package/dist/assets/assets-middleware.d.ts.map +1 -1
  10. package/dist/assets/assets-middleware.js +7 -0
  11. package/dist/assets/assets-middleware.js.map +1 -1
  12. package/dist/client/client-manager.d.ts +4 -3
  13. package/dist/client/client-manager.d.ts.map +1 -1
  14. package/dist/client/client-manager.js +60 -37
  15. package/dist/client/client-manager.js.map +1 -1
  16. package/dist/client/client.d.ts.map +1 -1
  17. package/dist/client/client.js +1 -3
  18. package/dist/client/client.js.map +1 -1
  19. package/dist/constants.d.ts +2 -0
  20. package/dist/constants.d.ts.map +1 -1
  21. package/dist/constants.js +3 -1
  22. package/dist/constants.js.map +1 -1
  23. package/dist/device/device-manager.d.ts +1 -1
  24. package/dist/device/device-manager.d.ts.map +1 -1
  25. package/dist/device/device-manager.js +2 -2
  26. package/dist/device/device-manager.js.map +1 -1
  27. package/dist/errors/invalid-authorization-details-error.d.ts +4 -3
  28. package/dist/errors/invalid-authorization-details-error.d.ts.map +1 -1
  29. package/dist/errors/invalid-authorization-details-error.js +4 -4
  30. package/dist/errors/invalid-authorization-details-error.js.map +1 -1
  31. package/dist/lib/http/request.d.ts +3 -0
  32. package/dist/lib/http/request.d.ts.map +1 -1
  33. package/dist/lib/http/request.js +24 -12
  34. package/dist/lib/http/request.js.map +1 -1
  35. package/dist/metadata/build-metadata.d.ts +0 -1
  36. package/dist/metadata/build-metadata.d.ts.map +1 -1
  37. package/dist/metadata/build-metadata.js +9 -35
  38. package/dist/metadata/build-metadata.js.map +1 -1
  39. package/dist/oauth-hooks.d.ts +3 -10
  40. package/dist/oauth-hooks.d.ts.map +1 -1
  41. package/dist/oauth-provider.d.ts +8 -13
  42. package/dist/oauth-provider.d.ts.map +1 -1
  43. package/dist/oauth-provider.js +169 -109
  44. package/dist/oauth-provider.js.map +1 -1
  45. package/dist/oauth-verifier.d.ts +1 -2
  46. package/dist/oauth-verifier.d.ts.map +1 -1
  47. package/dist/oauth-verifier.js.map +1 -1
  48. package/dist/output/build-authorize-data.d.ts +6 -0
  49. package/dist/output/build-authorize-data.d.ts.map +1 -1
  50. package/dist/output/build-authorize-data.js +1 -0
  51. package/dist/output/build-authorize-data.js.map +1 -1
  52. package/dist/replay/replay-manager.d.ts +1 -0
  53. package/dist/replay/replay-manager.d.ts.map +1 -1
  54. package/dist/replay/replay-manager.js +3 -0
  55. package/dist/replay/replay-manager.js.map +1 -1
  56. package/dist/replay/replay-store.d.ts +1 -1
  57. package/dist/request/request-info.d.ts +2 -0
  58. package/dist/request/request-info.d.ts.map +1 -1
  59. package/dist/request/request-manager.d.ts +3 -9
  60. package/dist/request/request-manager.d.ts.map +1 -1
  61. package/dist/request/request-manager.js +52 -77
  62. package/dist/request/request-manager.js.map +1 -1
  63. package/dist/request/types.d.ts +10 -10
  64. package/dist/signer/signed-token-payload.d.ts +85 -85
  65. package/dist/signer/signer.d.ts +23 -30
  66. package/dist/signer/signer.d.ts.map +1 -1
  67. package/dist/signer/signer.js +0 -40
  68. package/dist/signer/signer.js.map +1 -1
  69. package/dist/token/token-claims.d.ts +81 -81
  70. package/dist/token/token-manager.d.ts +1 -2
  71. package/dist/token/token-manager.d.ts.map +1 -1
  72. package/dist/token/token-manager.js +10 -37
  73. package/dist/token/token-manager.js.map +1 -1
  74. package/dist/token/types.d.ts +10 -10
  75. package/package.json +2 -3
  76. package/src/account/account.ts +11 -7
  77. package/src/assets/app/backend-data.ts +9 -2
  78. package/src/assets/app/components/accept-form.tsx +65 -51
  79. package/src/assets/app/components/client-name.tsx +24 -16
  80. package/src/assets/app/components/url-viewer.tsx +3 -3
  81. package/src/assets/app/views/accept-view.tsx +7 -4
  82. package/src/assets/app/views/authorize-view.tsx +2 -1
  83. package/src/assets/assets-middleware.ts +14 -2
  84. package/src/client/client-manager.ts +78 -60
  85. package/src/client/client.ts +1 -4
  86. package/src/constants.ts +3 -0
  87. package/src/device/device-manager.ts +7 -1
  88. package/src/errors/invalid-authorization-details-error.ts +9 -4
  89. package/src/lib/http/request.ts +61 -15
  90. package/src/metadata/build-metadata.ts +9 -42
  91. package/src/oauth-hooks.ts +3 -13
  92. package/src/oauth-provider.ts +181 -159
  93. package/src/oauth-verifier.ts +1 -2
  94. package/src/output/build-authorize-data.ts +8 -0
  95. package/src/replay/replay-manager.ts +9 -0
  96. package/src/replay/replay-store.ts +1 -1
  97. package/src/request/request-info.ts +2 -0
  98. package/src/request/request-manager.ts +81 -107
  99. package/src/signer/signer.ts +0 -63
  100. package/src/token/token-manager.ts +8 -41
  101. package/dist/oidc/claims.d.ts +0 -16
  102. package/dist/oidc/claims.d.ts.map +0 -1
  103. package/dist/oidc/claims.js +0 -29
  104. package/dist/oidc/claims.js.map +0 -1
  105. package/dist/oidc/userinfo.d.ts +0 -7
  106. package/dist/oidc/userinfo.d.ts.map +0 -1
  107. package/dist/oidc/userinfo.js +0 -3
  108. package/dist/oidc/userinfo.js.map +0 -1
  109. package/dist/parameters/claims-requested.d.ts +0 -3
  110. package/dist/parameters/claims-requested.d.ts.map +0 -1
  111. package/dist/parameters/claims-requested.js +0 -77
  112. package/dist/parameters/claims-requested.js.map +0 -1
  113. package/dist/parameters/oidc-payload.d.ts +0 -31
  114. package/dist/parameters/oidc-payload.d.ts.map +0 -1
  115. package/dist/parameters/oidc-payload.js +0 -25
  116. package/dist/parameters/oidc-payload.js.map +0 -1
  117. package/src/assets/app/components/client-identifier.tsx +0 -31
  118. package/src/oidc/claims.ts +0 -35
  119. package/src/oidc/userinfo.ts +0 -11
  120. package/src/parameters/claims-requested.ts +0 -106
  121. package/src/parameters/oidc-payload.ts +0 -28
@@ -17,6 +17,7 @@ import {
17
17
  isLoopbackUrl,
18
18
  isOAuthClientIdDiscoverable,
19
19
  isOAuthClientIdLoopback,
20
+ OAuthAuthorizationServerMetadata,
20
21
  OAuthClientIdDiscoverable,
21
22
  OAuthClientIdLoopback,
22
23
  OAuthClientMetadata,
@@ -55,9 +56,10 @@ export type LoopbackMetadataGetter = (
55
56
 
56
57
  export class ClientManager {
57
58
  protected readonly jwks: CachedGetter<string, Jwks>
58
- protected readonly metadata: CachedGetter<string, OAuthClientMetadata>
59
+ protected readonly metadataGetter: CachedGetter<string, OAuthClientMetadata>
59
60
 
60
61
  constructor(
62
+ protected readonly serverMetadata: OAuthAuthorizationServerMetadata,
61
63
  protected readonly keyset: Keyset,
62
64
  protected readonly hooks: OAuthHooks,
63
65
  protected readonly store: ClientStore | null,
@@ -76,7 +78,7 @@ export class ClientManager {
76
78
  return jwks
77
79
  }, clientJwksCache)
78
80
 
79
- this.metadata = new CachedGetter(async (uri, options) => {
81
+ this.metadataGetter = new CachedGetter(async (uri, options) => {
80
82
  const metadata = await fetch(buildJsonGetRequest(uri, options)).then(
81
83
  fetchMetadataHandler,
82
84
  )
@@ -159,7 +161,7 @@ export class ClientManager {
159
161
  ): Promise<OAuthClientMetadata> {
160
162
  const metadataUrl = parseDiscoverableClientId(clientId)
161
163
 
162
- const metadata = await this.metadata.get(metadataUrl.href)
164
+ const metadata = await this.metadataGetter.get(metadataUrl.href)
163
165
 
164
166
  // Note: we do *not* re-validate the metadata here, as the metadata is
165
167
  // validated within the getter. This is to avoid double validation.
@@ -195,6 +197,18 @@ export class ClientManager {
195
197
  )
196
198
  }
197
199
 
200
+ // Known OIDC specific parameters
201
+ for (const k of [
202
+ 'default_max_age',
203
+ 'userinfo_signed_response_alg',
204
+ 'id_token_signed_response_alg',
205
+ 'userinfo_encrypted_response_alg',
206
+ ] as const) {
207
+ if (metadata[k] != null) {
208
+ throw new InvalidClientMetadataError(`Unsupported "${k}" parameter`)
209
+ }
210
+ }
211
+
198
212
  const clientUriUrl = metadata.client_uri
199
213
  ? new URL(metadata.client_uri)
200
214
  : null
@@ -204,13 +218,27 @@ export class ClientManager {
204
218
  throw new InvalidClientMetadataError('client_uri must be a valid URL')
205
219
  }
206
220
 
207
- const scopes = metadata.scope?.split(' ')
208
- if (
209
- metadata.grant_types.includes('refresh_token') !==
210
- (scopes?.includes('offline_access') ?? false)
211
- ) {
221
+ const scopes = metadata.scope?.split(' ').filter(Boolean)
222
+
223
+ const dupScope = scopes?.find(isDuplicate)
224
+ if (dupScope) {
225
+ throw new InvalidClientMetadataError(`Duplicate scope "${dupScope}"`)
226
+ }
227
+
228
+ if (scopes) {
229
+ for (const scope of scopes) {
230
+ // Note, once we have dynamic scopes, this check will need to be
231
+ // updated to check against the server's supported scopes.
232
+ if (!this.serverMetadata.scopes_supported?.includes(scope)) {
233
+ throw new InvalidClientMetadataError(`Unsupported scope "${scope}"`)
234
+ }
235
+ }
236
+ }
237
+
238
+ const dupGrantType = metadata.grant_types.find(isDuplicate)
239
+ if (dupGrantType) {
212
240
  throw new InvalidClientMetadataError(
213
- 'Grant type "refresh_token" requires scope "offline_access" (and vice versa)',
241
+ `Duplicate grant type "${dupGrantType}"`,
214
242
  )
215
243
  }
216
244
 
@@ -218,8 +246,8 @@ export class ClientManager {
218
246
  switch (grantType) {
219
247
  case 'authorization_code':
220
248
  case 'refresh_token':
221
- case 'implicit': // Required by OIDC (for id_token)
222
249
  continue
250
+ case 'implicit':
223
251
  case 'password':
224
252
  throw new InvalidClientMetadataError(
225
253
  `Grant type "${grantType}" is not allowed`,
@@ -241,35 +269,6 @@ export class ClientManager {
241
269
  )
242
270
  }
243
271
 
244
- if (
245
- metadata.userinfo_signed_response_alg &&
246
- !this.keyset.signAlgorithms.includes(
247
- metadata.userinfo_signed_response_alg,
248
- )
249
- ) {
250
- throw new InvalidClientMetadataError(
251
- `Unsupported "userinfo_signed_response_alg" ${metadata.userinfo_signed_response_alg}`,
252
- )
253
- }
254
-
255
- if (
256
- metadata.id_token_signed_response_alg &&
257
- !this.keyset.signAlgorithms.includes(
258
- metadata.id_token_signed_response_alg,
259
- )
260
- ) {
261
- throw new InvalidClientMetadataError(
262
- `Unsupported "id_token_signed_response_alg" ${metadata.id_token_signed_response_alg}`,
263
- )
264
- }
265
-
266
- if (metadata.userinfo_encrypted_response_alg) {
267
- // We only support signature for now.
268
- throw new InvalidClientMetadataError(
269
- 'Encrypted userinfo response is not supported',
270
- )
271
- }
272
-
273
272
  const method = metadata[`token_endpoint_auth_method`]
274
273
  switch (method) {
275
274
  case undefined:
@@ -338,37 +337,28 @@ export class ClientManager {
338
337
  }
339
338
 
340
339
  for (const responseType of metadata.response_types) {
341
- const rt = responseType.split(' ')
340
+ if (responseType.includes('id_token')) {
341
+ throw new InvalidClientMetadataError(
342
+ `OpenID Connect response type "${responseType}" is not supported`,
343
+ )
344
+ }
342
345
 
343
346
  // ATPROTO spec requires the use of PKCE
344
- if (rt.includes('token')) {
347
+ if (responseType !== 'code') {
345
348
  throw new InvalidClientMetadataError(
346
- '"token" response type is not compatible with PKCE (use "code" instead)',
349
+ `Unsupported response type "${responseType}"`,
347
350
  )
348
351
  }
349
352
 
350
353
  // Consistency check
351
354
  if (
352
- rt.includes('code') &&
355
+ responseType === 'code' &&
353
356
  !metadata.grant_types.includes('authorization_code')
354
357
  ) {
355
358
  throw new InvalidClientMetadataError(
356
359
  `Response type "${responseType}" requires the "authorization_code" grant type`,
357
360
  )
358
361
  }
359
-
360
- // Asking for "code token" or "code id_token" is fine (as long as the
361
- // grant_types includes "authorization_code" and the scope includes
362
- // "openid"). Asking for "token" or "id_token" (without "code") requires
363
- // the "implicit" grant type.
364
- if (
365
- (rt.includes('token') || rt.includes('id_token')) &&
366
- !metadata.grant_types.includes('implicit')
367
- ) {
368
- throw new InvalidClientMetadataError(
369
- `Response type "${responseType}" requires the "implicit" grant type`,
370
- )
371
- }
372
362
  }
373
363
 
374
364
  if (metadata.application_type === 'native') {
@@ -383,11 +373,33 @@ export class ClientManager {
383
373
  // > accordingly.
384
374
  }
385
375
 
376
+ if (metadata.authorization_details_types?.length) {
377
+ const dupAuthDetailsType =
378
+ metadata.authorization_details_types.find(isDuplicate)
379
+ if (dupAuthDetailsType) {
380
+ throw new InvalidClientMetadataError(
381
+ `Duplicate authorization_details_type "${dupAuthDetailsType}"`,
382
+ )
383
+ }
384
+
385
+ const authorizationDetailsTypesSupported =
386
+ this.serverMetadata.authorization_details_types_supported
387
+ if (!authorizationDetailsTypesSupported) {
388
+ throw new InvalidClientMetadataError(
389
+ 'authorization_details_types are not supported',
390
+ )
391
+ }
392
+ for (const type of metadata.authorization_details_types) {
393
+ if (!authorizationDetailsTypesSupported.includes(type)) {
394
+ throw new InvalidClientMetadataError(
395
+ `Unsupported authorization_details_type "${type}"`,
396
+ )
397
+ }
398
+ }
399
+ }
400
+
386
401
  if (!metadata.redirect_uris?.length) {
387
- // https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2
388
- //
389
- // > OPs can require that request_uri values used be pre-registered with
390
- // > the require_request_uri_registration discovery parameter.
402
+ // ATPROTO spec requires that at least one redirect URI is provided
391
403
 
392
404
  throw new InvalidClientMetadataError(
393
405
  'At least one redirect_uri is required',
@@ -786,6 +798,12 @@ export class ClientManager {
786
798
  }
787
799
  }
788
800
 
801
+ function isDuplicate<
802
+ T extends string | number | boolean | null | undefined | symbol,
803
+ >(value: T, index: number, array: T[]) {
804
+ return array.includes(value, index + 1)
805
+ }
806
+
789
807
  function reverseDomain(domain: string) {
790
808
  return domain.split('.').reverse().join('.')
791
809
  }
@@ -140,6 +140,7 @@ export class Client {
140
140
  audience: checks.audience,
141
141
  subject: this.id,
142
142
  maxTokenAge: CLIENT_ASSERTION_MAX_AGE / 1000,
143
+ requiredClaims: ['jti'],
143
144
  }).catch((err) => {
144
145
  if (err instanceof JOSEError) {
145
146
  const msg = `Validation of "client_assertion" failed: ${err.message}`
@@ -153,10 +154,6 @@ export class Client {
153
154
  throw new InvalidClientError(`"kid" required in client_assertion`)
154
155
  }
155
156
 
156
- if (!result.payload.jti) {
157
- throw new InvalidClientError(`"jti" required in client_assertion`)
158
- }
159
-
160
157
  const clientAuth: ClientAuth = {
161
158
  method: CLIENT_ASSERTION_TYPE_JWT_BEARER,
162
159
  jkt: await authJwkThumbprint(result.key),
package/src/constants.ts CHANGED
@@ -67,3 +67,6 @@ export const DPOP_NONCE_MAX_AGE = 3 * MINUTE
67
67
 
68
68
  /** 5 seconds */
69
69
  export const SESSION_FIXATION_MAX_AGE = 5 * SECOND
70
+
71
+ /** 1 day */
72
+ export const CODE_CHALLENGE_REPLAY_TIMEFRAME = 1 * DAY
@@ -100,10 +100,16 @@ export class DeviceManager {
100
100
  public async load(
101
101
  req: IncomingMessage,
102
102
  res: ServerResponse,
103
+ forceRotate = false,
103
104
  ): Promise<{ deviceId: DeviceId }> {
104
105
  const cookie = await this.getCookie(req)
105
106
  if (cookie) {
106
- return this.refresh(req, res, cookie.value, cookie.mustRotate)
107
+ return this.refresh(
108
+ req,
109
+ res,
110
+ cookie.value,
111
+ forceRotate || cookie.mustRotate,
112
+ )
107
113
  } else {
108
114
  return this.create(req, res)
109
115
  }
@@ -1,4 +1,5 @@
1
- import { OAuthError } from './oauth-error.js'
1
+ import { OAuthAuthenticationRequestParameters } from '@atproto/oauth-types'
2
+ import { AccessDeniedError } from './access-denied-error.js'
2
3
 
3
4
  /**
4
5
  * @see
@@ -15,8 +16,12 @@ import { OAuthError } from './oauth-error.js'
15
16
  * - contains fields with invalid values for the authorization details type, or
16
17
  * - is missing required fields for the authorization details type.
17
18
  */
18
- export class InvalidAuthorizationDetailsError extends OAuthError {
19
- constructor(error_description: string, cause?: unknown) {
20
- super('invalid_authorization_details', error_description, 400, cause)
19
+ export class InvalidAuthorizationDetailsError extends AccessDeniedError {
20
+ constructor(
21
+ parameters: OAuthAuthenticationRequestParameters,
22
+ error_description: string,
23
+ cause?: unknown,
24
+ ) {
25
+ super(parameters, error_description, 'invalid_authorization_details', cause)
21
26
  }
22
27
  }
@@ -28,6 +28,27 @@ export async function validateRequestPayload<S extends z.ZodTypeAny>(
28
28
  return schema.parseAsync(payload, { path: ['body'] })
29
29
  }
30
30
 
31
+ export function validateHeaderValue(
32
+ req: IncomingMessage,
33
+ name: keyof IncomingMessage['headers'],
34
+ allowedValues: readonly (string | null)[],
35
+ ) {
36
+ const value = req.headers[name] ?? null
37
+
38
+ if (Array.isArray(value)) {
39
+ throw createHttpError(400, `Invalid ${name} header`)
40
+ }
41
+
42
+ if (!allowedValues.includes(value)) {
43
+ throw createHttpError(
44
+ 400,
45
+ value
46
+ ? `Forbidden ${name} header "${value}" (expected ${allowedValues})`
47
+ : `Missing ${name} header`,
48
+ )
49
+ }
50
+ }
51
+
31
52
  export function validateFetchMode(
32
53
  req: IncomingMessage,
33
54
  res: ServerResponse,
@@ -39,20 +60,45 @@ export function validateFetchMode(
39
60
  | 'cors'
40
61
  )[],
41
62
  ) {
42
- const reqMode = req.headers['sec-fetch-mode'] ?? null
63
+ validateHeaderValue(req, 'sec-fetch-mode', expectedMode)
64
+ }
43
65
 
44
- if (Array.isArray(reqMode)) {
45
- throw createHttpError(400, `Invalid sec-fetch-mode header`)
46
- }
66
+ export function validateFetchDest(
67
+ req: IncomingMessage,
68
+ res: ServerResponse,
69
+ expectedDest: readonly (
70
+ | null
71
+ | 'document'
72
+ | 'embed'
73
+ | 'font'
74
+ | 'image'
75
+ | 'manifest'
76
+ | 'media'
77
+ | 'object'
78
+ | 'report'
79
+ | 'script'
80
+ | 'serviceworker'
81
+ | 'sharedworker'
82
+ | 'style'
83
+ | 'worker'
84
+ | 'xslt'
85
+ )[],
86
+ ) {
87
+ validateHeaderValue(req, 'sec-fetch-dest', expectedDest)
88
+ }
47
89
 
48
- if (!(expectedMode as (string | null)[]).includes(reqMode)) {
49
- throw createHttpError(
50
- 403,
51
- reqMode
52
- ? `Forbidden sec-fetch-mode "${reqMode}" (expected ${expectedMode})`
53
- : `Missing sec-fetch-mode (expected ${expectedMode})`,
54
- )
55
- }
90
+ export function validateFetchSite(
91
+ req: IncomingMessage,
92
+ res: ServerResponse,
93
+ expectedSite: readonly (
94
+ | null
95
+ | 'same-origin'
96
+ | 'same-site'
97
+ | 'cross-site'
98
+ | 'none'
99
+ )[],
100
+ ) {
101
+ validateHeaderValue(req, 'sec-fetch-site', expectedSite)
56
102
  }
57
103
 
58
104
  export function validateReferer(
@@ -64,7 +110,7 @@ export function validateReferer(
64
110
  const referer = req.headers['referer']
65
111
  const refererUrl = referer ? new URL(referer) : null
66
112
  if (refererUrl ? !urlMatch(refererUrl, reference) : !allowNull) {
67
- throw createHttpError(403, `Invalid referer ${referer}`)
113
+ throw createHttpError(400, `Invalid referer ${referer}`)
68
114
  }
69
115
  }
70
116
 
@@ -95,7 +141,7 @@ export function validateSameOrigin(
95
141
  ) {
96
142
  const reqOrigin = req.headers['origin']
97
143
  if (reqOrigin ? reqOrigin !== origin : !allowNull) {
98
- throw createHttpError(403, `Invalid origin ${reqOrigin}`)
144
+ throw createHttpError(400, `Invalid origin ${reqOrigin}`)
99
145
  }
100
146
  }
101
147
 
@@ -113,7 +159,7 @@ export function validateCsrfToken(
113
159
  !cookieName ||
114
160
  cookies[cookieName] !== csrfToken
115
161
  ) {
116
- throw createHttpError(403, `Invalid CSRF token`)
162
+ throw createHttpError(400, `Invalid CSRF token`)
117
163
  }
118
164
 
119
165
  if (clearCookie) {
@@ -2,11 +2,9 @@ import { Keyset } from '@atproto/jwk'
2
2
  import { OAuthAuthorizationServerMetadata } from '@atproto/oauth-types'
3
3
 
4
4
  import { Client } from '../client/client.js'
5
- import { OIDC_STANDARD_CLAIMS } from '../oidc/claims.js'
6
5
  import { VERIFY_ALGOS } from '../lib/util/crypto.js'
7
6
 
8
7
  export type CustomMetadata = {
9
- claims_supported?: string[]
10
8
  scopes_supported?: string[]
11
9
  authorization_details_types_supported?: string[]
12
10
  protected_resources?: string[]
@@ -25,35 +23,10 @@ export function buildMetadata(
25
23
  issuer,
26
24
 
27
25
  scopes_supported: [
28
- 'offline_access',
29
- 'openid',
30
- 'email',
31
- 'phone',
32
- 'profile',
33
-
26
+ 'atproto',
27
+ //
34
28
  ...(customMetadata?.scopes_supported ?? []),
35
29
  ],
36
- claims_supported: [
37
- /* IESG (Always provided) */
38
-
39
- 'sub', // did
40
- 'iss', // Authorization Server Origin
41
- 'aud',
42
- 'exp',
43
- 'iat',
44
- 'jti',
45
- 'client_id',
46
-
47
- /* OpenID */
48
-
49
- // 'acr', // "0"
50
- // 'amr',
51
- // 'azp',
52
- 'auth_time', // number - seconds since epoch
53
- 'nonce', // always required in "id_token", why would it not be supported?
54
-
55
- ...(customMetadata?.claims_supported ?? OIDC_STANDARD_CLAIMS),
56
- ],
57
30
  subject_types_supported: [
58
31
  //
59
32
  'public', // The same "sub" is returned for all clients
@@ -62,15 +35,15 @@ export function buildMetadata(
62
35
  response_types_supported: [
63
36
  // OAuth
64
37
  'code',
65
- 'token',
38
+ // 'token',
66
39
 
67
40
  // OpenID
68
- 'none',
69
- 'code id_token token',
70
- 'code id_token',
71
- 'code token',
72
- 'id_token token',
73
- 'id_token',
41
+ // 'none',
42
+ // 'code id_token token',
43
+ // 'code id_token',
44
+ // 'code token',
45
+ // 'id_token token',
46
+ // 'id_token',
74
47
  ],
75
48
  response_modes_supported: [
76
49
  // https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
@@ -93,7 +66,6 @@ export function buildMetadata(
93
66
  //
94
67
  'en-US',
95
68
  ],
96
- id_token_signing_alg_values_supported: [...keyset.signAlgorithms],
97
69
  display_values_supported: [
98
70
  //
99
71
  'page',
@@ -110,10 +82,6 @@ export function buildMetadata(
110
82
  request_object_encryption_alg_values_supported: [], // None
111
83
  request_object_encryption_enc_values_supported: [], // None
112
84
 
113
- // No claim makes sense to be translated
114
- claims_locales_supported: [],
115
-
116
- claims_parameter_supported: true,
117
85
  request_parameter_supported: true,
118
86
  request_uri_parameter_supported: true,
119
87
  require_request_uri_registration: true,
@@ -130,7 +98,6 @@ export function buildMetadata(
130
98
 
131
99
  introspection_endpoint: new URL('/oauth/introspect', issuer).href,
132
100
 
133
- userinfo_endpoint: new URL('/oauth/userinfo', issuer).href,
134
101
  // end_session_endpoint: new URL('/oauth/logout', issuer).href,
135
102
 
136
103
  // https://datatracker.ietf.org/doc/html/rfc9126#section-5
@@ -11,6 +11,7 @@ import { ClientAuth } from './client/client-auth.js'
11
11
  import { ClientId } from './client/client-id.js'
12
12
  import { ClientInfo } from './client/client-info.js'
13
13
  import { Client } from './client/client.js'
14
+ import { InvalidAuthorizationDetailsError } from './errors/invalid-authorization-details-error.js'
14
15
  import { Awaitable } from './lib/util/type.js'
15
16
 
16
17
  // Make sure all types needed to implement the OAuthHooks are exported
@@ -20,6 +21,7 @@ export type {
20
21
  ClientAuth,
21
22
  ClientId,
22
23
  ClientInfo,
24
+ InvalidAuthorizationDetailsError,
23
25
  Jwks,
24
26
  OAuthAuthenticationRequestParameters,
25
27
  OAuthAuthorizationDetails,
@@ -42,7 +44,7 @@ export type OAuthHooks = {
42
44
 
43
45
  /**
44
46
  * Allows enriching the authorization details with additional information
45
- * before the tokens are issued.
47
+ * when the tokens are issued.
46
48
  *
47
49
  * @see {@link https://datatracker.ietf.org/doc/html/rfc9396 | RFC 9396}
48
50
  */
@@ -51,16 +53,4 @@ export type OAuthHooks = {
51
53
  parameters: OAuthAuthenticationRequestParameters
52
54
  account: Account
53
55
  }) => Awaitable<undefined | OAuthAuthorizationDetails>
54
-
55
- /**
56
- * Allows altering the token response before it is sent to the client.
57
- */
58
- onTokenResponse?: (
59
- tokenResponse: OAuthTokenResponse,
60
- data: {
61
- client: Client
62
- parameters: OAuthAuthenticationRequestParameters
63
- account: Account
64
- },
65
- ) => Awaitable<void>
66
56
  }