Summary
Mashlib OIDC login does not complete without a workaround patch to solid-logic. The upstream solid-client-authn-browser library receives the OAuth authorization code but fails to exchange it for tokens.
Root Cause Analysis
The AuthCodeRedirectHandler in solid-client-authn-browser looks up session data using the OAuth state parameter:
// AuthCodeRedirectHandler.ts:91-97
const storedSessionId = await this.storageUtility.getForUser(
oauthState, // Uses STATE parameter as lookup key
"sessionId",
{ errorIfNull: true } // Throws if not found!
);
This expects localStorage to have:
solidClientAuthenticationUser:{state} → {sessionId: "default"}
But we observed only:
solidClientAuthenticationUser:default → {codeVerifier, clientId, ...}
Hypothesis: The state→sessionId mapping isn't being created during login, so the redirect handler can't find the session data.
Observable Behavior
- User clicks "Sign In" → redirects to IdP
- User logs in → redirects back with
?code=xxx&state=yyy
handleIncomingRedirect() is called
- No POST to
/idp/token - token exchange never happens
session.info.isLoggedIn remains false
localStorage State After Redirect
{
"solidClientAuthenticationUser:default": {
"clientId": "client_xxx",
"codeVerifier": "abc123...",
"redirectUrl": "http://jss:4000/",
"issuer": "http://jss:4000/"
}
}
Missing: solidClientAuthenticationUser:{state} entry.
Workaround Implementation
Patch solid-logic/src/authn/SolidAuthnLogic.ts:
1. Capture auth code at module load (before library cleans URL)
let capturedAuthCode: { code: string, state: string } | null = null
;(function() {
const url = new URL(window.location.href)
const code = url.searchParams.get('code')
const state = url.searchParams.get('state')
if (code && state) capturedAuthCode = { code, state }
})()
2. Manual token exchange in checkUser()
// Find session data (stored under sessionId, not state)
for (key of localStorage starting with 'solidClientAuthenticationUser:') {
if (data.codeVerifier && data.clientId) { sessionData = data; break }
}
// POST to token endpoint manually
const response = await fetch(issuer + '/idp/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: capturedAuthCode.code,
redirect_uri: sessionData.redirectUrl,
client_id: sessionData.clientId,
code_verifier: sessionData.codeVerifier
})
})
3. Patch window.fetch for authenticated requests
// rdflib uses window.fetch directly, not session.fetch
const originalFetch = window.fetch
window.fetch = (input, init) => {
if (tokens && url.startsWith(window.location.origin)) {
init.headers.set('Authorization', 'Bearer ' + tokens.accessToken)
}
return originalFetch(input, init)
}
Environment
- solid-client-authn-browser: 3.1.1
- solid-logic: 4.0.1
- Browser: Chrome 131
- Server: JSS with oidc-provider
Questions
- Is this specific to JSS's oidc-provider, or does it affect other servers?
- Is the state→sessionId mapping supposed to be stored by oidc-client-ext?
- Has this worked historically and regressed, or is it a configuration issue?
Related
Status
Summary
Mashlib OIDC login does not complete without a workaround patch to
solid-logic. The upstreamsolid-client-authn-browserlibrary receives the OAuth authorization code but fails to exchange it for tokens.Root Cause Analysis
The
AuthCodeRedirectHandlerin solid-client-authn-browser looks up session data using the OAuthstateparameter:This expects localStorage to have:
solidClientAuthenticationUser:{state}→{sessionId: "default"}But we observed only:
solidClientAuthenticationUser:default→{codeVerifier, clientId, ...}Hypothesis: The state→sessionId mapping isn't being created during login, so the redirect handler can't find the session data.
Observable Behavior
?code=xxx&state=yyyhandleIncomingRedirect()is called/idp/token- token exchange never happenssession.info.isLoggedInremainsfalselocalStorage State After Redirect
{ "solidClientAuthenticationUser:default": { "clientId": "client_xxx", "codeVerifier": "abc123...", "redirectUrl": "http://jss:4000/", "issuer": "http://jss:4000/" } }Missing:
solidClientAuthenticationUser:{state}entry.Workaround Implementation
Patch
solid-logic/src/authn/SolidAuthnLogic.ts:1. Capture auth code at module load (before library cleans URL)
2. Manual token exchange in checkUser()
3. Patch window.fetch for authenticated requests
Environment
Questions
Related
Status