LibreChat/packages/api/src/utils/env.ts

359 lines
11 KiB
TypeScript
Raw Normal View History

👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
import { extractEnvVariable } from 'librechat-data-provider';
import type { MCPOptions } from 'librechat-data-provider';
import type { IUser } from '@librechat/data-schemas';
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
import type { RequestBody } from '~/types';
🆔 feat: Add OpenID Connect Federated Provider Token Support (#9931) * feat: Add OpenID Connect federated provider token support Implements support for passing federated provider tokens (Cognito, Azure AD, Auth0) as variables in LibreChat's librechat.yaml configuration for both custom endpoints and MCP servers. Features: - New LIBRECHAT_OPENID_* template variables for federated provider tokens - JWT claims parsing from ID tokens without verification (for claim extraction) - Token validation with expiration checking - Support for multiple token storage locations (federatedTokens, openidTokens) - Integration with existing template variable system - Comprehensive test suite with Cognito-specific scenarios - Provider-agnostic design supporting Cognito, Azure AD, Auth0, etc. Security: - Server-side only token processing - Automatic token expiration validation - Graceful fallbacks for missing/invalid tokens - No client-side token exposure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Add federated token propagation to OIDC authentication strategies 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 <denis.ramic@nfon.com> Co-Authored-By: Claude <noreply@anthropic.com> * test: Add federatedTokens validation tests for OIDC strategies Adds comprehensive test coverage for the federated token propagation feature implemented in the authentication strategies. Tests added: - Verify federatedTokens object is attached to user with correct structure (access_token, refresh_token, expires_at) - Verify both tokenset and federatedTokens are present in user object - Ensure tokens from OIDC provider are correctly propagated Also fixes existing test suite by adding missing mocks: - isEmailDomainAllowed function mock - findOpenIDUser function mock These tests validate the fix from commit 5874ba29f that enables {{LIBRECHAT_OPENID_TOKEN}} template variable functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Remove implementation documentation file The PR description already contains all necessary implementation details. This documentation file is redundant and was requested to be removed. * fix: skip s256 check * fix(openid): handle missing refresh token in Cognito token refresh response When OPENID_REUSE_TOKENS=true, the token refresh flow was failing because Cognito (and most OAuth providers) don't return a new refresh token in the refresh grant response - they only return new access and ID tokens. Changes: - Modified setOpenIDAuthTokens() to accept optional existingRefreshToken parameter - Updated validation to only require access_token (refresh_token now optional) - Added logic to reuse existing refresh token when not provided in tokenset - Updated refreshController to pass original refresh token as fallback - Added comments explaining standard OAuth 2.0 refresh token behavior This fixes the "Token is not present. User is not authenticated." error that occurred during silent token refresh with Cognito as the OpenID provider. Fixes: Authentication loop with OPENID_REUSE_TOKENS=true and AWS Cognito * fix(openid): extract refresh token from cookies for template variable replacement When OPENID_REUSE_TOKENS=true, the openIdJwtStrategy populates user.federatedTokens to enable template variable replacement (e.g., {{LIBRECHAT_OPENID_ACCESS_TOKEN}}). However, the refresh_token field was incorrectly sourced from payload.refresh_token, which is always undefined because: 1. JWTs don't contain refresh tokens in their payload 2. The JWT itself IS the access token 3. Refresh tokens are separate opaque tokens stored in HTTP-only cookies This caused extractOpenIDTokenInfo() to receive incomplete federatedTokens, resulting in template variables remaining unreplaced in headers. **Root Cause:** - Line 90: `refresh_token: payload.refresh_token` (always undefined) - JWTs only contain access token data in their claims - Refresh tokens are separate, stored securely in cookies **Solution:** - Import `cookie` module to parse cookies from request - Extract refresh token from `refreshToken` cookie - Populate federatedTokens with both access token (JWT) and refresh token (from cookie) **Impact:** - Template variables like {{LIBRECHAT_OPENID_ACCESS_TOKEN}} now work correctly - Headers in librechat.yaml are properly replaced with actual tokens - MCP server authentication with federated tokens now functional **Technical Details:** - passReqToCallback=true in JWT strategy provides req object access - Refresh token extracted via cookies.parse(req.headers.cookie).refreshToken - Falls back gracefully if cookie header or refreshToken is missing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: re-resolve headers on each request to pick up fresh federatedTokens - OpenAIClient now re-resolves headers in chatCompletion() before each API call - This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} are replaced with actual token values from req.user.federatedTokens - initialize.js now stores original template headers instead of pre-resolved ones - Fixes template variable replacement when OPENID_REUSE_TOKENS=true The issue was that headers were only resolved once during client initialization, before openIdJwtStrategy had populated user.federatedTokens. Now headers are re-resolved on every request with the current user's fresh tokens. * debug: add logging to track header resolution in OpenAIClient * debug: log tokenset structure after refresh to diagnose missing access_token * fix: set federatedTokens on user object after OAuth refresh - After successful OAuth token refresh, the user object was not being updated with federatedTokens - This caused template variable resolution to fail on subsequent requests - Now sets user.federatedTokens with access_token, id_token, refresh_token and expires_at from the refreshed tokenset - Fixes template variables like {{LIBRECHAT_OPENID_TOKEN}} not being replaced after token refresh - Related to PR #9931 (OpenID federated token support) * fix(openid): pass user object through agent chain for template variable resolution Root cause: buildAgentContext in agents/run.ts called resolveHeaders without the user parameter, preventing OpenID federated token template variables from being resolved in agent runtime parameters. Changes: - packages/api/src/agents/run.ts: Add user parameter to createRun signature - packages/api/src/agents/run.ts: Pass user to resolveHeaders in buildAgentContext - api/server/controllers/agents/client.js: Pass user when calling createRun - api/server/services/Endpoints/bedrock/options.js: Add resolveHeaders call with debug logging - api/server/services/Endpoints/custom/initialize.js: Add debug logging - packages/api/src/utils/env.ts: Add comprehensive debug logging and stack traces - packages/api/src/utils/oidc.ts: Fix eslint errors (unused type, explicit any) This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} and {{LIBRECHAT_USER_OPENIDID}} are properly resolved in both custom endpoint headers and Bedrock AgentCore runtime parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: remove debug logging from OpenID token template feature Removed excessive debug logging that was added during development to make the PR more suitable for upstream review: - Removed 7 debug statements from OpenAIClient.js - Removed all console.log statements from packages/api/src/utils/env.ts - Removed debug logging from bedrock/options.js - Removed debug logging from custom/initialize.js - Removed debug statement from AuthController.js This reduces the changeset by ~50 lines while maintaining full functionality of the OpenID federated token template variable feature. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test(openid): add comprehensive unit tests for template variable substitution - Add 34 unit tests for OIDC token utilities (oidc.spec.ts) - Test coverage for token extraction, validation, and placeholder processing - Integration tests for full OpenID token flow - All tests pass with comprehensive edge case coverage 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * test: fix OpenID federated tokens test failures - Add serverMetadata() mock to openid-client mock configuration * Fixes TypeError in openIdJwtStrategy.js where serverMetadata() was being called * Mock now returns jwks_uri and end_session_endpoint as expected by the code - Update outdated initialize.spec.js test * Remove test expecting resolveHeaders call during initialization * Header resolution was refactored to be deferred until LLM request time * Update test to verify options are returned correctly with useLegacyContent flag Fixes #9931 CI failures for backend unit tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: fix package-lock.json conflict * chore: sync package-log with upstream * chore: cleanup * fix: use createSafeUser * fix: fix createSafeUser signature * chore: remove comments * chore: purge comments * fix: update Jest testPathPattern to testPathPatterns for Jest 30+ compatibility --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Denis Ramic <denis.ramic@nfon.com> Co-authored-by: kristjanaapro <kristjana@apro.is> chore: import order and add back JSDoc for OpenID JWT callback
2025-11-21 14:44:52 +00:00
import { extractOpenIDTokenInfo, processOpenIDPlaceholders, isOpenIDTokenValid } from './oidc';
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
/**
* List of allowed user fields that can be used in MCP environment variables.
* These are non-sensitive string/boolean fields from the IUser interface.
*/
const ALLOWED_USER_FIELDS = [
'id',
'name',
'username',
'email',
'provider',
'role',
'googleId',
'facebookId',
'openidId',
'samlId',
'ldapId',
'githubId',
'discordId',
'appleId',
'emailVerified',
'twoFactorEnabled',
'termsAccepted',
] as const;
type AllowedUserField = (typeof ALLOWED_USER_FIELDS)[number];
type SafeUser = Pick<IUser, AllowedUserField>;
/**
* Creates a safe user object containing only allowed fields.
🆔 feat: Add OpenID Connect Federated Provider Token Support (#9931) * feat: Add OpenID Connect federated provider token support Implements support for passing federated provider tokens (Cognito, Azure AD, Auth0) as variables in LibreChat's librechat.yaml configuration for both custom endpoints and MCP servers. Features: - New LIBRECHAT_OPENID_* template variables for federated provider tokens - JWT claims parsing from ID tokens without verification (for claim extraction) - Token validation with expiration checking - Support for multiple token storage locations (federatedTokens, openidTokens) - Integration with existing template variable system - Comprehensive test suite with Cognito-specific scenarios - Provider-agnostic design supporting Cognito, Azure AD, Auth0, etc. Security: - Server-side only token processing - Automatic token expiration validation - Graceful fallbacks for missing/invalid tokens - No client-side token exposure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Add federated token propagation to OIDC authentication strategies 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 <denis.ramic@nfon.com> Co-Authored-By: Claude <noreply@anthropic.com> * test: Add federatedTokens validation tests for OIDC strategies Adds comprehensive test coverage for the federated token propagation feature implemented in the authentication strategies. Tests added: - Verify federatedTokens object is attached to user with correct structure (access_token, refresh_token, expires_at) - Verify both tokenset and federatedTokens are present in user object - Ensure tokens from OIDC provider are correctly propagated Also fixes existing test suite by adding missing mocks: - isEmailDomainAllowed function mock - findOpenIDUser function mock These tests validate the fix from commit 5874ba29f that enables {{LIBRECHAT_OPENID_TOKEN}} template variable functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Remove implementation documentation file The PR description already contains all necessary implementation details. This documentation file is redundant and was requested to be removed. * fix: skip s256 check * fix(openid): handle missing refresh token in Cognito token refresh response When OPENID_REUSE_TOKENS=true, the token refresh flow was failing because Cognito (and most OAuth providers) don't return a new refresh token in the refresh grant response - they only return new access and ID tokens. Changes: - Modified setOpenIDAuthTokens() to accept optional existingRefreshToken parameter - Updated validation to only require access_token (refresh_token now optional) - Added logic to reuse existing refresh token when not provided in tokenset - Updated refreshController to pass original refresh token as fallback - Added comments explaining standard OAuth 2.0 refresh token behavior This fixes the "Token is not present. User is not authenticated." error that occurred during silent token refresh with Cognito as the OpenID provider. Fixes: Authentication loop with OPENID_REUSE_TOKENS=true and AWS Cognito * fix(openid): extract refresh token from cookies for template variable replacement When OPENID_REUSE_TOKENS=true, the openIdJwtStrategy populates user.federatedTokens to enable template variable replacement (e.g., {{LIBRECHAT_OPENID_ACCESS_TOKEN}}). However, the refresh_token field was incorrectly sourced from payload.refresh_token, which is always undefined because: 1. JWTs don't contain refresh tokens in their payload 2. The JWT itself IS the access token 3. Refresh tokens are separate opaque tokens stored in HTTP-only cookies This caused extractOpenIDTokenInfo() to receive incomplete federatedTokens, resulting in template variables remaining unreplaced in headers. **Root Cause:** - Line 90: `refresh_token: payload.refresh_token` (always undefined) - JWTs only contain access token data in their claims - Refresh tokens are separate, stored securely in cookies **Solution:** - Import `cookie` module to parse cookies from request - Extract refresh token from `refreshToken` cookie - Populate federatedTokens with both access token (JWT) and refresh token (from cookie) **Impact:** - Template variables like {{LIBRECHAT_OPENID_ACCESS_TOKEN}} now work correctly - Headers in librechat.yaml are properly replaced with actual tokens - MCP server authentication with federated tokens now functional **Technical Details:** - passReqToCallback=true in JWT strategy provides req object access - Refresh token extracted via cookies.parse(req.headers.cookie).refreshToken - Falls back gracefully if cookie header or refreshToken is missing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: re-resolve headers on each request to pick up fresh federatedTokens - OpenAIClient now re-resolves headers in chatCompletion() before each API call - This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} are replaced with actual token values from req.user.federatedTokens - initialize.js now stores original template headers instead of pre-resolved ones - Fixes template variable replacement when OPENID_REUSE_TOKENS=true The issue was that headers were only resolved once during client initialization, before openIdJwtStrategy had populated user.federatedTokens. Now headers are re-resolved on every request with the current user's fresh tokens. * debug: add logging to track header resolution in OpenAIClient * debug: log tokenset structure after refresh to diagnose missing access_token * fix: set federatedTokens on user object after OAuth refresh - After successful OAuth token refresh, the user object was not being updated with federatedTokens - This caused template variable resolution to fail on subsequent requests - Now sets user.federatedTokens with access_token, id_token, refresh_token and expires_at from the refreshed tokenset - Fixes template variables like {{LIBRECHAT_OPENID_TOKEN}} not being replaced after token refresh - Related to PR #9931 (OpenID federated token support) * fix(openid): pass user object through agent chain for template variable resolution Root cause: buildAgentContext in agents/run.ts called resolveHeaders without the user parameter, preventing OpenID federated token template variables from being resolved in agent runtime parameters. Changes: - packages/api/src/agents/run.ts: Add user parameter to createRun signature - packages/api/src/agents/run.ts: Pass user to resolveHeaders in buildAgentContext - api/server/controllers/agents/client.js: Pass user when calling createRun - api/server/services/Endpoints/bedrock/options.js: Add resolveHeaders call with debug logging - api/server/services/Endpoints/custom/initialize.js: Add debug logging - packages/api/src/utils/env.ts: Add comprehensive debug logging and stack traces - packages/api/src/utils/oidc.ts: Fix eslint errors (unused type, explicit any) This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} and {{LIBRECHAT_USER_OPENIDID}} are properly resolved in both custom endpoint headers and Bedrock AgentCore runtime parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: remove debug logging from OpenID token template feature Removed excessive debug logging that was added during development to make the PR more suitable for upstream review: - Removed 7 debug statements from OpenAIClient.js - Removed all console.log statements from packages/api/src/utils/env.ts - Removed debug logging from bedrock/options.js - Removed debug logging from custom/initialize.js - Removed debug statement from AuthController.js This reduces the changeset by ~50 lines while maintaining full functionality of the OpenID federated token template variable feature. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test(openid): add comprehensive unit tests for template variable substitution - Add 34 unit tests for OIDC token utilities (oidc.spec.ts) - Test coverage for token extraction, validation, and placeholder processing - Integration tests for full OpenID token flow - All tests pass with comprehensive edge case coverage 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * test: fix OpenID federated tokens test failures - Add serverMetadata() mock to openid-client mock configuration * Fixes TypeError in openIdJwtStrategy.js where serverMetadata() was being called * Mock now returns jwks_uri and end_session_endpoint as expected by the code - Update outdated initialize.spec.js test * Remove test expecting resolveHeaders call during initialization * Header resolution was refactored to be deferred until LLM request time * Update test to verify options are returned correctly with useLegacyContent flag Fixes #9931 CI failures for backend unit tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: fix package-lock.json conflict * chore: sync package-log with upstream * chore: cleanup * fix: use createSafeUser * fix: fix createSafeUser signature * chore: remove comments * chore: purge comments * fix: update Jest testPathPattern to testPathPatterns for Jest 30+ compatibility --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Denis Ramic <denis.ramic@nfon.com> Co-authored-by: kristjanaapro <kristjana@apro.is> chore: import order and add back JSDoc for OpenID JWT callback
2025-11-21 14:44:52 +00:00
* Preserves federatedTokens for OpenID token template variable resolution.
*
* @param user - The user object to extract safe fields from
🆔 feat: Add OpenID Connect Federated Provider Token Support (#9931) * feat: Add OpenID Connect federated provider token support Implements support for passing federated provider tokens (Cognito, Azure AD, Auth0) as variables in LibreChat's librechat.yaml configuration for both custom endpoints and MCP servers. Features: - New LIBRECHAT_OPENID_* template variables for federated provider tokens - JWT claims parsing from ID tokens without verification (for claim extraction) - Token validation with expiration checking - Support for multiple token storage locations (federatedTokens, openidTokens) - Integration with existing template variable system - Comprehensive test suite with Cognito-specific scenarios - Provider-agnostic design supporting Cognito, Azure AD, Auth0, etc. Security: - Server-side only token processing - Automatic token expiration validation - Graceful fallbacks for missing/invalid tokens - No client-side token exposure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Add federated token propagation to OIDC authentication strategies 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 <denis.ramic@nfon.com> Co-Authored-By: Claude <noreply@anthropic.com> * test: Add federatedTokens validation tests for OIDC strategies Adds comprehensive test coverage for the federated token propagation feature implemented in the authentication strategies. Tests added: - Verify federatedTokens object is attached to user with correct structure (access_token, refresh_token, expires_at) - Verify both tokenset and federatedTokens are present in user object - Ensure tokens from OIDC provider are correctly propagated Also fixes existing test suite by adding missing mocks: - isEmailDomainAllowed function mock - findOpenIDUser function mock These tests validate the fix from commit 5874ba29f that enables {{LIBRECHAT_OPENID_TOKEN}} template variable functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Remove implementation documentation file The PR description already contains all necessary implementation details. This documentation file is redundant and was requested to be removed. * fix: skip s256 check * fix(openid): handle missing refresh token in Cognito token refresh response When OPENID_REUSE_TOKENS=true, the token refresh flow was failing because Cognito (and most OAuth providers) don't return a new refresh token in the refresh grant response - they only return new access and ID tokens. Changes: - Modified setOpenIDAuthTokens() to accept optional existingRefreshToken parameter - Updated validation to only require access_token (refresh_token now optional) - Added logic to reuse existing refresh token when not provided in tokenset - Updated refreshController to pass original refresh token as fallback - Added comments explaining standard OAuth 2.0 refresh token behavior This fixes the "Token is not present. User is not authenticated." error that occurred during silent token refresh with Cognito as the OpenID provider. Fixes: Authentication loop with OPENID_REUSE_TOKENS=true and AWS Cognito * fix(openid): extract refresh token from cookies for template variable replacement When OPENID_REUSE_TOKENS=true, the openIdJwtStrategy populates user.federatedTokens to enable template variable replacement (e.g., {{LIBRECHAT_OPENID_ACCESS_TOKEN}}). However, the refresh_token field was incorrectly sourced from payload.refresh_token, which is always undefined because: 1. JWTs don't contain refresh tokens in their payload 2. The JWT itself IS the access token 3. Refresh tokens are separate opaque tokens stored in HTTP-only cookies This caused extractOpenIDTokenInfo() to receive incomplete federatedTokens, resulting in template variables remaining unreplaced in headers. **Root Cause:** - Line 90: `refresh_token: payload.refresh_token` (always undefined) - JWTs only contain access token data in their claims - Refresh tokens are separate, stored securely in cookies **Solution:** - Import `cookie` module to parse cookies from request - Extract refresh token from `refreshToken` cookie - Populate federatedTokens with both access token (JWT) and refresh token (from cookie) **Impact:** - Template variables like {{LIBRECHAT_OPENID_ACCESS_TOKEN}} now work correctly - Headers in librechat.yaml are properly replaced with actual tokens - MCP server authentication with federated tokens now functional **Technical Details:** - passReqToCallback=true in JWT strategy provides req object access - Refresh token extracted via cookies.parse(req.headers.cookie).refreshToken - Falls back gracefully if cookie header or refreshToken is missing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: re-resolve headers on each request to pick up fresh federatedTokens - OpenAIClient now re-resolves headers in chatCompletion() before each API call - This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} are replaced with actual token values from req.user.federatedTokens - initialize.js now stores original template headers instead of pre-resolved ones - Fixes template variable replacement when OPENID_REUSE_TOKENS=true The issue was that headers were only resolved once during client initialization, before openIdJwtStrategy had populated user.federatedTokens. Now headers are re-resolved on every request with the current user's fresh tokens. * debug: add logging to track header resolution in OpenAIClient * debug: log tokenset structure after refresh to diagnose missing access_token * fix: set federatedTokens on user object after OAuth refresh - After successful OAuth token refresh, the user object was not being updated with federatedTokens - This caused template variable resolution to fail on subsequent requests - Now sets user.federatedTokens with access_token, id_token, refresh_token and expires_at from the refreshed tokenset - Fixes template variables like {{LIBRECHAT_OPENID_TOKEN}} not being replaced after token refresh - Related to PR #9931 (OpenID federated token support) * fix(openid): pass user object through agent chain for template variable resolution Root cause: buildAgentContext in agents/run.ts called resolveHeaders without the user parameter, preventing OpenID federated token template variables from being resolved in agent runtime parameters. Changes: - packages/api/src/agents/run.ts: Add user parameter to createRun signature - packages/api/src/agents/run.ts: Pass user to resolveHeaders in buildAgentContext - api/server/controllers/agents/client.js: Pass user when calling createRun - api/server/services/Endpoints/bedrock/options.js: Add resolveHeaders call with debug logging - api/server/services/Endpoints/custom/initialize.js: Add debug logging - packages/api/src/utils/env.ts: Add comprehensive debug logging and stack traces - packages/api/src/utils/oidc.ts: Fix eslint errors (unused type, explicit any) This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} and {{LIBRECHAT_USER_OPENIDID}} are properly resolved in both custom endpoint headers and Bedrock AgentCore runtime parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: remove debug logging from OpenID token template feature Removed excessive debug logging that was added during development to make the PR more suitable for upstream review: - Removed 7 debug statements from OpenAIClient.js - Removed all console.log statements from packages/api/src/utils/env.ts - Removed debug logging from bedrock/options.js - Removed debug logging from custom/initialize.js - Removed debug statement from AuthController.js This reduces the changeset by ~50 lines while maintaining full functionality of the OpenID federated token template variable feature. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test(openid): add comprehensive unit tests for template variable substitution - Add 34 unit tests for OIDC token utilities (oidc.spec.ts) - Test coverage for token extraction, validation, and placeholder processing - Integration tests for full OpenID token flow - All tests pass with comprehensive edge case coverage 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * test: fix OpenID federated tokens test failures - Add serverMetadata() mock to openid-client mock configuration * Fixes TypeError in openIdJwtStrategy.js where serverMetadata() was being called * Mock now returns jwks_uri and end_session_endpoint as expected by the code - Update outdated initialize.spec.js test * Remove test expecting resolveHeaders call during initialization * Header resolution was refactored to be deferred until LLM request time * Update test to verify options are returned correctly with useLegacyContent flag Fixes #9931 CI failures for backend unit tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: fix package-lock.json conflict * chore: sync package-log with upstream * chore: cleanup * fix: use createSafeUser * fix: fix createSafeUser signature * chore: remove comments * chore: purge comments * fix: update Jest testPathPattern to testPathPatterns for Jest 30+ compatibility --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Denis Ramic <denis.ramic@nfon.com> Co-authored-by: kristjanaapro <kristjana@apro.is> chore: import order and add back JSDoc for OpenID JWT callback
2025-11-21 14:44:52 +00:00
* @returns A new object containing only allowed fields plus federatedTokens if present
*/
🆔 feat: Add OpenID Connect Federated Provider Token Support (#9931) * feat: Add OpenID Connect federated provider token support Implements support for passing federated provider tokens (Cognito, Azure AD, Auth0) as variables in LibreChat's librechat.yaml configuration for both custom endpoints and MCP servers. Features: - New LIBRECHAT_OPENID_* template variables for federated provider tokens - JWT claims parsing from ID tokens without verification (for claim extraction) - Token validation with expiration checking - Support for multiple token storage locations (federatedTokens, openidTokens) - Integration with existing template variable system - Comprehensive test suite with Cognito-specific scenarios - Provider-agnostic design supporting Cognito, Azure AD, Auth0, etc. Security: - Server-side only token processing - Automatic token expiration validation - Graceful fallbacks for missing/invalid tokens - No client-side token exposure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Add federated token propagation to OIDC authentication strategies 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 <denis.ramic@nfon.com> Co-Authored-By: Claude <noreply@anthropic.com> * test: Add federatedTokens validation tests for OIDC strategies Adds comprehensive test coverage for the federated token propagation feature implemented in the authentication strategies. Tests added: - Verify federatedTokens object is attached to user with correct structure (access_token, refresh_token, expires_at) - Verify both tokenset and federatedTokens are present in user object - Ensure tokens from OIDC provider are correctly propagated Also fixes existing test suite by adding missing mocks: - isEmailDomainAllowed function mock - findOpenIDUser function mock These tests validate the fix from commit 5874ba29f that enables {{LIBRECHAT_OPENID_TOKEN}} template variable functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Remove implementation documentation file The PR description already contains all necessary implementation details. This documentation file is redundant and was requested to be removed. * fix: skip s256 check * fix(openid): handle missing refresh token in Cognito token refresh response When OPENID_REUSE_TOKENS=true, the token refresh flow was failing because Cognito (and most OAuth providers) don't return a new refresh token in the refresh grant response - they only return new access and ID tokens. Changes: - Modified setOpenIDAuthTokens() to accept optional existingRefreshToken parameter - Updated validation to only require access_token (refresh_token now optional) - Added logic to reuse existing refresh token when not provided in tokenset - Updated refreshController to pass original refresh token as fallback - Added comments explaining standard OAuth 2.0 refresh token behavior This fixes the "Token is not present. User is not authenticated." error that occurred during silent token refresh with Cognito as the OpenID provider. Fixes: Authentication loop with OPENID_REUSE_TOKENS=true and AWS Cognito * fix(openid): extract refresh token from cookies for template variable replacement When OPENID_REUSE_TOKENS=true, the openIdJwtStrategy populates user.federatedTokens to enable template variable replacement (e.g., {{LIBRECHAT_OPENID_ACCESS_TOKEN}}). However, the refresh_token field was incorrectly sourced from payload.refresh_token, which is always undefined because: 1. JWTs don't contain refresh tokens in their payload 2. The JWT itself IS the access token 3. Refresh tokens are separate opaque tokens stored in HTTP-only cookies This caused extractOpenIDTokenInfo() to receive incomplete federatedTokens, resulting in template variables remaining unreplaced in headers. **Root Cause:** - Line 90: `refresh_token: payload.refresh_token` (always undefined) - JWTs only contain access token data in their claims - Refresh tokens are separate, stored securely in cookies **Solution:** - Import `cookie` module to parse cookies from request - Extract refresh token from `refreshToken` cookie - Populate federatedTokens with both access token (JWT) and refresh token (from cookie) **Impact:** - Template variables like {{LIBRECHAT_OPENID_ACCESS_TOKEN}} now work correctly - Headers in librechat.yaml are properly replaced with actual tokens - MCP server authentication with federated tokens now functional **Technical Details:** - passReqToCallback=true in JWT strategy provides req object access - Refresh token extracted via cookies.parse(req.headers.cookie).refreshToken - Falls back gracefully if cookie header or refreshToken is missing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: re-resolve headers on each request to pick up fresh federatedTokens - OpenAIClient now re-resolves headers in chatCompletion() before each API call - This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} are replaced with actual token values from req.user.federatedTokens - initialize.js now stores original template headers instead of pre-resolved ones - Fixes template variable replacement when OPENID_REUSE_TOKENS=true The issue was that headers were only resolved once during client initialization, before openIdJwtStrategy had populated user.federatedTokens. Now headers are re-resolved on every request with the current user's fresh tokens. * debug: add logging to track header resolution in OpenAIClient * debug: log tokenset structure after refresh to diagnose missing access_token * fix: set federatedTokens on user object after OAuth refresh - After successful OAuth token refresh, the user object was not being updated with federatedTokens - This caused template variable resolution to fail on subsequent requests - Now sets user.federatedTokens with access_token, id_token, refresh_token and expires_at from the refreshed tokenset - Fixes template variables like {{LIBRECHAT_OPENID_TOKEN}} not being replaced after token refresh - Related to PR #9931 (OpenID federated token support) * fix(openid): pass user object through agent chain for template variable resolution Root cause: buildAgentContext in agents/run.ts called resolveHeaders without the user parameter, preventing OpenID federated token template variables from being resolved in agent runtime parameters. Changes: - packages/api/src/agents/run.ts: Add user parameter to createRun signature - packages/api/src/agents/run.ts: Pass user to resolveHeaders in buildAgentContext - api/server/controllers/agents/client.js: Pass user when calling createRun - api/server/services/Endpoints/bedrock/options.js: Add resolveHeaders call with debug logging - api/server/services/Endpoints/custom/initialize.js: Add debug logging - packages/api/src/utils/env.ts: Add comprehensive debug logging and stack traces - packages/api/src/utils/oidc.ts: Fix eslint errors (unused type, explicit any) This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} and {{LIBRECHAT_USER_OPENIDID}} are properly resolved in both custom endpoint headers and Bedrock AgentCore runtime parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: remove debug logging from OpenID token template feature Removed excessive debug logging that was added during development to make the PR more suitable for upstream review: - Removed 7 debug statements from OpenAIClient.js - Removed all console.log statements from packages/api/src/utils/env.ts - Removed debug logging from bedrock/options.js - Removed debug logging from custom/initialize.js - Removed debug statement from AuthController.js This reduces the changeset by ~50 lines while maintaining full functionality of the OpenID federated token template variable feature. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test(openid): add comprehensive unit tests for template variable substitution - Add 34 unit tests for OIDC token utilities (oidc.spec.ts) - Test coverage for token extraction, validation, and placeholder processing - Integration tests for full OpenID token flow - All tests pass with comprehensive edge case coverage 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * test: fix OpenID federated tokens test failures - Add serverMetadata() mock to openid-client mock configuration * Fixes TypeError in openIdJwtStrategy.js where serverMetadata() was being called * Mock now returns jwks_uri and end_session_endpoint as expected by the code - Update outdated initialize.spec.js test * Remove test expecting resolveHeaders call during initialization * Header resolution was refactored to be deferred until LLM request time * Update test to verify options are returned correctly with useLegacyContent flag Fixes #9931 CI failures for backend unit tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: fix package-lock.json conflict * chore: sync package-log with upstream * chore: cleanup * fix: use createSafeUser * fix: fix createSafeUser signature * chore: remove comments * chore: purge comments * fix: update Jest testPathPattern to testPathPatterns for Jest 30+ compatibility --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Denis Ramic <denis.ramic@nfon.com> Co-authored-by: kristjanaapro <kristjana@apro.is> chore: import order and add back JSDoc for OpenID JWT callback
2025-11-21 14:44:52 +00:00
export function createSafeUser(
user: IUser | null | undefined,
): Partial<SafeUser> & { federatedTokens?: unknown } {
if (!user) {
return {};
}
🆔 feat: Add OpenID Connect Federated Provider Token Support (#9931) * feat: Add OpenID Connect federated provider token support Implements support for passing federated provider tokens (Cognito, Azure AD, Auth0) as variables in LibreChat's librechat.yaml configuration for both custom endpoints and MCP servers. Features: - New LIBRECHAT_OPENID_* template variables for federated provider tokens - JWT claims parsing from ID tokens without verification (for claim extraction) - Token validation with expiration checking - Support for multiple token storage locations (federatedTokens, openidTokens) - Integration with existing template variable system - Comprehensive test suite with Cognito-specific scenarios - Provider-agnostic design supporting Cognito, Azure AD, Auth0, etc. Security: - Server-side only token processing - Automatic token expiration validation - Graceful fallbacks for missing/invalid tokens - No client-side token exposure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Add federated token propagation to OIDC authentication strategies 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 <denis.ramic@nfon.com> Co-Authored-By: Claude <noreply@anthropic.com> * test: Add federatedTokens validation tests for OIDC strategies Adds comprehensive test coverage for the federated token propagation feature implemented in the authentication strategies. Tests added: - Verify federatedTokens object is attached to user with correct structure (access_token, refresh_token, expires_at) - Verify both tokenset and federatedTokens are present in user object - Ensure tokens from OIDC provider are correctly propagated Also fixes existing test suite by adding missing mocks: - isEmailDomainAllowed function mock - findOpenIDUser function mock These tests validate the fix from commit 5874ba29f that enables {{LIBRECHAT_OPENID_TOKEN}} template variable functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Remove implementation documentation file The PR description already contains all necessary implementation details. This documentation file is redundant and was requested to be removed. * fix: skip s256 check * fix(openid): handle missing refresh token in Cognito token refresh response When OPENID_REUSE_TOKENS=true, the token refresh flow was failing because Cognito (and most OAuth providers) don't return a new refresh token in the refresh grant response - they only return new access and ID tokens. Changes: - Modified setOpenIDAuthTokens() to accept optional existingRefreshToken parameter - Updated validation to only require access_token (refresh_token now optional) - Added logic to reuse existing refresh token when not provided in tokenset - Updated refreshController to pass original refresh token as fallback - Added comments explaining standard OAuth 2.0 refresh token behavior This fixes the "Token is not present. User is not authenticated." error that occurred during silent token refresh with Cognito as the OpenID provider. Fixes: Authentication loop with OPENID_REUSE_TOKENS=true and AWS Cognito * fix(openid): extract refresh token from cookies for template variable replacement When OPENID_REUSE_TOKENS=true, the openIdJwtStrategy populates user.federatedTokens to enable template variable replacement (e.g., {{LIBRECHAT_OPENID_ACCESS_TOKEN}}). However, the refresh_token field was incorrectly sourced from payload.refresh_token, which is always undefined because: 1. JWTs don't contain refresh tokens in their payload 2. The JWT itself IS the access token 3. Refresh tokens are separate opaque tokens stored in HTTP-only cookies This caused extractOpenIDTokenInfo() to receive incomplete federatedTokens, resulting in template variables remaining unreplaced in headers. **Root Cause:** - Line 90: `refresh_token: payload.refresh_token` (always undefined) - JWTs only contain access token data in their claims - Refresh tokens are separate, stored securely in cookies **Solution:** - Import `cookie` module to parse cookies from request - Extract refresh token from `refreshToken` cookie - Populate federatedTokens with both access token (JWT) and refresh token (from cookie) **Impact:** - Template variables like {{LIBRECHAT_OPENID_ACCESS_TOKEN}} now work correctly - Headers in librechat.yaml are properly replaced with actual tokens - MCP server authentication with federated tokens now functional **Technical Details:** - passReqToCallback=true in JWT strategy provides req object access - Refresh token extracted via cookies.parse(req.headers.cookie).refreshToken - Falls back gracefully if cookie header or refreshToken is missing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: re-resolve headers on each request to pick up fresh federatedTokens - OpenAIClient now re-resolves headers in chatCompletion() before each API call - This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} are replaced with actual token values from req.user.federatedTokens - initialize.js now stores original template headers instead of pre-resolved ones - Fixes template variable replacement when OPENID_REUSE_TOKENS=true The issue was that headers were only resolved once during client initialization, before openIdJwtStrategy had populated user.federatedTokens. Now headers are re-resolved on every request with the current user's fresh tokens. * debug: add logging to track header resolution in OpenAIClient * debug: log tokenset structure after refresh to diagnose missing access_token * fix: set federatedTokens on user object after OAuth refresh - After successful OAuth token refresh, the user object was not being updated with federatedTokens - This caused template variable resolution to fail on subsequent requests - Now sets user.federatedTokens with access_token, id_token, refresh_token and expires_at from the refreshed tokenset - Fixes template variables like {{LIBRECHAT_OPENID_TOKEN}} not being replaced after token refresh - Related to PR #9931 (OpenID federated token support) * fix(openid): pass user object through agent chain for template variable resolution Root cause: buildAgentContext in agents/run.ts called resolveHeaders without the user parameter, preventing OpenID federated token template variables from being resolved in agent runtime parameters. Changes: - packages/api/src/agents/run.ts: Add user parameter to createRun signature - packages/api/src/agents/run.ts: Pass user to resolveHeaders in buildAgentContext - api/server/controllers/agents/client.js: Pass user when calling createRun - api/server/services/Endpoints/bedrock/options.js: Add resolveHeaders call with debug logging - api/server/services/Endpoints/custom/initialize.js: Add debug logging - packages/api/src/utils/env.ts: Add comprehensive debug logging and stack traces - packages/api/src/utils/oidc.ts: Fix eslint errors (unused type, explicit any) This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} and {{LIBRECHAT_USER_OPENIDID}} are properly resolved in both custom endpoint headers and Bedrock AgentCore runtime parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: remove debug logging from OpenID token template feature Removed excessive debug logging that was added during development to make the PR more suitable for upstream review: - Removed 7 debug statements from OpenAIClient.js - Removed all console.log statements from packages/api/src/utils/env.ts - Removed debug logging from bedrock/options.js - Removed debug logging from custom/initialize.js - Removed debug statement from AuthController.js This reduces the changeset by ~50 lines while maintaining full functionality of the OpenID federated token template variable feature. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test(openid): add comprehensive unit tests for template variable substitution - Add 34 unit tests for OIDC token utilities (oidc.spec.ts) - Test coverage for token extraction, validation, and placeholder processing - Integration tests for full OpenID token flow - All tests pass with comprehensive edge case coverage 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * test: fix OpenID federated tokens test failures - Add serverMetadata() mock to openid-client mock configuration * Fixes TypeError in openIdJwtStrategy.js where serverMetadata() was being called * Mock now returns jwks_uri and end_session_endpoint as expected by the code - Update outdated initialize.spec.js test * Remove test expecting resolveHeaders call during initialization * Header resolution was refactored to be deferred until LLM request time * Update test to verify options are returned correctly with useLegacyContent flag Fixes #9931 CI failures for backend unit tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: fix package-lock.json conflict * chore: sync package-log with upstream * chore: cleanup * fix: use createSafeUser * fix: fix createSafeUser signature * chore: remove comments * chore: purge comments * fix: update Jest testPathPattern to testPathPatterns for Jest 30+ compatibility --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Denis Ramic <denis.ramic@nfon.com> Co-authored-by: kristjanaapro <kristjana@apro.is> chore: import order and add back JSDoc for OpenID JWT callback
2025-11-21 14:44:52 +00:00
const safeUser: Partial<SafeUser> & { federatedTokens?: unknown } = {};
for (const field of ALLOWED_USER_FIELDS) {
if (field in user) {
safeUser[field] = user[field];
}
}
🆔 feat: Add OpenID Connect Federated Provider Token Support (#9931) * feat: Add OpenID Connect federated provider token support Implements support for passing federated provider tokens (Cognito, Azure AD, Auth0) as variables in LibreChat's librechat.yaml configuration for both custom endpoints and MCP servers. Features: - New LIBRECHAT_OPENID_* template variables for federated provider tokens - JWT claims parsing from ID tokens without verification (for claim extraction) - Token validation with expiration checking - Support for multiple token storage locations (federatedTokens, openidTokens) - Integration with existing template variable system - Comprehensive test suite with Cognito-specific scenarios - Provider-agnostic design supporting Cognito, Azure AD, Auth0, etc. Security: - Server-side only token processing - Automatic token expiration validation - Graceful fallbacks for missing/invalid tokens - No client-side token exposure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Add federated token propagation to OIDC authentication strategies 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 <denis.ramic@nfon.com> Co-Authored-By: Claude <noreply@anthropic.com> * test: Add federatedTokens validation tests for OIDC strategies Adds comprehensive test coverage for the federated token propagation feature implemented in the authentication strategies. Tests added: - Verify federatedTokens object is attached to user with correct structure (access_token, refresh_token, expires_at) - Verify both tokenset and federatedTokens are present in user object - Ensure tokens from OIDC provider are correctly propagated Also fixes existing test suite by adding missing mocks: - isEmailDomainAllowed function mock - findOpenIDUser function mock These tests validate the fix from commit 5874ba29f that enables {{LIBRECHAT_OPENID_TOKEN}} template variable functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Remove implementation documentation file The PR description already contains all necessary implementation details. This documentation file is redundant and was requested to be removed. * fix: skip s256 check * fix(openid): handle missing refresh token in Cognito token refresh response When OPENID_REUSE_TOKENS=true, the token refresh flow was failing because Cognito (and most OAuth providers) don't return a new refresh token in the refresh grant response - they only return new access and ID tokens. Changes: - Modified setOpenIDAuthTokens() to accept optional existingRefreshToken parameter - Updated validation to only require access_token (refresh_token now optional) - Added logic to reuse existing refresh token when not provided in tokenset - Updated refreshController to pass original refresh token as fallback - Added comments explaining standard OAuth 2.0 refresh token behavior This fixes the "Token is not present. User is not authenticated." error that occurred during silent token refresh with Cognito as the OpenID provider. Fixes: Authentication loop with OPENID_REUSE_TOKENS=true and AWS Cognito * fix(openid): extract refresh token from cookies for template variable replacement When OPENID_REUSE_TOKENS=true, the openIdJwtStrategy populates user.federatedTokens to enable template variable replacement (e.g., {{LIBRECHAT_OPENID_ACCESS_TOKEN}}). However, the refresh_token field was incorrectly sourced from payload.refresh_token, which is always undefined because: 1. JWTs don't contain refresh tokens in their payload 2. The JWT itself IS the access token 3. Refresh tokens are separate opaque tokens stored in HTTP-only cookies This caused extractOpenIDTokenInfo() to receive incomplete federatedTokens, resulting in template variables remaining unreplaced in headers. **Root Cause:** - Line 90: `refresh_token: payload.refresh_token` (always undefined) - JWTs only contain access token data in their claims - Refresh tokens are separate, stored securely in cookies **Solution:** - Import `cookie` module to parse cookies from request - Extract refresh token from `refreshToken` cookie - Populate federatedTokens with both access token (JWT) and refresh token (from cookie) **Impact:** - Template variables like {{LIBRECHAT_OPENID_ACCESS_TOKEN}} now work correctly - Headers in librechat.yaml are properly replaced with actual tokens - MCP server authentication with federated tokens now functional **Technical Details:** - passReqToCallback=true in JWT strategy provides req object access - Refresh token extracted via cookies.parse(req.headers.cookie).refreshToken - Falls back gracefully if cookie header or refreshToken is missing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: re-resolve headers on each request to pick up fresh federatedTokens - OpenAIClient now re-resolves headers in chatCompletion() before each API call - This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} are replaced with actual token values from req.user.federatedTokens - initialize.js now stores original template headers instead of pre-resolved ones - Fixes template variable replacement when OPENID_REUSE_TOKENS=true The issue was that headers were only resolved once during client initialization, before openIdJwtStrategy had populated user.federatedTokens. Now headers are re-resolved on every request with the current user's fresh tokens. * debug: add logging to track header resolution in OpenAIClient * debug: log tokenset structure after refresh to diagnose missing access_token * fix: set federatedTokens on user object after OAuth refresh - After successful OAuth token refresh, the user object was not being updated with federatedTokens - This caused template variable resolution to fail on subsequent requests - Now sets user.federatedTokens with access_token, id_token, refresh_token and expires_at from the refreshed tokenset - Fixes template variables like {{LIBRECHAT_OPENID_TOKEN}} not being replaced after token refresh - Related to PR #9931 (OpenID federated token support) * fix(openid): pass user object through agent chain for template variable resolution Root cause: buildAgentContext in agents/run.ts called resolveHeaders without the user parameter, preventing OpenID federated token template variables from being resolved in agent runtime parameters. Changes: - packages/api/src/agents/run.ts: Add user parameter to createRun signature - packages/api/src/agents/run.ts: Pass user to resolveHeaders in buildAgentContext - api/server/controllers/agents/client.js: Pass user when calling createRun - api/server/services/Endpoints/bedrock/options.js: Add resolveHeaders call with debug logging - api/server/services/Endpoints/custom/initialize.js: Add debug logging - packages/api/src/utils/env.ts: Add comprehensive debug logging and stack traces - packages/api/src/utils/oidc.ts: Fix eslint errors (unused type, explicit any) This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} and {{LIBRECHAT_USER_OPENIDID}} are properly resolved in both custom endpoint headers and Bedrock AgentCore runtime parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: remove debug logging from OpenID token template feature Removed excessive debug logging that was added during development to make the PR more suitable for upstream review: - Removed 7 debug statements from OpenAIClient.js - Removed all console.log statements from packages/api/src/utils/env.ts - Removed debug logging from bedrock/options.js - Removed debug logging from custom/initialize.js - Removed debug statement from AuthController.js This reduces the changeset by ~50 lines while maintaining full functionality of the OpenID federated token template variable feature. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test(openid): add comprehensive unit tests for template variable substitution - Add 34 unit tests for OIDC token utilities (oidc.spec.ts) - Test coverage for token extraction, validation, and placeholder processing - Integration tests for full OpenID token flow - All tests pass with comprehensive edge case coverage 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * test: fix OpenID federated tokens test failures - Add serverMetadata() mock to openid-client mock configuration * Fixes TypeError in openIdJwtStrategy.js where serverMetadata() was being called * Mock now returns jwks_uri and end_session_endpoint as expected by the code - Update outdated initialize.spec.js test * Remove test expecting resolveHeaders call during initialization * Header resolution was refactored to be deferred until LLM request time * Update test to verify options are returned correctly with useLegacyContent flag Fixes #9931 CI failures for backend unit tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: fix package-lock.json conflict * chore: sync package-log with upstream * chore: cleanup * fix: use createSafeUser * fix: fix createSafeUser signature * chore: remove comments * chore: purge comments * fix: update Jest testPathPattern to testPathPatterns for Jest 30+ compatibility --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Denis Ramic <denis.ramic@nfon.com> Co-authored-by: kristjanaapro <kristjana@apro.is> chore: import order and add back JSDoc for OpenID JWT callback
2025-11-21 14:44:52 +00:00
if ('federatedTokens' in user) {
safeUser.federatedTokens = user.federatedTokens;
}
return safeUser;
}
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
/**
* List of allowed request body fields that can be used in header placeholders.
* These are common fields from the request body that are safe to expose in headers.
*/
const ALLOWED_BODY_FIELDS = ['conversationId', 'parentMessageId', 'messageId'] as const;
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
/**
* Processes a string value to replace user field placeholders
* @param value - The string value to process
* @param user - The user object
* @returns The processed string with placeholders replaced
*/
function processUserPlaceholders(value: string, user?: IUser): string {
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
if (!user || typeof value !== 'string') {
return value;
}
for (const field of ALLOWED_USER_FIELDS) {
const placeholder = `{{LIBRECHAT_USER_${field.toUpperCase()}}}`;
if (typeof value !== 'string' || !value.includes(placeholder)) {
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
continue;
}
const fieldValue = user[field as keyof IUser];
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
// Skip replacement if field doesn't exist in user object
if (!(field in user)) {
continue;
}
// Special case for 'id' field: skip if undefined or empty
if (field === 'id' && (fieldValue === undefined || fieldValue === '')) {
continue;
}
const replacementValue = fieldValue == null ? '' : String(fieldValue);
value = value.replace(new RegExp(placeholder, 'g'), replacementValue);
}
return value;
}
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
/**
* Replaces request body field placeholders within a string.
* Recognized placeholders: `{{LIBRECHAT_BODY_<FIELD>}}` where `<FIELD>` ALLOWED_BODY_FIELDS.
* If a body field is absent or null/undefined, it is replaced with an empty string.
*
* @param value - The string value to process
* @param body - The request body object
* @returns The processed string with placeholders replaced
*/
function processBodyPlaceholders(value: string, body: RequestBody): string {
// Type guard: ensure value is a string
if (typeof value !== 'string') {
return value;
}
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
for (const field of ALLOWED_BODY_FIELDS) {
const placeholder = `{{LIBRECHAT_BODY_${field.toUpperCase()}}}`;
if (!value.includes(placeholder)) {
continue;
}
const fieldValue = body[field];
const replacementValue = fieldValue == null ? '' : String(fieldValue);
value = value.replace(new RegExp(placeholder, 'g'), replacementValue);
}
return value;
}
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
/**
* Processes a single string value by replacing various types of placeholders
* @param originalValue - The original string value to process
* @param customUserVars - Optional custom user variables to replace placeholders
* @param user - Optional user object for replacing user field placeholders
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
* @param body - Optional request body object for replacing body field placeholders
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
* @returns The processed string with all placeholders replaced
*/
function processSingleValue({
originalValue,
customUserVars,
user,
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
body = undefined,
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
}: {
originalValue: string;
customUserVars?: Record<string, string>;
user?: IUser;
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
body?: RequestBody;
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
}): string {
// Type guard: ensure we're working with a string
if (typeof originalValue !== 'string') {
return String(originalValue);
}
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
let value = originalValue;
if (customUserVars) {
for (const [varName, varVal] of Object.entries(customUserVars)) {
/** Escaped varName for use in regex to avoid issues with special characters */
const escapedVarName = varName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const placeholderRegex = new RegExp(`\\{\\{${escapedVarName}\\}\\}`, 'g');
value = value.replace(placeholderRegex, varVal);
}
}
value = processUserPlaceholders(value, user);
🆔 feat: Add OpenID Connect Federated Provider Token Support (#9931) * feat: Add OpenID Connect federated provider token support Implements support for passing federated provider tokens (Cognito, Azure AD, Auth0) as variables in LibreChat's librechat.yaml configuration for both custom endpoints and MCP servers. Features: - New LIBRECHAT_OPENID_* template variables for federated provider tokens - JWT claims parsing from ID tokens without verification (for claim extraction) - Token validation with expiration checking - Support for multiple token storage locations (federatedTokens, openidTokens) - Integration with existing template variable system - Comprehensive test suite with Cognito-specific scenarios - Provider-agnostic design supporting Cognito, Azure AD, Auth0, etc. Security: - Server-side only token processing - Automatic token expiration validation - Graceful fallbacks for missing/invalid tokens - No client-side token exposure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Add federated token propagation to OIDC authentication strategies 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 <denis.ramic@nfon.com> Co-Authored-By: Claude <noreply@anthropic.com> * test: Add federatedTokens validation tests for OIDC strategies Adds comprehensive test coverage for the federated token propagation feature implemented in the authentication strategies. Tests added: - Verify federatedTokens object is attached to user with correct structure (access_token, refresh_token, expires_at) - Verify both tokenset and federatedTokens are present in user object - Ensure tokens from OIDC provider are correctly propagated Also fixes existing test suite by adding missing mocks: - isEmailDomainAllowed function mock - findOpenIDUser function mock These tests validate the fix from commit 5874ba29f that enables {{LIBRECHAT_OPENID_TOKEN}} template variable functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: Remove implementation documentation file The PR description already contains all necessary implementation details. This documentation file is redundant and was requested to be removed. * fix: skip s256 check * fix(openid): handle missing refresh token in Cognito token refresh response When OPENID_REUSE_TOKENS=true, the token refresh flow was failing because Cognito (and most OAuth providers) don't return a new refresh token in the refresh grant response - they only return new access and ID tokens. Changes: - Modified setOpenIDAuthTokens() to accept optional existingRefreshToken parameter - Updated validation to only require access_token (refresh_token now optional) - Added logic to reuse existing refresh token when not provided in tokenset - Updated refreshController to pass original refresh token as fallback - Added comments explaining standard OAuth 2.0 refresh token behavior This fixes the "Token is not present. User is not authenticated." error that occurred during silent token refresh with Cognito as the OpenID provider. Fixes: Authentication loop with OPENID_REUSE_TOKENS=true and AWS Cognito * fix(openid): extract refresh token from cookies for template variable replacement When OPENID_REUSE_TOKENS=true, the openIdJwtStrategy populates user.federatedTokens to enable template variable replacement (e.g., {{LIBRECHAT_OPENID_ACCESS_TOKEN}}). However, the refresh_token field was incorrectly sourced from payload.refresh_token, which is always undefined because: 1. JWTs don't contain refresh tokens in their payload 2. The JWT itself IS the access token 3. Refresh tokens are separate opaque tokens stored in HTTP-only cookies This caused extractOpenIDTokenInfo() to receive incomplete federatedTokens, resulting in template variables remaining unreplaced in headers. **Root Cause:** - Line 90: `refresh_token: payload.refresh_token` (always undefined) - JWTs only contain access token data in their claims - Refresh tokens are separate, stored securely in cookies **Solution:** - Import `cookie` module to parse cookies from request - Extract refresh token from `refreshToken` cookie - Populate federatedTokens with both access token (JWT) and refresh token (from cookie) **Impact:** - Template variables like {{LIBRECHAT_OPENID_ACCESS_TOKEN}} now work correctly - Headers in librechat.yaml are properly replaced with actual tokens - MCP server authentication with federated tokens now functional **Technical Details:** - passReqToCallback=true in JWT strategy provides req object access - Refresh token extracted via cookies.parse(req.headers.cookie).refreshToken - Falls back gracefully if cookie header or refreshToken is missing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: re-resolve headers on each request to pick up fresh federatedTokens - OpenAIClient now re-resolves headers in chatCompletion() before each API call - This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} are replaced with actual token values from req.user.federatedTokens - initialize.js now stores original template headers instead of pre-resolved ones - Fixes template variable replacement when OPENID_REUSE_TOKENS=true The issue was that headers were only resolved once during client initialization, before openIdJwtStrategy had populated user.federatedTokens. Now headers are re-resolved on every request with the current user's fresh tokens. * debug: add logging to track header resolution in OpenAIClient * debug: log tokenset structure after refresh to diagnose missing access_token * fix: set federatedTokens on user object after OAuth refresh - After successful OAuth token refresh, the user object was not being updated with federatedTokens - This caused template variable resolution to fail on subsequent requests - Now sets user.federatedTokens with access_token, id_token, refresh_token and expires_at from the refreshed tokenset - Fixes template variables like {{LIBRECHAT_OPENID_TOKEN}} not being replaced after token refresh - Related to PR #9931 (OpenID federated token support) * fix(openid): pass user object through agent chain for template variable resolution Root cause: buildAgentContext in agents/run.ts called resolveHeaders without the user parameter, preventing OpenID federated token template variables from being resolved in agent runtime parameters. Changes: - packages/api/src/agents/run.ts: Add user parameter to createRun signature - packages/api/src/agents/run.ts: Pass user to resolveHeaders in buildAgentContext - api/server/controllers/agents/client.js: Pass user when calling createRun - api/server/services/Endpoints/bedrock/options.js: Add resolveHeaders call with debug logging - api/server/services/Endpoints/custom/initialize.js: Add debug logging - packages/api/src/utils/env.ts: Add comprehensive debug logging and stack traces - packages/api/src/utils/oidc.ts: Fix eslint errors (unused type, explicit any) This ensures template variables like {{LIBRECHAT_OPENID_TOKEN}} and {{LIBRECHAT_USER_OPENIDID}} are properly resolved in both custom endpoint headers and Bedrock AgentCore runtime parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: remove debug logging from OpenID token template feature Removed excessive debug logging that was added during development to make the PR more suitable for upstream review: - Removed 7 debug statements from OpenAIClient.js - Removed all console.log statements from packages/api/src/utils/env.ts - Removed debug logging from bedrock/options.js - Removed debug logging from custom/initialize.js - Removed debug statement from AuthController.js This reduces the changeset by ~50 lines while maintaining full functionality of the OpenID federated token template variable feature. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test(openid): add comprehensive unit tests for template variable substitution - Add 34 unit tests for OIDC token utilities (oidc.spec.ts) - Test coverage for token extraction, validation, and placeholder processing - Integration tests for full OpenID token flow - All tests pass with comprehensive edge case coverage 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> * test: fix OpenID federated tokens test failures - Add serverMetadata() mock to openid-client mock configuration * Fixes TypeError in openIdJwtStrategy.js where serverMetadata() was being called * Mock now returns jwks_uri and end_session_endpoint as expected by the code - Update outdated initialize.spec.js test * Remove test expecting resolveHeaders call during initialization * Header resolution was refactored to be deferred until LLM request time * Update test to verify options are returned correctly with useLegacyContent flag Fixes #9931 CI failures for backend unit tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: fix package-lock.json conflict * chore: sync package-log with upstream * chore: cleanup * fix: use createSafeUser * fix: fix createSafeUser signature * chore: remove comments * chore: purge comments * fix: update Jest testPathPattern to testPathPatterns for Jest 30+ compatibility --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Denis Ramic <denis.ramic@nfon.com> Co-authored-by: kristjanaapro <kristjana@apro.is> chore: import order and add back JSDoc for OpenID JWT callback
2025-11-21 14:44:52 +00:00
const openidTokenInfo = extractOpenIDTokenInfo(user);
if (openidTokenInfo && isOpenIDTokenValid(openidTokenInfo)) {
value = processOpenIDPlaceholders(value, openidTokenInfo);
}
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
if (body) {
value = processBodyPlaceholders(value, body);
}
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
value = extractEnvVariable(value);
return value;
}
/**
* Recursively processes an object to replace environment variables in string values
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
* @param params - Processing parameters
* @param params.options - The MCP options to process
* @param params.user - The user object containing all user fields
* @param params.customUserVars - vars that user set in settings
* @param params.body - the body of the request that is being processed
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
* @returns - The processed object with environment variables replaced
*/
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
export function processMCPEnv(params: {
options: Readonly<MCPOptions>;
user?: IUser;
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
customUserVars?: Record<string, string>;
body?: RequestBody;
}): MCPOptions {
const { options, user, customUserVars, body } = params;
if (options === null || options === undefined) {
return options;
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
}
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
const newObj: MCPOptions = structuredClone(options);
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
if ('env' in newObj && newObj.env) {
const processedEnv: Record<string, string> = {};
for (const [key, originalValue] of Object.entries(newObj.env)) {
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
processedEnv[key] = processSingleValue({ originalValue, customUserVars, user, body });
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
}
newObj.env = processedEnv;
}
if ('args' in newObj && newObj.args) {
const processedArgs: string[] = [];
for (const originalValue of newObj.args) {
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
processedArgs.push(processSingleValue({ originalValue, customUserVars, user, body }));
}
newObj.args = processedArgs;
}
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
// Process headers if they exist (for WebSocket, SSE, StreamableHTTP types)
// Note: `env` and `headers` are on different branches of the MCPOptions union type.
if ('headers' in newObj && newObj.headers) {
const processedHeaders: Record<string, string> = {};
for (const [key, originalValue] of Object.entries(newObj.headers)) {
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
processedHeaders[key] = processSingleValue({ originalValue, customUserVars, user, body });
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
}
newObj.headers = processedHeaders;
}
// Process URL if it exists (for WebSocket, SSE, StreamableHTTP types)
if ('url' in newObj && newObj.url) {
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
newObj.url = processSingleValue({ originalValue: newObj.url, customUserVars, user, body });
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
}
// Process OAuth configuration if it exists (for all transport types)
if ('oauth' in newObj && newObj.oauth) {
const processedOAuth: Record<string, boolean | string | string[] | undefined> = {};
for (const [key, originalValue] of Object.entries(newObj.oauth)) {
// Only process string values for environment variables
// token_exchange_method is an enum and shouldn't be processed
if (typeof originalValue === 'string') {
processedOAuth[key] = processSingleValue({ originalValue, customUserVars, user, body });
} else {
processedOAuth[key] = originalValue;
}
}
newObj.oauth = processedOAuth;
}
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
return newObj;
}
/**
* Recursively processes a value, replacing placeholders in strings while preserving structure
* @param value - The value to process (can be string, number, boolean, array, object, etc.)
* @param options - Processing options
* @returns The processed value with the same structure
*/
function processValue(
value: unknown,
options: {
customUserVars?: Record<string, string>;
user?: IUser;
body?: RequestBody;
},
): unknown {
if (typeof value === 'string') {
return processSingleValue({
originalValue: value,
customUserVars: options.customUserVars,
user: options.user,
body: options.body,
});
}
if (Array.isArray(value)) {
return value.map((item) => processValue(item, options));
}
if (value !== null && typeof value === 'object') {
const processed: Record<string, unknown> = {};
for (const [key, val] of Object.entries(value)) {
processed[key] = processValue(val, options);
}
return processed;
}
return value;
}
/**
* Recursively resolves placeholders in a nested object structure while preserving types.
* Only processes string values - leaves numbers, booleans, arrays, and nested objects intact.
*
* @param options - Configuration object
* @param options.obj - The object to process
* @param options.user - Optional user object for replacing user field placeholders
* @param options.body - Optional request body object for replacing body field placeholders
* @param options.customUserVars - Optional custom user variables to replace placeholders
* @returns The processed object with placeholders replaced in string values
*/
export function resolveNestedObject<T = unknown>(options?: {
obj: T | undefined;
user?: Partial<IUser> | { id: string };
body?: RequestBody;
customUserVars?: Record<string, string>;
}): T {
const { obj, user, body, customUserVars } = options ?? {};
if (!obj) {
return obj as T;
}
return processValue(obj, {
customUserVars,
user: user as IUser,
body,
}) as T;
}
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
/**
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
* Resolves header values by replacing user placeholders, body variables, custom variables, and environment variables.
*
* @param options - Optional configuration object.
* @param options.headers - The headers object to process.
* @param options.user - Optional user object for replacing user field placeholders (can be partial with just id).
* @param options.body - Optional request body object for replacing body field placeholders.
* @param options.customUserVars - Optional custom user variables to replace placeholders.
* @returns The processed headers with all placeholders replaced.
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
*/
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
export function resolveHeaders(options?: {
headers: Record<string, string> | undefined;
user?: Partial<IUser> | { id: string };
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
body?: RequestBody;
customUserVars?: Record<string, string>;
}) {
const { headers, user, body, customUserVars } = options ?? {};
const inputHeaders = headers ?? {};
const resolvedHeaders: Record<string, string> = { ...inputHeaders };
if (inputHeaders && typeof inputHeaders === 'object' && !Array.isArray(inputHeaders)) {
Object.keys(inputHeaders).forEach((key) => {
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
resolvedHeaders[key] = processSingleValue({
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
originalValue: inputHeaders[key],
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
customUserVars,
user: user as IUser,
🏷️ feat: Request Placeholders for Custom Endpoint & MCP Headers (#9095) * feat: Add conversation ID support to custom endpoint headers - Add LIBRECHAT_CONVERSATION_ID to customUserVars when provided - Pass conversation ID to header resolution for dynamic headers - Add comprehensive test coverage Enables custom endpoints to access conversation context using {{LIBRECHAT_CONVERSATION_ID}} placeholder. * fix: filter out unresolved placeholders from headers (thanks @MrunmayS) * feat: add support for request body placeholders in custom endpoint headers - Add {{LIBRECHAT_BODY_*}} placeholders for conversationId, parentMessageId, messageId - Update tests to reflect new body placeholder functionality * refactor resolveHeaders * style: minor styling cleanup * fix: type error in unit test * feat: add body to other endpoints * feat: add body for mcp tool calls * chore: remove changes that unnecessarily increase scope after clarification of requirements * refactor: move http.ts to packages/api and have RequestBody intersect with Express request body * refactor: processMCPEnv now uses single object argument pattern * refactor: update processMCPEnv to use 'options' parameter and align types across MCP connection classes * feat: enhance MCP connection handling with dynamic request headers to pass request body fields --------- Co-authored-by: Gopal Sharma <gopalsharma@gopal.sharma1> Co-authored-by: s10gopal <36487439+s10gopal@users.noreply.github.com> Co-authored-by: Dustin Healy <dustinhealy1@gmail.com>
2025-08-16 20:45:55 -04:00
body,
👤 feat: User Placeholder Variables for Custom Endpoint Headers (#7993) * 🔧 refactor: move `processMCPEnv` from `librechat-data-provider` and move to `@librechat/api` * 🔧 refactor: Update resolveHeaders import paths * 🔧 refactor: Enhance resolveHeaders to support user and custom variables - Updated resolveHeaders function to accept user and custom user variables for placeholder replacement. - Modified header resolution in multiple client and controller files to utilize the enhanced resolveHeaders functionality. - Added comprehensive tests for resolveHeaders to ensure correct processing of user and custom variables. * 🔧 fix: Update user ID placeholder processing in env.ts * 🔧 fix: Remove arguments passing this.user rather than req.user - Updated multiple client and controller files to call resolveHeaders without the user parameter * 🔧 refactor: Enhance processUserPlaceholders to be more readable / less nested * 🔧 refactor: Update processUserPlaceholders to pass all tests in mpc.spec.ts and env.spec.ts * chore: remove legacy ChatGPTClient * chore: remove LLM initialization code * chore: initial deprecation removal of `gptPlugins` * chore: remove cohere-ai dependency from package.json and package-lock.json * chore: update brace-expansion to version 2.0.2 and add license information * chore: remove PluginsClient test file * chore: remove legacy * ci: remove deprecated sendMessage/getCompletion/chatCompletion tests --------- Co-authored-by: Dustin Healy <54083382+dustinhealy@users.noreply.github.com>
2025-06-23 12:39:27 -04:00
});
});
}
return resolvedHeaders;
}