@atproto/oauth-provider 0.15.16 → 0.16.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 (54) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/account/account-store.d.ts +1 -1
  3. package/dist/account/account-store.d.ts.map +1 -1
  4. package/dist/account/account-store.js.map +1 -1
  5. package/dist/customization/branding.d.ts +18 -1
  6. package/dist/customization/branding.d.ts.map +1 -1
  7. package/dist/customization/build-customization-css.d.ts.map +1 -1
  8. package/dist/customization/build-customization-css.js +16 -2
  9. package/dist/customization/build-customization-css.js.map +1 -1
  10. package/dist/customization/build-customization-data.d.ts +2 -2
  11. package/dist/customization/build-customization-data.d.ts.map +1 -1
  12. package/dist/customization/build-customization-data.js.map +1 -1
  13. package/dist/customization/colors.d.ts +11 -2
  14. package/dist/customization/colors.d.ts.map +1 -1
  15. package/dist/customization/colors.js +19 -1
  16. package/dist/customization/colors.js.map +1 -1
  17. package/dist/customization/customization.d.ts +26 -1
  18. package/dist/customization/customization.d.ts.map +1 -1
  19. package/dist/lib/http/router.d.ts +2 -1
  20. package/dist/lib/http/router.d.ts.map +1 -1
  21. package/dist/lib/http/router.js +1 -1
  22. package/dist/lib/http/router.js.map +1 -1
  23. package/dist/lib/util/color.d.ts +3 -0
  24. package/dist/lib/util/color.d.ts.map +1 -1
  25. package/dist/lib/util/color.js +33 -1
  26. package/dist/lib/util/color.js.map +1 -1
  27. package/dist/oauth-provider.d.ts.map +1 -1
  28. package/dist/oauth-provider.js +6 -11
  29. package/dist/oauth-provider.js.map +1 -1
  30. package/dist/result/authorization-result-authorize-page.d.ts +2 -1
  31. package/dist/result/authorization-result-authorize-page.d.ts.map +1 -1
  32. package/dist/result/authorization-result-authorize-page.js.map +1 -1
  33. package/dist/router/assets/assets.d.ts +1 -2
  34. package/dist/router/assets/assets.d.ts.map +1 -1
  35. package/dist/router/assets/assets.js +20 -12
  36. package/dist/router/assets/assets.js.map +1 -1
  37. package/dist/router/assets/send-authorization-page.d.ts.map +1 -1
  38. package/dist/router/assets/send-authorization-page.js +1 -0
  39. package/dist/router/assets/send-authorization-page.js.map +1 -1
  40. package/dist/router/create-api-middleware.d.ts.map +1 -1
  41. package/dist/router/create-api-middleware.js +5 -6
  42. package/dist/router/create-api-middleware.js.map +1 -1
  43. package/package.json +7 -8
  44. package/src/account/account-store.ts +1 -1
  45. package/src/customization/build-customization-css.ts +25 -3
  46. package/src/customization/build-customization-data.ts +2 -2
  47. package/src/customization/colors.ts +20 -1
  48. package/src/lib/http/router.ts +7 -3
  49. package/src/lib/util/color.ts +37 -1
  50. package/src/oauth-provider.ts +7 -13
  51. package/src/result/authorization-result-authorize-page.ts +2 -1
  52. package/src/router/assets/assets.ts +22 -17
  53. package/src/router/assets/send-authorization-page.ts +1 -0
  54. package/src/router/create-api-middleware.ts +10 -6
@@ -1,5 +1,4 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http'
2
- import type { HydrationData as FeHydrationData } from '@atproto/oauth-provider-frontend/hydration-data'
3
2
  import type { HydrationData as UiHydrationData } from '@atproto/oauth-provider-ui/hydration-data'
4
3
  import { buildCustomizationCss } from '../../customization/build-customization-css.js'
5
4
  import { buildCustomizationData } from '../../customization/build-customization-data.js'
@@ -7,7 +6,6 @@ import { Customization } from '../../customization/customization.js'
7
6
  import { CspConfig, mergeCsp } from '../../lib/csp/index.js'
8
7
  import { declareHydrationData } from '../../lib/html/hydration-data.js'
9
8
  import { cssCode, html } from '../../lib/html/index.js'
10
- import { combineMiddlewares } from '../../lib/http/middleware.js'
11
9
  import { WriteResponseOptions } from '../../lib/http/response.js'
12
10
  import {
13
11
  CrossOriginEmbedderPolicy,
@@ -29,24 +27,18 @@ import { setupCsrfToken } from './csrf.js'
29
27
  const ui = parseAssetsManifest(
30
28
  require.resolve('@atproto/oauth-provider-ui/bundle-manifest.json'),
31
29
  )
32
- const fe = parseAssetsManifest(
33
- require.resolve('@atproto/oauth-provider-frontend/bundle-manifest.json'),
34
- )
35
30
 
36
- type HydrationData = Simplify<UiHydrationData & FeHydrationData>
31
+ type HydrationData = Simplify<UiHydrationData>
37
32
 
38
33
  function getAssets(entryName: keyof HydrationData) {
39
- const assetRef = ui.getAssets(entryName) || fe.getAssets(entryName)
34
+ const assetRef = ui.getAssets(entryName)
40
35
  if (assetRef) return assetRef
41
36
 
42
37
  // Fool-proof. Should never happen.
43
38
  throw new Error(`Entry "${entryName}" not found in assets`)
44
39
  }
45
40
 
46
- export const assetsMiddleware = combineMiddlewares([
47
- ui.assetsMiddleware,
48
- fe.assetsMiddleware,
49
- ])
41
+ export const assetsMiddleware = ui.assetsMiddleware
50
42
 
51
43
  const SPA_CSP: CspConfig = {
52
44
  // API calls are made to the same origin
@@ -81,9 +73,25 @@ export function sendWebAppFactory<P extends keyof HydrationData>(
81
73
 
82
74
  const csp = mergeCsp(
83
75
  SPA_CSP,
84
- customization?.hcaptcha ? HCAPTCHA_CSP : undefined,
76
+ customization.hcaptcha ? HCAPTCHA_CSP : undefined,
85
77
  )
86
78
 
79
+ const coep = customization.hcaptcha
80
+ ? // hCaptcha's implementation of COEP is currently broken. Let's disable it
81
+ // to avoid breaking the entire page.
82
+ //
83
+ // https://github.com/hCaptcha/react-hcaptcha/issues/259
84
+ // https://github.com/hCaptcha/react-hcaptcha/issues/380
85
+ CrossOriginEmbedderPolicy.unsafeNone
86
+ : // Since we are loading avatars form other origins, which might not have
87
+ // CORP headers, we need to use the "credentialless" value, which allows
88
+ // loading cross-origin resources without credentials (cookies, client
89
+ // certificates, etc.). This is a more secure alternative to
90
+ // "unsafe-none". Ideally, we would want to set COEP to "require-corp" and
91
+ // ensure that all cross-origin resources have the appropriate CORP
92
+ // headers.
93
+ CrossOriginEmbedderPolicy.credentialless
94
+
87
95
  return async function sendWebApp(
88
96
  req: IncomingMessage,
89
97
  res: ServerResponse,
@@ -101,12 +109,9 @@ export function sendWebAppFactory<P extends keyof HydrationData>(
101
109
  return writeHtml(
102
110
  res,
103
111
  mergeDefaults<WriteHtmlOptions>(defaults, options, {
104
- bodyAttrs: {
105
- class:
106
- 'bg-white text-slate-900 dark:bg-slate-900 dark:text-slate-100',
107
- },
112
+ bodyAttrs: { class: 'text-text-default bg-contrast-0' },
108
113
  csp: options?.csp ? mergeCsp(csp, options.csp) : csp,
109
- coep: options?.coep ?? CrossOriginEmbedderPolicy.credentialless,
114
+ coep: options?.coep ?? coep,
110
115
  meta: [{ name: 'robots', content: 'noindex' }],
111
116
  body: html`<div id="root"></div>`,
112
117
  scripts: [script, ...scripts],
@@ -33,6 +33,7 @@ export function sendAuthorizePageFactory(
33
33
  loginHint: data.parameters.login_hint,
34
34
  promptMode: data.parameters.prompt,
35
35
  permissionSets: Object.fromEntries(data.permissionSets),
36
+ selectedSub: data.selectedSub,
36
37
  },
37
38
  __sessions: data.sessions,
38
39
  },
@@ -576,14 +576,14 @@ export function createApiMiddleware<
576
576
  async function authenticate(
577
577
  this: ApiContext<void, { sub: Sub }>,
578
578
  req: Req,
579
- res: Res,
579
+ _res: Res,
580
580
  ) {
581
- const authorization = req.headers.authorization?.split(' ')
582
- if (authorization?.[0].toLowerCase() === 'bearer') {
581
+ if (req.headers.authorization?.startsWith('Bearer ')) {
583
582
  try {
584
583
  // If there is an authorization header, verify that the ephemeral token it
585
584
  // contains is a jwt bound to the right [sub, device, request].
586
- const ephemeralToken = signedJwtSchema.parse(authorization[1])
585
+ const bearer = req.headers.authorization.slice(7)
586
+ const ephemeralToken = signedJwtSchema.parse(bearer)
587
587
  const { payload } =
588
588
  await server.signer.verifyEphemeralToken(ephemeralToken)
589
589
 
@@ -595,8 +595,12 @@ export function createApiMiddleware<
595
595
  return await server.accountManager.getAccount(payload.sub)
596
596
  }
597
597
  } catch (err) {
598
- onError?.(req, res, err, 'Failed to authenticate ephemeral token')
599
- // Fall back to session based authentication
598
+ throw new WWWAuthenticateError(
599
+ 'unauthorized',
600
+ `Invalid or expired bearer token`,
601
+ { Bearer: {} },
602
+ err,
603
+ )
600
604
  }
601
605
  }
602
606