From 5874ba29ff6bfa451008444c25e1869f7eb55b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3n=20Levy?= Date: Thu, 16 Oct 2025 11:46:59 +0000 Subject: [PATCH] fix: Add federated token propagation to OIDC authentication strategies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds federatedTokens object to user during authentication to enable federated provider token template variables in LibreChat configuration. Changes: - OpenID JWT Strategy: Extract raw JWT from Authorization header and attach as federatedTokens.access_token to enable {{LIBRECHAT_OPENID_TOKEN}} placeholder resolution - OpenID Strategy: Attach tokenset tokens as federatedTokens object to standardize token access across both authentication strategies This enables proper token propagation for custom endpoints and MCP servers that require federated provider tokens for authorization. Resolves missing token issue reported by @ramden in PR #9931 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Denis Ramic Co-Authored-By: Claude --- api/strategies/openIdJwtStrategy.js | 16 +++++++++++++++- api/strategies/openidStrategy.js | 10 +++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/api/strategies/openIdJwtStrategy.js b/api/strategies/openIdJwtStrategy.js index 94685fc86c..69dc2f1033 100644 --- a/api/strategies/openIdJwtStrategy.js +++ b/api/strategies/openIdJwtStrategy.js @@ -40,13 +40,19 @@ const openIdJwtLogin = (openIdConfig) => { { jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKeyProvider: jwksRsa.passportJwtSecret(jwksRsaOptions), + passReqToCallback: true, // Pass request to callback to access raw token }, /** + * @param {Express.Request} req * @param {import('openid-client').IDToken} payload * @param {import('passport-jwt').VerifyCallback} done */ - async (payload, done) => { + async (req, payload, done) => { try { + // Extract the raw JWT token from the Authorization header + const authHeader = req.headers.authorization; + const rawToken = authHeader?.replace('Bearer ', ''); + const { user, error, migration } = await findOpenIDUser({ findUser, email: payload?.email, @@ -77,6 +83,14 @@ const openIdJwtLogin = (openIdConfig) => { await updateUser(user.id, updateData); } + // Add federated tokens for OIDC placeholder processing + // Use the raw JWT token as the access token + user.federatedTokens = { + access_token: rawToken, + refresh_token: payload.refresh_token, + expires_at: payload.exp, + }; + done(null, user); } else { logger.warn( diff --git a/api/strategies/openidStrategy.js b/api/strategies/openidStrategy.js index ce564fc655..5f71ef09cd 100644 --- a/api/strategies/openidStrategy.js +++ b/api/strategies/openidStrategy.js @@ -491,7 +491,15 @@ async function setupOpenId() { }, ); - done(null, { ...user, tokenset }); + done(null, { + ...user, + tokenset, + federatedTokens: { + access_token: tokenset.access_token, + refresh_token: tokenset.refresh_token, + expires_at: tokenset.expires_at, + }, + }); } catch (err) { logger.error('[openidStrategy] login failed', err); done(err);