@atproto/oauth-provider 0.18.3 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/account/account-manager.d.ts +11 -7
  3. package/dist/account/account-manager.d.ts.map +1 -1
  4. package/dist/account/account-manager.js +82 -19
  5. package/dist/account/account-manager.js.map +1 -1
  6. package/dist/account/account-store.d.ts +47 -13
  7. package/dist/account/account-store.d.ts.map +1 -1
  8. package/dist/account/account-store.js +12 -9
  9. package/dist/account/account-store.js.map +1 -1
  10. package/dist/account/sign-in-data.d.ts +2 -2
  11. package/dist/account/sign-up-input.d.ts +5 -5
  12. package/dist/client/client-manager.d.ts.map +1 -1
  13. package/dist/client/client-manager.js.map +1 -1
  14. package/dist/client/client.d.ts +1 -1
  15. package/dist/client/client.d.ts.map +1 -1
  16. package/dist/client/client.js.map +1 -1
  17. package/dist/customization/branding.d.ts +52 -52
  18. package/dist/customization/colors.d.ts +24 -24
  19. package/dist/customization/colors.d.ts.map +1 -1
  20. package/dist/customization/customization.d.ts +77 -77
  21. package/dist/customization/links.d.ts +4 -4
  22. package/dist/device/device-manager.d.ts +20 -20
  23. package/dist/device/device-manager.d.ts.map +1 -1
  24. package/dist/device/device-manager.js.map +1 -1
  25. package/dist/device/device-store.js +1 -1
  26. package/dist/device/device-store.js.map +1 -1
  27. package/dist/dpop/dpop-manager.d.ts.map +1 -1
  28. package/dist/dpop/dpop-manager.js.map +1 -1
  29. package/dist/dpop/dpop-nonce.d.ts.map +1 -1
  30. package/dist/dpop/dpop-nonce.js +1 -1
  31. package/dist/dpop/dpop-nonce.js.map +1 -1
  32. package/dist/errors/access-denied-error.d.ts.map +1 -1
  33. package/dist/errors/account-selection-required-error.d.ts.map +1 -1
  34. package/dist/errors/authorization-error.d.ts.map +1 -1
  35. package/dist/errors/authorization-error.js.map +1 -1
  36. package/dist/errors/consent-required-error.d.ts.map +1 -1
  37. package/dist/errors/handle-unavailable-error.d.ts +1 -1
  38. package/dist/errors/handle-unavailable-error.d.ts.map +1 -1
  39. package/dist/errors/handle-unavailable-error.js.map +1 -1
  40. package/dist/errors/invalid-authorization-details-error.d.ts.map +1 -1
  41. package/dist/errors/invalid-client-error.d.ts.map +1 -1
  42. package/dist/errors/invalid-client-id-error.d.ts.map +1 -1
  43. package/dist/errors/invalid-client-metadata-error.d.ts.map +1 -1
  44. package/dist/errors/invalid-credentials-error.d.ts +9 -9
  45. package/dist/errors/invalid-credentials-error.d.ts.map +1 -1
  46. package/dist/errors/invalid-credentials-error.js +8 -8
  47. package/dist/errors/invalid-credentials-error.js.map +1 -1
  48. package/dist/errors/invalid-dpop-key-binding-error.d.ts.map +1 -1
  49. package/dist/errors/invalid-dpop-proof-error.d.ts.map +1 -1
  50. package/dist/errors/invalid-grant-error.d.ts.map +1 -1
  51. package/dist/errors/invalid-invite-code-error.d.ts.map +1 -1
  52. package/dist/errors/invalid-redirect-uri-error.d.ts.map +1 -1
  53. package/dist/errors/invalid-request-error.d.ts.map +1 -1
  54. package/dist/errors/invalid-scope-error.d.ts.map +1 -1
  55. package/dist/errors/invalid-token-error.d.ts.map +1 -1
  56. package/dist/errors/invalid-token-error.js.map +1 -1
  57. package/dist/errors/login-required-error.d.ts.map +1 -1
  58. package/dist/errors/oauth-error.d.ts.map +1 -1
  59. package/dist/errors/oauth-error.js.map +1 -1
  60. package/dist/errors/second-authentication-factor-required-error.d.ts +2 -2
  61. package/dist/errors/second-authentication-factor-required-error.d.ts.map +1 -1
  62. package/dist/errors/second-authentication-factor-required-error.js.map +1 -1
  63. package/dist/errors/unauthorized-client-error.d.ts.map +1 -1
  64. package/dist/errors/use-dpop-nonce-error.d.ts.map +1 -1
  65. package/dist/errors/www-authenticate-error.d.ts.map +1 -1
  66. package/dist/lexicon/lexicon-getter.d.ts.map +1 -1
  67. package/dist/lexicon/lexicon-manager.d.ts.map +1 -1
  68. package/dist/lexicon/lexicon-store.js +1 -1
  69. package/dist/lexicon/lexicon-store.js.map +1 -1
  70. package/dist/lib/csp/index.d.ts +3 -3
  71. package/dist/lib/csp/index.d.ts.map +1 -1
  72. package/dist/lib/hcaptcha.d.ts +3 -3
  73. package/dist/lib/hcaptcha.d.ts.map +1 -1
  74. package/dist/lib/hcaptcha.js.map +1 -1
  75. package/dist/lib/html/build-document.d.ts.map +1 -1
  76. package/dist/lib/html/html.d.ts.map +1 -1
  77. package/dist/lib/html/tags.d.ts.map +1 -1
  78. package/dist/lib/http/accept.js.map +1 -1
  79. package/dist/lib/http/context.js.map +1 -1
  80. package/dist/lib/http/middleware.js.map +1 -1
  81. package/dist/lib/http/parser.d.ts +5 -5
  82. package/dist/lib/http/parser.d.ts.map +1 -1
  83. package/dist/lib/http/response.js.map +1 -1
  84. package/dist/lib/http/router.d.ts.map +1 -1
  85. package/dist/lib/http/stream.d.ts +5 -5
  86. package/dist/lib/http/stream.d.ts.map +1 -1
  87. package/dist/lib/util/authorization-header.d.ts +1 -1
  88. package/dist/lib/util/authorization-header.d.ts.map +1 -1
  89. package/dist/lib/util/color.js.map +1 -1
  90. package/dist/lib/util/crypto.d.ts +1 -1
  91. package/dist/lib/util/crypto.d.ts.map +1 -1
  92. package/dist/lib/util/date.js.map +1 -1
  93. package/dist/lib/util/function.js +1 -1
  94. package/dist/lib/util/function.js.map +1 -1
  95. package/dist/lib/util/type.d.ts.map +1 -1
  96. package/dist/oauth-hooks.d.ts +77 -4
  97. package/dist/oauth-hooks.d.ts.map +1 -1
  98. package/dist/oauth-hooks.js.map +1 -1
  99. package/dist/oauth-middleware.js.map +1 -1
  100. package/dist/oauth-provider.d.ts +31 -31
  101. package/dist/oauth-provider.d.ts.map +1 -1
  102. package/dist/oauth-provider.js +15 -9
  103. package/dist/oauth-provider.js.map +1 -1
  104. package/dist/oauth-verifier.d.ts.map +1 -1
  105. package/dist/replay/replay-manager.d.ts.map +1 -1
  106. package/dist/replay/replay-manager.js.map +1 -1
  107. package/dist/replay/replay-store-memory.d.ts.map +1 -1
  108. package/dist/replay/replay-store-redis.d.ts.map +1 -1
  109. package/dist/request/code.d.ts.map +1 -1
  110. package/dist/request/request-data.d.ts +4 -4
  111. package/dist/request/request-data.d.ts.map +1 -1
  112. package/dist/request/request-data.js +1 -1
  113. package/dist/request/request-data.js.map +1 -1
  114. package/dist/request/request-manager.d.ts +32 -32
  115. package/dist/request/request-manager.d.ts.map +1 -1
  116. package/dist/request/request-manager.js +7 -4
  117. package/dist/request/request-manager.js.map +1 -1
  118. package/dist/request/request-store.d.ts +1 -1
  119. package/dist/request/request-store.js +2 -2
  120. package/dist/request/request-store.js.map +1 -1
  121. package/dist/result/authorization-result-authorize-page.d.ts +1 -1
  122. package/dist/result/authorization-result-authorize-page.js.map +1 -1
  123. package/dist/router/assets/assets-manifest.js.map +1 -1
  124. package/dist/router/assets/assets.d.ts +1 -1
  125. package/dist/router/assets/assets.d.ts.map +1 -1
  126. package/dist/router/assets/assets.js.map +1 -1
  127. package/dist/router/assets/send-account-page.d.ts.map +1 -1
  128. package/dist/router/assets/send-authorization-page.d.ts.map +1 -1
  129. package/dist/router/assets/send-authorization-page.js +1 -1
  130. package/dist/router/assets/send-authorization-page.js.map +1 -1
  131. package/dist/router/assets/send-cookie-error-page.d.ts.map +1 -1
  132. package/dist/router/assets/send-error-page.d.ts.map +1 -1
  133. package/dist/router/assets/send-redirect.d.ts +2 -2
  134. package/dist/router/assets/send-redirect.d.ts.map +1 -1
  135. package/dist/router/create-api-middleware.d.ts.map +1 -1
  136. package/dist/router/create-api-middleware.js +87 -51
  137. package/dist/router/create-api-middleware.js.map +1 -1
  138. package/dist/signer/access-token-payload.d.ts +1762 -1762
  139. package/dist/signer/access-token-payload.d.ts.map +1 -1
  140. package/dist/signer/access-token-payload.js +2 -2
  141. package/dist/signer/access-token-payload.js.map +1 -1
  142. package/dist/signer/api-token-payload.d.ts +1738 -1738
  143. package/dist/signer/api-token-payload.d.ts.map +1 -1
  144. package/dist/signer/api-token-payload.js +2 -2
  145. package/dist/signer/api-token-payload.js.map +1 -1
  146. package/dist/signer/signer.d.ts +6 -187
  147. package/dist/signer/signer.d.ts.map +1 -1
  148. package/dist/signer/signer.js.map +1 -1
  149. package/dist/token/refresh-token.d.ts.map +1 -1
  150. package/dist/token/token-claims.d.ts +2 -1
  151. package/dist/token/token-claims.d.ts.map +1 -1
  152. package/dist/token/token-claims.js.map +1 -1
  153. package/dist/token/token-data.d.ts +3 -3
  154. package/dist/token/token-data.d.ts.map +1 -1
  155. package/dist/token/token-data.js.map +1 -1
  156. package/dist/token/token-id.d.ts.map +1 -1
  157. package/dist/token/token-manager.d.ts +3 -3
  158. package/dist/token/token-manager.d.ts.map +1 -1
  159. package/dist/token/token-manager.js +14 -14
  160. package/dist/token/token-manager.js.map +1 -1
  161. package/dist/token/token-store.d.ts +3 -3
  162. package/dist/token/token-store.d.ts.map +1 -1
  163. package/dist/token/token-store.js +3 -3
  164. package/dist/token/token-store.js.map +1 -1
  165. package/dist/types/handle.d.ts +5 -1
  166. package/dist/types/handle.d.ts.map +1 -1
  167. package/dist/types/handle.js +9 -8
  168. package/dist/types/handle.js.map +1 -1
  169. package/package.json +19 -19
  170. package/src/account/account-manager.ts +123 -20
  171. package/src/account/account-store.ts +67 -19
  172. package/src/device/device-store.ts +1 -1
  173. package/src/errors/invalid-credentials-error.ts +8 -8
  174. package/src/lexicon/lexicon-store.ts +1 -1
  175. package/src/lib/util/function.ts +2 -2
  176. package/src/oauth-hooks.ts +85 -3
  177. package/src/oauth-provider.ts +17 -9
  178. package/src/request/request-data.ts +5 -5
  179. package/src/request/request-manager.ts +11 -4
  180. package/src/request/request-store.ts +3 -3
  181. package/src/result/authorization-result-authorize-page.ts +1 -1
  182. package/src/router/assets/send-authorization-page.ts +1 -1
  183. package/src/router/create-api-middleware.ts +128 -67
  184. package/src/signer/access-token-payload.ts +2 -2
  185. package/src/signer/api-token-payload.ts +2 -2
  186. package/src/signer/signer.ts +13 -4
  187. package/src/token/token-claims.ts +2 -1
  188. package/src/token/token-data.ts +3 -3
  189. package/src/token/token-manager.ts +15 -15
  190. package/src/token/token-store.ts +6 -6
  191. package/src/types/handle.ts +21 -16
  192. package/tsconfig.build.tsbuildinfo +1 -1
  193. package/dist/oidc/sub.d.ts +0 -4
  194. package/dist/oidc/sub.d.ts.map +0 -1
  195. package/dist/oidc/sub.js +0 -3
  196. package/dist/oidc/sub.js.map +0 -1
  197. package/src/oidc/sub.ts +0 -4
@@ -1,6 +1,7 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http'
2
2
  import createHttpError from 'http-errors'
3
3
  import { z } from 'zod'
4
+ import { Did, didSchema } from '@atproto/did'
4
5
  import { signedJwtSchema } from '@atproto/jwk'
5
6
  import {
6
7
  API_ENDPOINT_PREFIX,
@@ -16,6 +17,7 @@ import {
16
17
  OAuthResponseMode,
17
18
  oauthRedirectUriSchema,
18
19
  oauthResponseModeSchema,
20
+ oauthScopeSchema,
19
21
  } from '@atproto/oauth-types'
20
22
  import { signInDataSchema } from '../account/sign-in-data.js'
21
23
  import { signUpInputSchema } from '../account/sign-up-input.js'
@@ -49,14 +51,13 @@ import { asArray } from '../lib/util/cast.js'
49
51
  import { localeSchema } from '../lib/util/locale.js'
50
52
  import type { Awaitable } from '../lib/util/type.js'
51
53
  import type { OAuthProvider } from '../oauth-provider.js'
52
- import { Sub, subSchema } from '../oidc/sub.js'
53
54
  import { RequestUri, requestUriSchema } from '../request/request-uri.js'
54
55
  import { AuthorizationRedirectParameters } from '../result/authorization-redirect-parameters.js'
55
56
  import { tokenIdSchema } from '../token/token-id.js'
56
57
  import { emailOtpSchema } from '../types/email-otp.js'
57
58
  import { emailSchema } from '../types/email.js'
58
59
  import { handleSchema } from '../types/handle.js'
59
- import { newPasswordSchema } from '../types/password.js'
60
+ import { newPasswordSchema, oldPasswordSchema } from '../types/password.js'
60
61
  import { validateCsrfToken } from './assets/csrf.js'
61
62
  import {
62
63
  ERROR_REDIRECT_KEYS,
@@ -69,8 +70,6 @@ import {
69
70
  } from './assets/send-redirect.js'
70
71
  import type { MiddlewareOptions } from './middleware-options.js'
71
72
 
72
- const verifyHandleSchema = z.object({ handle: handleSchema }).strict()
73
-
74
73
  export function createApiMiddleware<
75
74
  Ctx extends object | void = void,
76
75
  Req extends IncomingMessage = IncomingMessage,
@@ -87,7 +86,7 @@ export function createApiMiddleware<
87
86
  apiRoute({
88
87
  method: 'POST',
89
88
  endpoint: '/verify-handle-availability',
90
- schema: verifyHandleSchema,
89
+ schema: z.object({ handle: handleSchema }).strict(),
91
90
  async handler() {
92
91
  await server.accountManager.verifyHandleAvailability(this.input.handle)
93
92
  return { json: { available: true } }
@@ -116,13 +115,13 @@ export function createApiMiddleware<
116
115
  // Only "remember" the newly created account if it was not created during an
117
116
  // OAuth flow.
118
117
  if (remember) {
119
- await server.accountManager.upsertDeviceAccount(deviceId, account.sub)
118
+ await server.accountManager.upsertDeviceAccount(deviceId, account.did)
120
119
  }
121
120
 
122
121
  const ephemeralToken = remember
123
122
  ? undefined
124
123
  : await server.signer.createEphemeralToken({
125
- sub: account.sub,
124
+ sub: account.did,
126
125
  deviceId,
127
126
  requestUri: this.requestUri,
128
127
  })
@@ -159,46 +158,21 @@ export function createApiMiddleware<
159
158
  )
160
159
 
161
160
  if (remember) {
162
- await server.accountManager.upsertDeviceAccount(deviceId, account.sub)
161
+ await server.accountManager.upsertDeviceAccount(deviceId, account.did)
163
162
  } else {
164
163
  // In case the user was already signed in, and signed in again, this
165
164
  // time without "remember me", let's sign them off of the device.
166
- await server.accountManager.removeDeviceAccount(deviceId, account.sub)
165
+ await server.accountManager.removeDeviceAccount(deviceId, account.did)
167
166
  }
168
167
 
169
168
  const ephemeralToken = remember
170
169
  ? undefined
171
170
  : await server.signer.createEphemeralToken({
172
- sub: account.sub,
171
+ sub: account.did,
173
172
  deviceId,
174
173
  requestUri,
175
174
  })
176
175
 
177
- if (requestUri) {
178
- // Check if a consent is required for the client, but only if this
179
- // call is made within the context of an oauth request.
180
-
181
- const { clientId, parameters } = await server.requestManager.get(
182
- requestUri,
183
- deviceId,
184
- )
185
-
186
- const { authorizedClients } = await server.accountManager.getAccount(
187
- account.sub,
188
- )
189
-
190
- const json = {
191
- account,
192
- ephemeralToken,
193
- consentRequired: server.checkConsentRequired(
194
- parameters,
195
- authorizedClients.get(clientId),
196
- ),
197
- }
198
-
199
- return { json }
200
- }
201
-
202
176
  const json = { account, ephemeralToken }
203
177
  return { json }
204
178
  },
@@ -211,12 +185,12 @@ export function createApiMiddleware<
211
185
  endpoint: '/sign-out',
212
186
  schema: z
213
187
  .object({
214
- sub: z.union([subSchema, z.array(subSchema)]),
188
+ did: z.union([didSchema, z.array(didSchema)]),
215
189
  })
216
190
  .strict(),
217
191
  rotateDeviceCookies: true,
218
192
  async handler() {
219
- const uniqueSubs = new Set(asArray(this.input.sub))
193
+ const uniqueSubs = new Set(asArray(this.input.did))
220
194
 
221
195
  for (const sub of uniqueSubs) {
222
196
  await server.accountManager.removeDeviceAccount(this.deviceId, sub)
@@ -275,7 +249,7 @@ export function createApiMiddleware<
275
249
  endpoint: '/update-email-request',
276
250
  schema: z
277
251
  .object({
278
- sub: subSchema,
252
+ did: didSchema,
279
253
  locale: localeSchema.optional(),
280
254
  })
281
255
  .strict(),
@@ -301,23 +275,23 @@ export function createApiMiddleware<
301
275
  endpoint: '/update-email-confirm',
302
276
  schema: z
303
277
  .object({
304
- sub: subSchema,
278
+ did: didSchema,
305
279
  email: emailSchema,
306
280
  token: emailOtpSchema.optional(),
307
281
  locale: localeSchema.optional(),
308
282
  })
309
283
  .strict(),
310
284
  async handler(req, res) {
311
- const { account } = await authenticate.call(this, req, res)
285
+ let { account } = await authenticate.call(this, req, res)
312
286
 
313
- await server.accountManager.updateEmailConfirm(
287
+ account = await server.accountManager.updateEmailConfirm(
314
288
  this.deviceId,
315
289
  this.deviceMetadata,
316
290
  this.input,
317
291
  account,
318
292
  )
319
293
 
320
- return { json: { success: true } }
294
+ return { json: { account } }
321
295
  },
322
296
  }),
323
297
  )
@@ -328,7 +302,7 @@ export function createApiMiddleware<
328
302
  endpoint: '/verify-email-request',
329
303
  schema: z
330
304
  .object({
331
- sub: subSchema,
305
+ did: didSchema,
332
306
  locale: localeSchema.optional(),
333
307
  })
334
308
  .strict(),
@@ -353,22 +327,22 @@ export function createApiMiddleware<
353
327
  endpoint: '/verify-email-confirm',
354
328
  schema: z
355
329
  .object({
356
- sub: subSchema,
330
+ did: didSchema,
357
331
  token: emailOtpSchema,
358
332
  email: emailSchema,
359
333
  })
360
334
  .strict(),
361
335
  async handler(req, res) {
362
- const { account } = await authenticate.call(this, req, res)
336
+ let { account } = await authenticate.call(this, req, res)
363
337
 
364
- await server.accountManager.verifyEmailConfirm(
338
+ account = await server.accountManager.verifyEmailConfirm(
365
339
  this.deviceId,
366
340
  this.deviceMetadata,
367
341
  this.input,
368
342
  account,
369
343
  )
370
344
 
371
- return { json: { success: true } }
345
+ return { json: { account } }
372
346
  },
373
347
  }),
374
348
  )
@@ -379,14 +353,104 @@ export function createApiMiddleware<
379
353
  endpoint: '/update-handle',
380
354
  schema: z
381
355
  .object({
382
- sub: subSchema,
356
+ did: didSchema,
383
357
  handle: handleSchema,
384
358
  })
385
359
  .strict(),
360
+ async handler(req, res) {
361
+ let { account } = await authenticate.call(this, req, res)
362
+
363
+ account = await server.accountManager.updateHandle(
364
+ this.deviceId,
365
+ this.deviceMetadata,
366
+ this.input,
367
+ account,
368
+ )
369
+
370
+ return { json: { account } }
371
+ },
372
+ }),
373
+ )
374
+
375
+ router.use(
376
+ apiRoute({
377
+ method: 'POST',
378
+ endpoint: '/deactivate-account',
379
+ schema: z.object({ did: didSchema }).strict(),
380
+ async handler(req, res) {
381
+ let { account } = await authenticate.call(this, req, res)
382
+
383
+ if (!account.deactivated) {
384
+ account = await server.accountManager.deactivateAccount(
385
+ this.deviceId,
386
+ this.deviceMetadata,
387
+ account,
388
+ )
389
+ }
390
+
391
+ return { json: { account } }
392
+ },
393
+ }),
394
+ )
395
+
396
+ router.use(
397
+ apiRoute({
398
+ method: 'POST',
399
+ endpoint: '/reactivate-account',
400
+ schema: z.object({ did: didSchema }).strict(),
401
+ async handler(req, res) {
402
+ let { account } = await authenticate.call(this, req, res)
403
+
404
+ if (account.deactivated) {
405
+ account = await server.accountManager.reactivateAccount(
406
+ this.deviceId,
407
+ this.deviceMetadata,
408
+ account,
409
+ )
410
+ }
411
+
412
+ return { json: { account } }
413
+ },
414
+ }),
415
+ )
416
+
417
+ router.use(
418
+ apiRoute({
419
+ method: 'POST',
420
+ endpoint: '/delete-account-request',
421
+ schema: z
422
+ .object({ did: didSchema, locale: localeSchema.optional() })
423
+ .strict(),
424
+ async handler(req, res) {
425
+ const { account } = await authenticate.call(this, req, res)
426
+
427
+ await server.accountManager.deleteAccountRequest(
428
+ this.deviceId,
429
+ this.deviceMetadata,
430
+ this.input,
431
+ account,
432
+ )
433
+
434
+ return { json: { success: true } }
435
+ },
436
+ }),
437
+ )
438
+
439
+ router.use(
440
+ apiRoute({
441
+ method: 'POST',
442
+ endpoint: '/delete-account-confirm',
443
+ schema: z
444
+ .object({
445
+ did: didSchema,
446
+ token: emailOtpSchema,
447
+ password: oldPasswordSchema,
448
+ })
449
+ .strict(),
386
450
  async handler(req, res) {
387
451
  const { account } = await authenticate.call(this, req, res)
388
452
 
389
- await server.accountManager.updateHandle(
453
+ await server.accountManager.deleteAccountConfirm(
390
454
  this.deviceId,
391
455
  this.deviceMetadata,
392
456
  this.input,
@@ -424,12 +488,12 @@ export function createApiMiddleware<
424
488
  apiRoute({
425
489
  method: 'GET',
426
490
  endpoint: '/oauth-sessions',
427
- schema: z.object({ sub: subSchema }).strict(),
491
+ schema: z.object({ did: didSchema }).strict(),
428
492
  async handler(req, res) {
429
493
  const { account } = await authenticate.call(this, req, res)
430
494
 
431
495
  const tokenInfos = await server.tokenManager.listAccountTokens(
432
- account.sub,
496
+ account.did,
433
497
  )
434
498
 
435
499
  const clientIds = tokenInfos.map((tokenInfo) => tokenInfo.data.clientId)
@@ -468,12 +532,12 @@ export function createApiMiddleware<
468
532
  apiRoute({
469
533
  method: 'GET',
470
534
  endpoint: '/account-sessions',
471
- schema: z.object({ sub: subSchema }).strict(),
535
+ schema: z.object({ did: didSchema }).strict(),
472
536
  async handler(req, res) {
473
537
  const { account } = await authenticate.call(this, req, res)
474
538
 
475
539
  const deviceAccounts = await server.accountManager.listAccountDevices(
476
- account.sub,
540
+ account.did,
477
541
  )
478
542
 
479
543
  const json = deviceAccounts.map(
@@ -499,7 +563,7 @@ export function createApiMiddleware<
499
563
  apiRoute({
500
564
  method: 'POST',
501
565
  endpoint: '/revoke-account-session',
502
- schema: z.object({ sub: subSchema, deviceId: deviceIdSchema }).strict(),
566
+ schema: z.object({ did: didSchema, deviceId: deviceIdSchema }).strict(),
503
567
  async handler() {
504
568
  // @NOTE This route is not authenticated. If a user is able to steal
505
569
  // another user's session cookie, we allow them to revoke the device
@@ -507,7 +571,7 @@ export function createApiMiddleware<
507
571
 
508
572
  await server.accountManager.removeDeviceAccount(
509
573
  this.input.deviceId,
510
- this.input.sub,
574
+ this.input.did,
511
575
  )
512
576
 
513
577
  return { json: { success: true } }
@@ -519,7 +583,7 @@ export function createApiMiddleware<
519
583
  apiRoute({
520
584
  method: 'POST',
521
585
  endpoint: '/revoke-oauth-session',
522
- schema: z.object({ sub: subSchema, tokenId: tokenIdSchema }).strict(),
586
+ schema: z.object({ did: didSchema, tokenId: tokenIdSchema }).strict(),
523
587
  async handler(req, res) {
524
588
  const { account } = await authenticate.call(this, req, res)
525
589
 
@@ -527,7 +591,7 @@ export function createApiMiddleware<
527
591
  this.input.tokenId,
528
592
  )
529
593
 
530
- if (!tokenInfo || tokenInfo.account.sub !== account.sub) {
594
+ if (!tokenInfo || tokenInfo.account.did !== account.did) {
531
595
  // report this as though the token was not found
532
596
  throw new InvalidRequestError(`Invalid token`)
533
597
  }
@@ -544,10 +608,7 @@ export function createApiMiddleware<
544
608
  method: 'POST',
545
609
  endpoint: '/consent',
546
610
  schema: z
547
- .object({
548
- sub: z.union([subSchema, signedJwtSchema]),
549
- scope: z.string().optional(),
550
- })
611
+ .object({ did: didSchema, scope: oauthScopeSchema.optional() })
551
612
  .strict(),
552
613
  async handler(req, res) {
553
614
  if (!this.requestUri) {
@@ -710,7 +771,7 @@ export function createApiMiddleware<
710
771
  return router.buildMiddleware()
711
772
 
712
773
  async function authenticate(
713
- this: ApiContext<void, { sub: Sub }>,
774
+ this: ApiContext<void, { did: Did }>,
714
775
  req: Req,
715
776
  _res: Res,
716
777
  ) {
@@ -724,7 +785,7 @@ export function createApiMiddleware<
724
785
  await server.signer.verifyEphemeralToken(ephemeralToken)
725
786
 
726
787
  if (
727
- payload.sub === this.input.sub &&
788
+ payload.sub === this.input.did &&
728
789
  payload.deviceId === this.deviceId &&
729
790
  payload.requestUri === this.requestUri
730
791
  ) {
@@ -744,7 +805,7 @@ export function createApiMiddleware<
744
805
  // Ensures the "sub" has an active session on the device
745
806
  const deviceAccount = await server.accountManager.getDeviceAccount(
746
807
  this.deviceId,
747
- this.input.sub,
808
+ this.input.did,
748
809
  )
749
810
 
750
811
  // The session exists but was created too long ago
@@ -756,7 +817,7 @@ export function createApiMiddleware<
756
817
  } catch (err) {
757
818
  throw new WWWAuthenticateError(
758
819
  'unauthorized',
759
- `User ${this.input.sub} not authenticated on this device`,
820
+ `User ${this.input.did} not authenticated on this device`,
760
821
  { Bearer: {} },
761
822
  err,
762
823
  )
@@ -803,9 +864,9 @@ export function createApiMiddleware<
803
864
  }[keyof ApiEndpoints],
804
865
  S extends // A schema that validates the POST input or GET params
805
866
  ApiEndpoints[E] extends { method: 'POST'; input: infer I }
806
- ? z.ZodType<I>
867
+ ? z.ZodType<I, z.ZodTypeDef, unknown>
807
868
  : ApiEndpoints[E] extends { method: 'GET'; params: infer P }
808
- ? z.ZodType<P>
869
+ ? z.ZodType<P, z.ZodTypeDef, unknown>
809
870
  : void,
810
871
  >(options: {
811
872
  method: M
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod'
2
+ import { didSchema } from '@atproto/did'
2
3
  import { jwtPayloadSchema } from '@atproto/jwk'
3
4
  import { clientIdSchema } from '../client/client-id.js'
4
- import { subSchema } from '../oidc/sub.js'
5
5
  import { tokenIdSchema } from '../token/token-id.js'
6
6
 
7
7
  export const accessTokenPayloadSchema = jwtPayloadSchema
@@ -9,7 +9,7 @@ export const accessTokenPayloadSchema = jwtPayloadSchema
9
9
  .extend({
10
10
  // Following are required
11
11
  jti: tokenIdSchema,
12
- sub: subSchema,
12
+ sub: didSchema,
13
13
  exp: z.number().int(),
14
14
  iat: z.number().int(),
15
15
  iss: z.string().min(1),
@@ -1,12 +1,12 @@
1
1
  import { z } from 'zod'
2
+ import { didSchema } from '@atproto/did'
2
3
  import { jwtPayloadSchema } from '@atproto/jwk'
3
4
  import { deviceIdSchema } from '../oauth-store.js'
4
- import { subSchema } from '../oidc/sub.js'
5
5
  import { requestUriSchema } from '../request/request-uri.js'
6
6
 
7
7
  export const apiTokenPayloadSchema = jwtPayloadSchema
8
8
  .extend({
9
- sub: subSchema,
9
+ sub: didSchema,
10
10
 
11
11
  deviceId: deviceIdSchema,
12
12
  // If the token is bound to a particular authorization request, it can only
@@ -1,10 +1,13 @@
1
1
  import {
2
+ JwtHeader,
2
3
  JwtPayload,
3
4
  JwtPayloadGetter,
4
5
  JwtSignHeader,
6
+ Key,
5
7
  Keyset,
6
8
  SignedJwt,
7
9
  VerifyOptions,
10
+ VerifyResult,
8
11
  } from '@atproto/jwk'
9
12
  import { EPHEMERAL_SESSION_MAX_AGE } from '../constants.js'
10
13
  import { dateToEpoch } from '../lib/util/date.js'
@@ -29,7 +32,7 @@ export class Signer {
29
32
  async verify<C extends string = never>(
30
33
  token: SignedJwt,
31
34
  options?: Omit<VerifyOptions<C>, 'issuer'>,
32
- ) {
35
+ ): Promise<VerifyResult<C> & { key: Key }> {
33
36
  return this.keyset.verifyJwt<C>(token, {
34
37
  ...options,
35
38
  issuer: [this.issuer],
@@ -64,7 +67,10 @@ export class Signer {
64
67
  async verifyAccessToken<C extends string = never>(
65
68
  token: SignedJwt,
66
69
  options?: Omit<VerifyOptions<C>, 'issuer' | 'typ'>,
67
- ) {
70
+ ): Promise<{
71
+ protectedHeader: JwtHeader
72
+ payload: RequiredKey<AccessTokenPayload, C>
73
+ }> {
68
74
  const result = await this.verify<C>(token, { ...options, typ: 'at+jwt' })
69
75
  return {
70
76
  protectedHeader: result.protectedHeader,
@@ -77,7 +83,7 @@ export class Signer {
77
83
 
78
84
  async createEphemeralToken(
79
85
  payload: OmitKey<ApiTokenPayload, 'iss' | 'aud' | 'iat'>,
80
- ) {
86
+ ): Promise<SignedJwt> {
81
87
  return this.sign(
82
88
  {
83
89
  alg: undefined,
@@ -94,7 +100,10 @@ export class Signer {
94
100
  async verifyEphemeralToken<C extends string = never>(
95
101
  token: SignedJwt,
96
102
  options?: Omit<VerifyOptions<C>, 'issuer' | 'audience' | 'typ'>,
97
- ) {
103
+ ): Promise<{
104
+ protectedHeader: JwtHeader
105
+ payload: RequiredKey<ApiTokenPayload, C>
106
+ }> {
98
107
  const result = await this.verify<C>(token, {
99
108
  ...options,
100
109
  maxTokenAge: options?.maxTokenAge ?? EPHEMERAL_SESSION_MAX_AGE / 1e3,
@@ -1,3 +1,4 @@
1
+ import { Did } from '@atproto/did'
1
2
  import { OAuthScope } from '@atproto/oauth-types'
2
3
  import { ClientId } from '../client/client-id.js'
3
4
  import { TokenId } from './token-id.js'
@@ -11,7 +12,7 @@ import { TokenId } from './token-id.js'
11
12
  */
12
13
  export type TokenClaims = {
13
14
  jti: TokenId
14
- sub: string
15
+ sub: Did
15
16
  iat: number
16
17
  exp: number
17
18
  aud: string | [string, ...string[]]
@@ -1,3 +1,4 @@
1
+ import { Did } from '@atproto/did'
1
2
  import {
2
3
  OAuthAuthorizationDetails,
3
4
  OAuthAuthorizationRequestParameters,
@@ -5,7 +6,6 @@ import {
5
6
  import { ClientAuth, ClientAuthLegacy } from '../client/client-auth.js'
6
7
  import { ClientId } from '../client/client-id.js'
7
8
  import { DeviceId } from '../device/device-id.js'
8
- import { Sub } from '../oidc/sub.js'
9
9
  import { Code } from '../request/code.js'
10
10
 
11
11
  export type {
@@ -13,9 +13,9 @@ export type {
13
13
  ClientId,
14
14
  Code,
15
15
  DeviceId,
16
+ Did,
16
17
  OAuthAuthorizationDetails,
17
18
  OAuthAuthorizationRequestParameters,
18
- Sub,
19
19
  }
20
20
 
21
21
  export type TokenData = {
@@ -25,7 +25,7 @@ export type TokenData = {
25
25
  clientId: ClientId
26
26
  clientAuth: ClientAuth | ClientAuthLegacy
27
27
  deviceId: DeviceId | null
28
- sub: Sub
28
+ did: Did
29
29
  parameters: OAuthAuthorizationRequestParameters
30
30
  details?: null // Legacy field, not used
31
31
  code: Code | null
@@ -1,3 +1,4 @@
1
+ import type { Did } from '@atproto/did'
1
2
  import { SignedJwt, isSignedJwt } from '@atproto/jwk'
2
3
  import { LexResolverError } from '@atproto/lex-resolver'
3
4
  import type { Account } from '@atproto/oauth-provider-api'
@@ -20,7 +21,6 @@ import { LexiconManager } from '../lexicon/lexicon-manager.js'
20
21
  import { RequestMetadata } from '../lib/http/request.js'
21
22
  import { dateToEpoch, dateToRelativeSeconds } from '../lib/util/date.js'
22
23
  import { OAuthHooks } from '../oauth-hooks.js'
23
- import { Sub } from '../oidc/sub.js'
24
24
  import { Code, isCode } from '../request/code.js'
25
25
  import { AccessTokenPayload } from '../signer/access-token-payload.js'
26
26
  import { Signer } from '../signer/signer.js'
@@ -61,10 +61,10 @@ export class TokenManager {
61
61
  ): Promise<OAuthAccessToken> {
62
62
  const claims: TokenClaims = {
63
63
  jti: tokenId,
64
- sub: account.sub,
64
+ sub: account.did,
65
65
  iat: dateToEpoch(issuedAt),
66
66
  exp: dateToEpoch(expiresAt),
67
- aud: account.aud,
67
+ aud: account.pds,
68
68
 
69
69
  ...(parameters.dpop_jkt && {
70
70
  cnf: { jkt: parameters.dpop_jkt },
@@ -136,7 +136,7 @@ export class TokenManager {
136
136
  accessToken,
137
137
  refreshToken,
138
138
  expiresAt,
139
- account.sub,
139
+ account.did,
140
140
  scope,
141
141
  )
142
142
 
@@ -147,7 +147,7 @@ export class TokenManager {
147
147
  clientId: client.id,
148
148
  clientAuth,
149
149
  deviceId,
150
- sub: account.sub,
150
+ did: account.did,
151
151
  parameters,
152
152
  details: null,
153
153
  scope,
@@ -191,7 +191,7 @@ export class TokenManager {
191
191
  accessToken: OAuthAccessToken,
192
192
  refreshToken: string | undefined,
193
193
  expiresAt: Date,
194
- sub: Sub,
194
+ did: Did,
195
195
  scope: string,
196
196
  ): OAuthTokenResponse {
197
197
  return {
@@ -209,7 +209,7 @@ export class TokenManager {
209
209
  // ATPROTO extension: add the sub claim to the token response to allow
210
210
  // clients to resolve the PDS url (audience) using the did resolution
211
211
  // mechanism.
212
- sub,
212
+ sub: did,
213
213
  }
214
214
  }
215
215
 
@@ -263,7 +263,7 @@ export class TokenManager {
263
263
  accessToken,
264
264
  nextRefreshToken,
265
265
  expiresAt,
266
- account.sub,
266
+ account.did,
267
267
  scope,
268
268
  )
269
269
 
@@ -305,10 +305,10 @@ export class TokenManager {
305
305
  if (!tokenInfo) return null
306
306
 
307
307
  // Fool-proof: Invalid store implementation ?
308
- if (payload.sub !== tokenInfo.account.sub) {
308
+ if (payload.sub !== tokenInfo.account.did) {
309
309
  await this.deleteToken(tokenInfo.id)
310
310
  throw new Error(
311
- `Account sub (${tokenInfo.account.sub}) does not match token sub (${payload.sub})`,
311
+ `Account sub (${tokenInfo.account.did}) does not match token sub (${payload.sub})`,
312
312
  )
313
313
  }
314
314
 
@@ -395,20 +395,20 @@ export class TokenManager {
395
395
 
396
396
  return {
397
397
  jti: tokenId,
398
- sub: account.sub,
398
+ sub: account.did,
399
399
  iat: dateToEpoch(data.updatedAt),
400
400
  exp: dateToEpoch(data.expiresAt),
401
- aud: account.aud,
401
+ aud: account.pds,
402
402
  scope: data.scope ?? data.parameters.scope,
403
403
  // https://datatracker.ietf.org/doc/html/rfc8693#section-4.3
404
404
  client_id: data.clientId,
405
405
  }
406
406
  }
407
407
 
408
- async listAccountTokens(sub: Sub): Promise<TokenInfo[]> {
409
- const results = await this.store.listAccountTokens(sub)
408
+ async listAccountTokens(did: Did): Promise<TokenInfo[]> {
409
+ const results = await this.store.listAccountTokens(did)
410
410
  return results
411
- .filter((tokenInfo) => tokenInfo.account.sub === sub) // Fool proof
411
+ .filter((tokenInfo) => tokenInfo.account.did === did) // Fool proof
412
412
  .filter((tokenInfo) => !isCurrentTokenExpired(tokenInfo))
413
413
  }
414
414
  }