From 6266817afdcee87b8d781e1350b59df1f160668d Mon Sep 17 00:00:00 2001 From: JP Hastings-Spital Date: Mon, 1 Jun 2026 12:06:58 +0200 Subject: [PATCH 1/2] fix(pds): allow Authorization header in CORS preflight The CORS middleware advertised `Access-Control-Allow-Headers: *`, but `*` wildcard does not cover the `Authorization` header. Authenticated cross-origin XRPC calls from web clients (e.g. PDS Moover's getRepoStatus) were being blocked at preflight. Lists the allowed headers explicitly instead. --- .changeset/cors-authorization-header.md | 7 +++++++ packages/pds/src/index.ts | 11 ++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 .changeset/cors-authorization-header.md diff --git a/.changeset/cors-authorization-header.md b/.changeset/cors-authorization-header.md new file mode 100644 index 00000000..9454574d --- /dev/null +++ b/.changeset/cors-authorization-header.md @@ -0,0 +1,7 @@ +--- +"@getcirrus/pds": patch +--- + +Be explicit with CORS headers so browser-based authenticated XRPC calls work (particularly PDS Moover). + +The CORS middleware advertised `Access-Control-Allow-Headers: *`, but the Fetch spec calls out that `*` wildcard does not cover the `Authorization` header — browsers require it to be named explicitly. As a result, authed cross-origin requests from web clients (eg. PDS Moover's `com.pdsmoover.backup.getRepoStatus`) were blocked at preflight. As `*` can't be used with other headers, all allowed headers are now listed explicitly. diff --git a/packages/pds/src/index.ts b/packages/pds/src/index.ts index afebf08b..184afd71 100644 --- a/packages/pds/src/index.ts +++ b/packages/pds/src/index.ts @@ -84,7 +84,16 @@ app.use( cors({ origin: "*", allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], - allowHeaders: ["*"], + // `Authorization` must be listed explicitly: a `*` wildcard in + // Access-Control-Allow-Headers doesn't cover `Authorization`, + // so browsers block authed XRPC calls (e.g. PDS Moover). + allowHeaders: [ + "Authorization", + "Content-Type", + "DPoP", + "atproto-proxy", + "atproto-accept-labelers", + ], exposeHeaders: ["Content-Type"], maxAge: 86400, }), From 4cd16af14b5429c2c4dbbd15636442abef49a5dd Mon Sep 17 00:00:00 2001 From: JP Hastings-Spital Date: Tue, 2 Jun 2026 09:13:37 +0200 Subject: [PATCH 2/2] fix(pds): reflect requested CORS headers instead of a fixed allowlist My previous commit hand-listed allowed headers (to get Authorization working), but that quietly dropped others browsers need (accept-language, x-bsky-topics, etc). Omitting allowHeaders lets Hono echo the requested headers back, matching the [reference atproto PDS](https://github.com/bluesky-social/atproto/blob/7f5c4ceb0b6872cb921ba9c2fab8c38614414f6c/packages/pds/src/index.ts#L171) and covering anything future clients send. --- .changeset/cors-authorization-header.md | 2 +- packages/pds/src/index.ts | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/.changeset/cors-authorization-header.md b/.changeset/cors-authorization-header.md index 9454574d..329743c8 100644 --- a/.changeset/cors-authorization-header.md +++ b/.changeset/cors-authorization-header.md @@ -4,4 +4,4 @@ Be explicit with CORS headers so browser-based authenticated XRPC calls work (particularly PDS Moover). -The CORS middleware advertised `Access-Control-Allow-Headers: *`, but the Fetch spec calls out that `*` wildcard does not cover the `Authorization` header — browsers require it to be named explicitly. As a result, authed cross-origin requests from web clients (eg. PDS Moover's `com.pdsmoover.backup.getRepoStatus`) were blocked at preflight. As `*` can't be used with other headers, all allowed headers are now listed explicitly. +The CORS middleware advertised `Access-Control-Allow-Headers: *`, but this didn't cover the `Authorization` header needed by tools like PDS Moover. As a result, authed cross-origin requests from web clients (eg. PDS Moover's `com.pdsmoover.backup.getRepoStatus`) were blocked at preflight. This is now resolved; all headers are reflected back, just like the Bluesky implementation. diff --git a/packages/pds/src/index.ts b/packages/pds/src/index.ts index 184afd71..8b947bcf 100644 --- a/packages/pds/src/index.ts +++ b/packages/pds/src/index.ts @@ -84,16 +84,12 @@ app.use( cors({ origin: "*", allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], - // `Authorization` must be listed explicitly: a `*` wildcard in - // Access-Control-Allow-Headers doesn't cover `Authorization`, - // so browsers block authed XRPC calls (e.g. PDS Moover). - allowHeaders: [ - "Authorization", - "Content-Type", - "DPoP", - "atproto-proxy", - "atproto-accept-labelers", - ], + // Omit allowHeaders: Hono reflects the browser's + // Access-Control-Request-Headers back, matching the reference + // atproto PDS (`cors({ maxAge })`). This allows Authorization + // (a `*` wildcard wouldn't), DPoP, atproto-proxy, + // atproto-accept-labelers, accept-language, x-bsky-topics and + // any future header automatically. exposeHeaders: ["Content-Type"], maxAge: 86400, }),