@atproto/oauth-provider 0.1.2 → 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 (136) hide show
  1. package/CHANGELOG.md +46 -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 +3 -3
  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 +91 -77
  15. package/dist/client/client-manager.js.map +1 -1
  16. package/dist/client/client.d.ts +2 -3
  17. package/dist/client/client.d.ts.map +1 -1
  18. package/dist/client/client.js +6 -12
  19. package/dist/client/client.js.map +1 -1
  20. package/dist/constants.d.ts +2 -0
  21. package/dist/constants.d.ts.map +1 -1
  22. package/dist/constants.js +3 -1
  23. package/dist/constants.js.map +1 -1
  24. package/dist/device/device-manager.d.ts +1 -1
  25. package/dist/device/device-manager.d.ts.map +1 -1
  26. package/dist/device/device-manager.js +2 -2
  27. package/dist/device/device-manager.js.map +1 -1
  28. package/dist/dpop/dpop-manager.d.ts +0 -1
  29. package/dist/dpop/dpop-manager.d.ts.map +1 -1
  30. package/dist/dpop/dpop-manager.js +1 -4
  31. package/dist/dpop/dpop-manager.js.map +1 -1
  32. package/dist/errors/invalid-authorization-details-error.d.ts +4 -3
  33. package/dist/errors/invalid-authorization-details-error.d.ts.map +1 -1
  34. package/dist/errors/invalid-authorization-details-error.js +4 -4
  35. package/dist/errors/invalid-authorization-details-error.js.map +1 -1
  36. package/dist/lib/http/parser.d.ts +13 -7
  37. package/dist/lib/http/parser.d.ts.map +1 -1
  38. package/dist/lib/http/parser.js +29 -9
  39. package/dist/lib/http/parser.js.map +1 -1
  40. package/dist/lib/http/request.d.ts +8 -5
  41. package/dist/lib/http/request.d.ts.map +1 -1
  42. package/dist/lib/http/request.js +24 -12
  43. package/dist/lib/http/request.js.map +1 -1
  44. package/dist/lib/http/stream.d.ts.map +1 -1
  45. package/dist/lib/http/stream.js +3 -2
  46. package/dist/lib/http/stream.js.map +1 -1
  47. package/dist/metadata/build-metadata.d.ts +0 -1
  48. package/dist/metadata/build-metadata.d.ts.map +1 -1
  49. package/dist/metadata/build-metadata.js +9 -49
  50. package/dist/metadata/build-metadata.js.map +1 -1
  51. package/dist/oauth-hooks.d.ts +3 -10
  52. package/dist/oauth-hooks.d.ts.map +1 -1
  53. package/dist/oauth-provider.d.ts +10 -15
  54. package/dist/oauth-provider.d.ts.map +1 -1
  55. package/dist/oauth-provider.js +176 -114
  56. package/dist/oauth-provider.js.map +1 -1
  57. package/dist/oauth-verifier.d.ts +1 -2
  58. package/dist/oauth-verifier.d.ts.map +1 -1
  59. package/dist/oauth-verifier.js.map +1 -1
  60. package/dist/output/build-authorize-data.d.ts +6 -0
  61. package/dist/output/build-authorize-data.d.ts.map +1 -1
  62. package/dist/output/build-authorize-data.js +1 -0
  63. package/dist/output/build-authorize-data.js.map +1 -1
  64. package/dist/replay/replay-manager.d.ts +1 -0
  65. package/dist/replay/replay-manager.d.ts.map +1 -1
  66. package/dist/replay/replay-manager.js +3 -0
  67. package/dist/replay/replay-manager.js.map +1 -1
  68. package/dist/replay/replay-store.d.ts +1 -1
  69. package/dist/request/request-info.d.ts +2 -0
  70. package/dist/request/request-info.d.ts.map +1 -1
  71. package/dist/request/request-manager.d.ts +3 -9
  72. package/dist/request/request-manager.d.ts.map +1 -1
  73. package/dist/request/request-manager.js +52 -77
  74. package/dist/request/request-manager.js.map +1 -1
  75. package/dist/request/types.d.ts +10 -10
  76. package/dist/signer/signed-token-payload.d.ts +88 -88
  77. package/dist/signer/signer.d.ts +24 -31
  78. package/dist/signer/signer.d.ts.map +1 -1
  79. package/dist/signer/signer.js +0 -40
  80. package/dist/signer/signer.js.map +1 -1
  81. package/dist/token/token-claims.d.ts +84 -84
  82. package/dist/token/token-manager.d.ts +1 -2
  83. package/dist/token/token-manager.d.ts.map +1 -1
  84. package/dist/token/token-manager.js +10 -37
  85. package/dist/token/token-manager.js.map +1 -1
  86. package/dist/token/types.d.ts +10 -10
  87. package/package.json +3 -3
  88. package/src/account/account.ts +11 -7
  89. package/src/assets/app/backend-data.ts +9 -2
  90. package/src/assets/app/components/accept-form.tsx +65 -51
  91. package/src/assets/app/components/client-name.tsx +24 -16
  92. package/src/assets/app/components/url-viewer.tsx +3 -3
  93. package/src/assets/app/views/accept-view.tsx +7 -4
  94. package/src/assets/app/views/authorize-view.tsx +2 -1
  95. package/src/assets/assets-middleware.ts +14 -2
  96. package/src/client/client-manager.ts +124 -120
  97. package/src/client/client.ts +5 -17
  98. package/src/constants.ts +3 -0
  99. package/src/device/device-manager.ts +7 -1
  100. package/src/dpop/dpop-manager.ts +1 -6
  101. package/src/errors/invalid-authorization-details-error.ts +9 -4
  102. package/src/lib/http/parser.ts +37 -13
  103. package/src/lib/http/request.ts +61 -15
  104. package/src/lib/http/stream.ts +5 -2
  105. package/src/metadata/build-metadata.ts +9 -56
  106. package/src/oauth-hooks.ts +3 -13
  107. package/src/oauth-provider.ts +187 -177
  108. package/src/oauth-verifier.ts +1 -2
  109. package/src/output/build-authorize-data.ts +8 -0
  110. package/src/replay/replay-manager.ts +9 -0
  111. package/src/replay/replay-store.ts +1 -1
  112. package/src/request/request-info.ts +2 -0
  113. package/src/request/request-manager.ts +81 -107
  114. package/src/signer/signer.ts +0 -63
  115. package/src/token/token-manager.ts +8 -41
  116. package/dist/oidc/claims.d.ts +0 -16
  117. package/dist/oidc/claims.d.ts.map +0 -1
  118. package/dist/oidc/claims.js +0 -29
  119. package/dist/oidc/claims.js.map +0 -1
  120. package/dist/oidc/userinfo.d.ts +0 -7
  121. package/dist/oidc/userinfo.d.ts.map +0 -1
  122. package/dist/oidc/userinfo.js +0 -3
  123. package/dist/oidc/userinfo.js.map +0 -1
  124. package/dist/parameters/claims-requested.d.ts +0 -3
  125. package/dist/parameters/claims-requested.d.ts.map +0 -1
  126. package/dist/parameters/claims-requested.js +0 -77
  127. package/dist/parameters/claims-requested.js.map +0 -1
  128. package/dist/parameters/oidc-payload.d.ts +0 -31
  129. package/dist/parameters/oidc-payload.d.ts.map +0 -1
  130. package/dist/parameters/oidc-payload.js +0 -25
  131. package/dist/parameters/oidc-payload.js.map +0 -1
  132. package/src/assets/app/components/client-identifier.tsx +0 -31
  133. package/src/oidc/claims.ts +0 -35
  134. package/src/oidc/userinfo.ts +0 -11
  135. package/src/parameters/claims-requested.ts +0 -106
  136. package/src/parameters/oidc-payload.ts +0 -28
@@ -3,7 +3,6 @@ import {
3
3
  CLIENT_ASSERTION_TYPE_JWT_BEARER,
4
4
  OAuthClientIdentification,
5
5
  OAuthClientMetadata,
6
- OAuthEndpointName,
7
6
  } from '@atproto/oauth-types'
8
7
  import {
9
8
  UnsecuredJWT,
@@ -101,13 +100,6 @@ export class Client {
101
100
  })
102
101
  }
103
102
 
104
- protected getAuthMethod(endpoint: OAuthEndpointName) {
105
- return (
106
- this.metadata[`${endpoint}_endpoint_auth_method`] ||
107
- this.metadata[`token_endpoint_auth_method`]
108
- )
109
- }
110
-
111
103
  /**
112
104
  * @see {@link https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1}
113
105
  * @see {@link https://datatracker.ietf.org/doc/html/draft-ietf-oauth-jwt-bearer-11#section-3}
@@ -115,7 +107,6 @@ export class Client {
115
107
  */
116
108
  public async verifyCredentials(
117
109
  input: OAuthClientIdentification,
118
- endpoint: OAuthEndpointName,
119
110
  checks: {
120
111
  audience: string
121
112
  },
@@ -124,7 +115,7 @@ export class Client {
124
115
  // for replay protection
125
116
  nonce?: string
126
117
  }> {
127
- const method = this.getAuthMethod(endpoint)
118
+ const method = this.metadata[`token_endpoint_auth_method`]
128
119
 
129
120
  if (method === 'none') {
130
121
  const clientAuth: ClientAuth = { method: 'none' }
@@ -149,6 +140,7 @@ export class Client {
149
140
  audience: checks.audience,
150
141
  subject: this.id,
151
142
  maxTokenAge: CLIENT_ASSERTION_MAX_AGE / 1000,
143
+ requiredClaims: ['jti'],
152
144
  }).catch((err) => {
153
145
  if (err instanceof JOSEError) {
154
146
  const msg = `Validation of "client_assertion" failed: ${err.message}`
@@ -162,10 +154,6 @@ export class Client {
162
154
  throw new InvalidClientError(`"kid" required in client_assertion`)
163
155
  }
164
156
 
165
- if (!result.payload.jti) {
166
- throw new InvalidClientError(`"jti" required in client_assertion`)
167
- }
168
-
169
157
  const clientAuth: ClientAuth = {
170
158
  method: CLIENT_ASSERTION_TYPE_JWT_BEARER,
171
159
  jkt: await authJwkThumbprint(result.key),
@@ -192,7 +180,7 @@ export class Client {
192
180
  }
193
181
 
194
182
  throw new InvalidClientMetadataError(
195
- `Unsupported ${endpoint}_endpoint_auth_method "${method}"`,
183
+ `Unsupported token_endpoint_auth_method "${method}"`,
196
184
  )
197
185
  }
198
186
 
@@ -204,11 +192,11 @@ export class Client {
204
192
  */
205
193
  public async validateClientAuth(clientAuth: ClientAuth): Promise<boolean> {
206
194
  if (clientAuth.method === 'none') {
207
- return this.getAuthMethod('token') === 'none'
195
+ return this.metadata[`token_endpoint_auth_method`] === 'none'
208
196
  }
209
197
 
210
198
  if (clientAuth.method === CLIENT_ASSERTION_TYPE_JWT_BEARER) {
211
- if (this.getAuthMethod('token') !== 'private_key_jwt') {
199
+ if (this.metadata[`token_endpoint_auth_method`] !== 'private_key_jwt') {
212
200
  return false
213
201
  }
214
202
  try {
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
  }
@@ -52,13 +52,12 @@ export class DpopManager {
52
52
 
53
53
  const { protectedHeader, payload } = await jwtVerify<{
54
54
  iat: number
55
- exp: number
56
55
  jti: string
57
56
  }>(proof, EmbeddedJWK, {
58
57
  typ: 'dpop+jwt',
59
58
  maxTokenAge: 10,
60
59
  clockTolerance: DPOP_NONCE_MAX_AGE / 1e3,
61
- requiredClaims: ['iat', 'exp', 'jti'],
60
+ requiredClaims: ['iat', 'jti'],
62
61
  }).catch((err) => {
63
62
  const message =
64
63
  err instanceof JOSEError
@@ -71,10 +70,6 @@ export class DpopManager {
71
70
  throw new InvalidDpopProofError('Invalid or missing jti property')
72
71
  }
73
72
 
74
- if (payload.exp - payload.iat > DPOP_NONCE_MAX_AGE / 3 / 1e3) {
75
- throw new InvalidDpopProofError('DPoP proof validity too long')
76
- }
77
-
78
73
  // Note rfc9110#section-9.1 states that the method name is case-sensitive
79
74
  if (!htm || htm !== payload['htm']) {
80
75
  throw new InvalidDpopProofError('DPoP htm mismatch')
@@ -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
  }
@@ -1,13 +1,33 @@
1
1
  import { parse as parseJson } from '@hapi/bourne'
2
+ import { type as hapiContentType } from '@hapi/content'
2
3
  import createHttpError from 'http-errors'
3
4
 
4
5
  export type JsonScalar = string | number | boolean | null
5
6
  export type Json = JsonScalar | Json[] | { [_ in string]?: Json }
6
7
 
8
+ export const parseContentType = (type: string): ContentType => {
9
+ try {
10
+ return hapiContentType(type)
11
+ } catch (err) {
12
+ // De-boomify the error
13
+ if (err?.['isBoom']) {
14
+ throw createHttpError(err['output']['statusCode'], err['message'])
15
+ }
16
+
17
+ throw err
18
+ }
19
+ }
20
+
21
+ export type ContentType = {
22
+ mime: string
23
+ charset?: string
24
+ boundary?: string
25
+ }
26
+
7
27
  export type Parser<T extends string = string, R = unknown> = {
8
28
  readonly name: string
9
- readonly test: (type: string) => type is T
10
- readonly parse: (buffer: Buffer) => R
29
+ readonly test: (mime: string) => mime is T
30
+ readonly parse: (buffer: Buffer, type: ContentType) => R
11
31
  }
12
32
 
13
33
  export type ParserName<P extends Parser> = P extends { readonly name: infer N }
@@ -22,12 +42,13 @@ export type ParserForType<P extends Parser, T> =
22
42
  export const parsers = [
23
43
  {
24
44
  name: 'json',
25
- test: (
26
- type: string,
27
- ): type is `application/json` | `application/${string}+json` => {
28
- return /^application\/(?:.+\+)?json$/.test(type)
45
+ test: (mime): mime is `application/json` | `application/${string}+json` => {
46
+ return /^application\/(?:.+\+)?json$/.test(mime)
29
47
  },
30
- parse: (buffer: Buffer): Json => {
48
+ parse: (buffer, { charset }): Json => {
49
+ if (charset != null && !/^utf-?8$/i.test(charset)) {
50
+ throw createHttpError(415, 'Unsupported charset')
51
+ }
31
52
  try {
32
53
  return parseJson(buffer.toString())
33
54
  } catch (err) {
@@ -37,10 +58,13 @@ export const parsers = [
37
58
  },
38
59
  {
39
60
  name: 'urlencoded',
40
- test: (type: string): type is 'application/x-www-form-urlencoded' => {
41
- return type === 'application/x-www-form-urlencoded'
61
+ test: (mime): mime is 'application/x-www-form-urlencoded' => {
62
+ return mime === 'application/x-www-form-urlencoded'
42
63
  },
43
- parse: (buffer: Buffer): Partial<Record<string, string>> => {
64
+ parse: (buffer, { charset }): Partial<Record<string, string>> => {
65
+ if (charset != null && !/^utf-?8$/i.test(charset)) {
66
+ throw createHttpError(415, 'Unsupported charset')
67
+ }
44
68
  try {
45
69
  if (!buffer.length) return {}
46
70
  return Object.fromEntries(new URLSearchParams(buffer.toString()))
@@ -51,10 +75,10 @@ export const parsers = [
51
75
  },
52
76
  {
53
77
  name: 'bytes',
54
- test: (type: string): type is 'application/octet-stream' => {
55
- return type === 'application/octet-stream'
78
+ test: (mime): mime is 'application/octet-stream' => {
79
+ return mime === 'application/octet-stream'
56
80
  },
57
- parse: (buffer: Buffer): Buffer => buffer,
81
+ parse: (buffer): Buffer => buffer,
58
82
  },
59
83
  ] as const satisfies Parser[]
60
84
 
@@ -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) {
@@ -7,6 +7,7 @@ import {
7
7
  KnownNames,
8
8
  KnownParser,
9
9
  KnownTypes,
10
+ parseContentType,
10
11
  ParserForType,
11
12
  ParserResult,
12
13
  parsers,
@@ -64,9 +65,11 @@ export async function parseStream(
64
65
  throw createHttpError(400, 'Invalid content-type')
65
66
  }
66
67
 
68
+ const type = parseContentType(contentType)
69
+
67
70
  const parser = parsers.find(
68
71
  (parser) =>
69
- allow?.includes(parser.name) !== false && parser.test(contentType),
72
+ allow?.includes(parser.name) !== false && parser.test(type.mime),
70
73
  )
71
74
 
72
75
  if (!parser) {
@@ -74,5 +77,5 @@ export async function parseStream(
74
77
  }
75
78
 
76
79
  const buffer = await readStream(req)
77
- return parser.parse(buffer)
80
+ return parser.parse(buffer, type)
78
81
  }
@@ -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,
@@ -127,28 +95,13 @@ export function buildMetadata(
127
95
  token_endpoint_auth_signing_alg_values_supported: [...VERIFY_ALGOS],
128
96
 
129
97
  revocation_endpoint: new URL('/oauth/revoke', issuer).href,
130
- revocation_endpoint_auth_methods_supported: [
131
- ...Client.AUTH_METHODS_SUPPORTED,
132
- ],
133
- revocation_endpoint_auth_signing_alg_values_supported: [...VERIFY_ALGOS],
134
98
 
135
99
  introspection_endpoint: new URL('/oauth/introspect', issuer).href,
136
- introspection_endpoint_auth_methods_supported: [
137
- ...Client.AUTH_METHODS_SUPPORTED,
138
- ],
139
- introspection_endpoint_auth_signing_alg_values_supported: [...VERIFY_ALGOS],
140
100
 
141
- userinfo_endpoint: new URL('/oauth/userinfo', issuer).href,
142
101
  // end_session_endpoint: new URL('/oauth/logout', issuer).href,
143
102
 
144
103
  // https://datatracker.ietf.org/doc/html/rfc9126#section-5
145
104
  pushed_authorization_request_endpoint: new URL('/oauth/par', issuer).href,
146
- pushed_authorization_request_endpoint_auth_methods_supported: [
147
- ...Client.AUTH_METHODS_SUPPORTED,
148
- ],
149
- pushed_authorization_request_endpoint_auth_signing_alg_values_supported: [
150
- ...VERIFY_ALGOS,
151
- ],
152
105
 
153
106
  require_pushed_authorization_requests: true,
154
107
 
@@ -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
  }