@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,5 +1,6 @@
1
1
  import { isAtprotoDid } from '@atproto/did'
2
2
  import type { Account } from '@atproto/oauth-provider-api'
3
+ import { isValidAtprotoOauthScope } from '@atproto/oauth-scopes'
3
4
  import {
4
5
  OAuthAuthorizationRequestParameters,
5
6
  OAuthAuthorizationServerMetadata,
@@ -16,10 +17,10 @@ import {
16
17
  } from '../constants.js'
17
18
  import { DeviceId } from '../device/device-id.js'
18
19
  import { AccessDeniedError } from '../errors/access-denied-error.js'
20
+ import { AuthorizationError } from '../errors/authorization-error.js'
19
21
  import { ConsentRequiredError } from '../errors/consent-required-error.js'
20
22
  import { InvalidAuthorizationDetailsError } from '../errors/invalid-authorization-details-error.js'
21
23
  import { InvalidGrantError } from '../errors/invalid-grant-error.js'
22
- import { InvalidParametersError } from '../errors/invalid-parameters-error.js'
23
24
  import { InvalidRequestError } from '../errors/invalid-request-error.js'
24
25
  import { InvalidScopeError } from '../errors/invalid-scope-error.js'
25
26
  import { RequestMetadata } from '../lib/http/request.js'
@@ -60,10 +61,16 @@ export class RequestManager {
60
61
  ) {
61
62
  const parameters = await this.validate(client, clientAuth, input)
62
63
 
64
+ await callAsync(this.hooks.onAuthorizationRequest, {
65
+ client,
66
+ clientAuth,
67
+ parameters,
68
+ })
69
+
63
70
  const expiresAt = new Date(Date.now() + PAR_EXPIRES_IN)
64
- const id = await generateRequestId()
71
+ const requestId = await generateRequestId()
65
72
 
66
- await this.store.createRequest(id, {
73
+ await this.store.createRequest(requestId, {
67
74
  clientId: client.id,
68
75
  clientAuth,
69
76
  parameters,
@@ -73,8 +80,8 @@ export class RequestManager {
73
80
  code: null,
74
81
  })
75
82
 
76
- const uri = encodeRequestUri(id)
77
- return { uri, expiresAt, parameters }
83
+ const requestUri = encodeRequestUri(requestId)
84
+ return { requestUri, expiresAt, parameters }
78
85
  }
79
86
 
80
87
  protected async validate(
@@ -93,10 +100,7 @@ export class RequestManager {
93
100
  'nonce', // note that OIDC "nonce" is redundant with PKCE
94
101
  ] as const) {
95
102
  if (parameters[k] !== undefined) {
96
- throw new InvalidParametersError(
97
- parameters,
98
- `Unsupported "${k}" parameter`,
99
- )
103
+ throw new AuthorizationError(parameters, `Unsupported "${k}" parameter`)
100
104
  }
101
105
  }
102
106
 
@@ -109,7 +113,7 @@ export class RequestManager {
109
113
  parameters.response_type,
110
114
  )
111
115
  ) {
112
- throw new AccessDeniedError(
116
+ throw new AuthorizationError(
113
117
  parameters,
114
118
  `Unsupported response_type "${parameters.response_type}"`,
115
119
  'unsupported_response_type',
@@ -120,27 +124,13 @@ export class RequestManager {
120
124
  parameters.response_type === 'code' &&
121
125
  !this.metadata.grant_types_supported?.includes('authorization_code')
122
126
  ) {
123
- throw new AccessDeniedError(
127
+ throw new AuthorizationError(
124
128
  parameters,
125
129
  `Unsupported grant_type "authorization_code"`,
126
130
  'invalid_request',
127
131
  )
128
132
  }
129
133
 
130
- if (parameters.scope) {
131
- for (const scope of parameters.scope.split(' ')) {
132
- // Currently, the implementation requires all the scopes to be statically
133
- // defined in the server metadata. In the future, we might add support
134
- // for dynamic scopes.
135
- if (!this.metadata.scopes_supported?.includes(scope)) {
136
- throw new InvalidParametersError(
137
- parameters,
138
- `Scope "${scope}" is not supported by this server`,
139
- )
140
- }
141
- }
142
- }
143
-
144
134
  if (parameters.authorization_details) {
145
135
  for (const detail of parameters.authorization_details) {
146
136
  if (
@@ -169,7 +159,7 @@ export class RequestManager {
169
159
  if (!parameters.redirect_uri) {
170
160
  // Should already be ensured by client.validateRequest(). Adding here for
171
161
  // clarity & extra safety.
172
- throw new InvalidParametersError(parameters, 'Missing "redirect_uri"')
162
+ throw new AuthorizationError(parameters, 'Missing "redirect_uri"')
173
163
  }
174
164
 
175
165
  // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10#section-1.4.1
@@ -180,8 +170,16 @@ export class RequestManager {
180
170
  // > server MUST include the scope response parameter in the token response
181
171
  // > (Section 3.2.3) to inform the client of the actual scope granted.
182
172
 
183
- // Let's make sure the scopes are unique (to reduce the token & storage size)
184
- const scopes = new Set(parameters.scope?.split(' '))
173
+ // Let's make sure the scopes are unique (to reduce the token & storage
174
+ // size) & are indeed supported.
175
+
176
+ // @NOTE An app requesting a not yet supported list of scopes will need to
177
+ // re-authenticate the user once the scopes are supported. This is due to
178
+ // the fact that the AS does not know how to properly display those scopes
179
+ // to the user, so it cannot properly ask for consent.
180
+ const scopes = new Set(
181
+ parameters.scope?.split(' ')?.filter(isValidAtprotoOauthScope),
182
+ )
185
183
 
186
184
  parameters = { ...parameters, scope: [...scopes].join(' ') || undefined }
187
185
 
@@ -195,7 +193,7 @@ export class RequestManager {
195
193
  case 'S256':
196
194
  break
197
195
  default: {
198
- throw new InvalidParametersError(
196
+ throw new AuthorizationError(
199
197
  parameters,
200
198
  `Unsupported code_challenge_method "${parameters.code_challenge_method}"`,
201
199
  )
@@ -204,7 +202,7 @@ export class RequestManager {
204
202
  } else {
205
203
  if (parameters.code_challenge_method) {
206
204
  // https://datatracker.ietf.org/doc/html/rfc7636#section-4.4.1
207
- throw new InvalidParametersError(
205
+ throw new AuthorizationError(
208
206
  parameters,
209
207
  'code_challenge is required when code_challenge_method is provided',
210
208
  )
@@ -225,7 +223,7 @@ export class RequestManager {
225
223
  // atproto does not implement the OpenID Connect nonce mechanism, so we
226
224
  // require the use of PKCE for all clients.
227
225
 
228
- throw new InvalidParametersError(parameters, 'Use of PKCE is required')
226
+ throw new AuthorizationError(parameters, 'Use of PKCE is required')
229
227
  }
230
228
 
231
229
  // -----------------
@@ -233,7 +231,7 @@ export class RequestManager {
233
231
  // -----------------
234
232
 
235
233
  if (parameters.response_type !== 'code') {
236
- throw new InvalidParametersError(
234
+ throw new AuthorizationError(
237
235
  parameters,
238
236
  'atproto only supports the "code" response_type',
239
237
  )
@@ -249,7 +247,7 @@ export class RequestManager {
249
247
  }
250
248
 
251
249
  if (parameters.code_challenge_method !== 'S256') {
252
- throw new InvalidParametersError(
250
+ throw new AuthorizationError(
253
251
  parameters,
254
252
  'atproto requires use of "S256" code_challenge_method',
255
253
  )
@@ -280,10 +278,7 @@ export class RequestManager {
280
278
  const hint = parameters.login_hint?.toLowerCase()
281
279
  if (hint) {
282
280
  if (!isAtprotoDid(hint) && !isValidHandle(hint)) {
283
- throw new InvalidParametersError(
284
- parameters,
285
- `Invalid login_hint "${hint}"`,
286
- )
281
+ throw new AuthorizationError(parameters, `Invalid login_hint "${hint}"`)
287
282
  }
288
283
 
289
284
  // @TODO: ensure that the account actually exists on this server (there is
@@ -296,10 +291,10 @@ export class RequestManager {
296
291
  return parameters
297
292
  }
298
293
 
299
- async get(uri: RequestUri, deviceId: DeviceId, clientId?: ClientId) {
300
- const id = decodeRequestUri(uri)
294
+ async get(requestUri: RequestUri, deviceId: DeviceId, clientId?: ClientId) {
295
+ const requestId = decodeRequestUri(requestUri)
301
296
 
302
- const data = await this.store.readRequest(id)
297
+ const data = await this.store.readRequest(requestId)
303
298
  if (!data) throw new InvalidRequestError('Unknown request_uri')
304
299
 
305
300
  const updates: UpdateRequestData = {}
@@ -338,16 +333,16 @@ export class RequestManager {
338
333
  )
339
334
  }
340
335
  } catch (err) {
341
- await this.store.deleteRequest(id)
336
+ await this.store.deleteRequest(requestId)
342
337
  throw err
343
338
  }
344
339
 
345
340
  if (Object.keys(updates).length > 0) {
346
- await this.store.updateRequest(id, updates)
341
+ await this.store.updateRequest(requestId, updates)
347
342
  }
348
343
 
349
344
  return {
350
- uri,
345
+ requestUri,
351
346
  expiresAt: updates.expiresAt || data.expiresAt,
352
347
  parameters: data.parameters,
353
348
  clientId: data.clientId,
@@ -355,40 +350,65 @@ export class RequestManager {
355
350
  }
356
351
 
357
352
  async setAuthorized(
358
- uri: RequestUri,
353
+ requestUri: RequestUri,
359
354
  client: Client,
360
355
  account: Account,
361
356
  deviceId: DeviceId,
362
357
  deviceMetadata: RequestMetadata,
358
+ scopeOverride?: string,
363
359
  ): Promise<Code> {
364
- const requestId = decodeRequestUri(uri)
360
+ const requestId = decodeRequestUri(requestUri)
365
361
 
366
362
  const data = await this.store.readRequest(requestId)
367
363
  if (!data) throw new InvalidRequestError('Unknown request_uri')
368
364
 
365
+ let { parameters } = data
366
+
369
367
  try {
370
368
  if (data.expiresAt < new Date()) {
371
- throw new AccessDeniedError(data.parameters, 'This request has expired')
369
+ throw new AccessDeniedError(parameters, 'This request has expired')
372
370
  }
373
371
  if (!data.deviceId) {
374
372
  throw new AccessDeniedError(
375
- data.parameters,
373
+ parameters,
376
374
  'This request was not initiated',
377
375
  )
378
376
  }
379
377
  if (data.deviceId !== deviceId) {
380
378
  throw new AccessDeniedError(
381
- data.parameters,
379
+ parameters,
382
380
  'This request was initiated from another device',
383
381
  )
384
382
  }
385
383
  if (data.sub || data.code) {
386
384
  throw new AccessDeniedError(
387
- data.parameters,
385
+ parameters,
388
386
  'This request was already authorized',
389
387
  )
390
388
  }
391
389
 
390
+ // If a new scope value is provided, update the parameters by ensuring
391
+ // that every existing scope in the parameters is also present in the
392
+ // override value. This allows the user to remove scopes from the request,
393
+ // but not to add new ones.
394
+ if (scopeOverride != null) {
395
+ const allowedScopes = new Set(scopeOverride.split(' '))
396
+ const existingScopes = parameters.scope?.split(' ')
397
+
398
+ // Compute the intersection of the existing scopes and the overrides.
399
+ const newScopes = existingScopes?.filter((s) => allowedScopes.has(s))
400
+
401
+ // Validate: make sure the new scopes are valid
402
+ if (!newScopes?.includes('atproto')) {
403
+ throw new AccessDeniedError(
404
+ parameters,
405
+ 'The "atproto" scope is required',
406
+ )
407
+ }
408
+
409
+ parameters = { ...parameters, scope: newScopes.join(' ') }
410
+ }
411
+
392
412
  // Only response_type=code is supported
393
413
  const code = await generateCode()
394
414
 
@@ -398,12 +418,13 @@ export class RequestManager {
398
418
  code,
399
419
  // Allow the client to exchange the code for a token within the next 60 seconds.
400
420
  expiresAt: new Date(Date.now() + AUTHORIZATION_INACTIVITY_TIMEOUT),
421
+ parameters,
401
422
  })
402
423
 
403
424
  await callAsync(this.hooks.onAuthorized, {
404
425
  client,
405
426
  account,
406
- parameters: data.parameters,
427
+ parameters,
407
428
  deviceId,
408
429
  deviceMetadata,
409
430
  requestId,
@@ -424,12 +445,12 @@ export class RequestManager {
424
445
  const result = await this.store.consumeRequestCode(code)
425
446
  if (!result) throw new InvalidGrantError('Invalid code')
426
447
 
427
- const { id, data } = result
448
+ const { requestId, data } = result
428
449
 
429
450
  // Fool-proofing the store implementation against code replay attacks (in
430
451
  // case consumeRequestCode() does not delete the request).
431
452
  if (NODE_ENV !== 'production') {
432
- const result = await this.store.readRequest(id)
453
+ const result = await this.store.readRequest(requestId)
433
454
  if (result) {
434
455
  throw new Error('Invalid store implementation: request not deleted')
435
456
  }
@@ -447,8 +468,8 @@ export class RequestManager {
447
468
  return data
448
469
  }
449
470
 
450
- async delete(uri: RequestUri): Promise<void> {
451
- const id = decodeRequestUri(uri)
452
- await this.store.deleteRequest(id)
471
+ async delete(requestUri: RequestUri): Promise<void> {
472
+ const requestId = decodeRequestUri(requestUri)
473
+ await this.store.deleteRequest(requestId)
453
474
  }
454
475
  }
@@ -12,25 +12,25 @@ export type { Awaitable }
12
12
 
13
13
  export type UpdateRequestData = Pick<
14
14
  Partial<RequestData>,
15
- 'sub' | 'code' | 'deviceId' | 'expiresAt'
15
+ 'sub' | 'code' | 'deviceId' | 'expiresAt' | 'parameters'
16
16
  >
17
17
 
18
18
  export type FoundRequestResult = {
19
- id: RequestId
19
+ requestId: RequestId
20
20
  data: RequestData
21
21
  }
22
22
 
23
23
  export { InvalidGrantError }
24
24
 
25
25
  export interface RequestStore {
26
- createRequest(id: RequestId, data: RequestData): Awaitable<void>
26
+ createRequest(requestId: RequestId, data: RequestData): Awaitable<void>
27
27
  /**
28
28
  * Note that expired requests **can** be returned to yield a different error
29
29
  * message than if the request was not found.
30
30
  */
31
- readRequest(id: RequestId): Awaitable<RequestData | null>
32
- updateRequest(id: RequestId, data: UpdateRequestData): Awaitable<void>
33
- deleteRequest(id: RequestId): void | Awaitable<void>
31
+ readRequest(requestId: RequestId): Awaitable<RequestData | null>
32
+ updateRequest(requestId: RequestId, data: UpdateRequestData): Awaitable<void>
33
+ deleteRequest(requestId: RequestId): void | Awaitable<void>
34
34
  /**
35
35
  * @note it is **IMPORTANT** that this method prevents concurrent retrieval of
36
36
  * the same code. If two requests are made with the same code, only one of
@@ -1,4 +1,4 @@
1
- import type { ScopeDetail, Session } from '@atproto/oauth-provider-api'
1
+ import type { Session } from '@atproto/oauth-provider-api'
2
2
  import { OAuthAuthorizationRequestParameters } from '@atproto/oauth-types'
3
3
  import { Client } from '../client/client.js'
4
4
  import { RequestUri } from '../request/request-uri.js'
@@ -8,7 +8,6 @@ export type AuthorizationResultAuthorizePage = {
8
8
  client: Client
9
9
  parameters: OAuthAuthorizationRequestParameters
10
10
 
11
- uri: RequestUri
12
- scopeDetails?: ScopeDetail[]
11
+ requestUri: RequestUri
13
12
  sessions: readonly Session[]
14
13
  }
@@ -36,14 +36,14 @@ export function sendAuthorizePageFactory(customization: Customization) {
36
36
  const script = declareHydrationData<HydrationData['authorization-page']>({
37
37
  __customizationData: customizationData,
38
38
  __authorizeData: {
39
- requestUri: data.uri,
39
+ requestUri: data.requestUri,
40
40
 
41
41
  clientId: data.client.id,
42
42
  clientMetadata: data.client.metadata,
43
43
  clientTrusted: data.client.info.isTrusted,
44
+ clientFirstParty: data.client.info.isFirstParty,
44
45
 
45
- scopeDetails: data.scopeDetails,
46
-
46
+ scope: data.parameters.scope,
47
47
  uiLocales: data.parameters.ui_locales,
48
48
  loginHint: data.parameters.login_hint,
49
49
  },