From 48614c5802f3fab44ba64dca4752ff3dbb343f69 Mon Sep 17 00:00:00 2001 From: Melvin Carvalho Date: Mon, 29 Dec 2025 08:34:12 +0100 Subject: [PATCH 1/3] fix(idp): allow CORS for all clients on token endpoint Simplify clientBasedCORS to return true for all clients, not just public clients with tokenEndpointAuthMethod 'none'. This fixes OIDC login for web apps loaded from CDN (like Mashlib from unpkg.com) where the origin doesn't match the client's redirect URIs. Solid servers are public and should accept token requests from any web app origin. Fixes #10 --- src/idp/provider.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/idp/provider.js b/src/idp/provider.js index f1de093..2e83d40 100644 --- a/src/idp/provider.js +++ b/src/idp/provider.js @@ -276,16 +276,10 @@ export async function createProvider(issuer) { // Clock tolerance for token validation clockTolerance: 60, // 60 seconds - // Allow CORS for public clients from any origin + // Allow CORS for all clients from any origin // This is needed for web apps like Mashlib loaded from CDN - clientBasedCORS: (ctx, origin, client) => { - // Allow all origins for public clients (no client_secret) - if (client.tokenEndpointAuthMethod === 'none') { - return true; - } - // For confidential clients, check registered origins - return false; - }, + // Solid servers are public and should accept requests from any web app + clientBasedCORS: () => true, // Render errors renderError: async (ctx, out, error) => { From 3f3d4e70a61e5a1905ffe4ab122d99807d0a5770 Mon Sep 17 00:00:00 2001 From: Melvin Carvalho Date: Mon, 29 Dec 2025 08:44:15 +0100 Subject: [PATCH 2/3] fix(cors): add DPoP to allowed headers for Solid-OIDC Solid-OIDC requires DPoP (Demonstrating Proof-of-Possession) tokens which use a DPoP HTTP header. Without this header in the CORS allowed headers list, browsers block the token exchange request. --- src/ldp/headers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ldp/headers.js b/src/ldp/headers.js index 53c4e8b..2243ce0 100644 --- a/src/ldp/headers.js +++ b/src/ldp/headers.js @@ -90,7 +90,7 @@ export function getCorsHeaders(origin) { return { 'Access-Control-Allow-Origin': origin || '*', 'Access-Control-Allow-Methods': 'GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS', - 'Access-Control-Allow-Headers': 'Accept, Authorization, Content-Type, If-Match, If-None-Match, Link, Slug, Origin', + 'Access-Control-Allow-Headers': 'Accept, Authorization, Content-Type, DPoP, If-Match, If-None-Match, Link, Slug, Origin', 'Access-Control-Expose-Headers': 'Accept-Patch, Accept-Post, Allow, Content-Type, ETag, Link, Location, Updates-Via, WAC-Allow', 'Access-Control-Allow-Credentials': 'true', 'Access-Control-Max-Age': '86400' From b496dc4cd5b8dea5391bbcb6fa654f2b40031b2c Mon Sep 17 00:00:00 2001 From: Melvin Carvalho Date: Mon, 29 Dec 2025 08:53:19 +0100 Subject: [PATCH 3/3] fix(idp): strip iss parameter from authorization redirects oidc-provider v9+ always includes the iss parameter (RFC 9207) in authorization responses. Mashlib's solid-ui auth library doesn't handle this parameter, causing the OAuth callback to fail. This intercepts the Location header and strips the iss parameter before sending the redirect to the client. --- src/idp/index.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/idp/index.js b/src/idp/index.js index 7a2b7c4..951c127 100644 --- a/src/idp/index.js +++ b/src/idp/index.js @@ -70,6 +70,19 @@ export async function idpPlugin(fastify, options) { const req = request.raw; const res = reply.raw; + // Intercept setHeader to strip 'iss' parameter from Location redirects + // oidc-provider v9+ always includes 'iss' (RFC 9207) but Mashlib's auth doesn't handle it + const originalSetHeader = res.setHeader.bind(res); + res.setHeader = (name, value) => { + if (name.toLowerCase() === 'location' && typeof value === 'string' && value.includes('iss=')) { + // Strip the iss parameter from the redirect URL + const url = new URL(value, 'http://localhost'); + url.searchParams.delete('iss'); + value = url.pathname + url.search + url.hash; + } + return originalSetHeader(name, value); + }; + // oidc-provider is now configured with /idp routes, no stripping needed // Ensure parsed body is accessible to oidc-provider // Fastify parses body into request.body, oidc-provider looks for req.body