mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-04-07 08:25:23 +02:00
fix: validate auth server identity and target cleanup to reused clients
- Gate client reuse on authorization server identity: compare stored issuer against freshly discovered metadata before reusing, preventing wrong-client reuse when the MCP server switches auth providers - Add reusedStoredClient flag to MCPOAuthFlowMetadata so cleanup only runs when the failed flow actually reused a stored registration, not on unrelated failures (timeouts, user-denied consent, etc.) - Add cleanup in returnOnOAuth path: when a prior flow that reused a stored client is detected as failed, clear the stale registration before re-initiating - Add tests for issuer mismatch and reusedStoredClient flag assertions
This commit is contained in:
parent
d355be7dd0
commit
978ce2b4eb
4 changed files with 83 additions and 14 deletions
|
|
@ -355,7 +355,17 @@ export class MCPConnectionFactory {
|
|||
);
|
||||
|
||||
if (existingFlow) {
|
||||
const oldState = (existingFlow.metadata as MCPOAuthFlowMetadata)?.state;
|
||||
const oldMeta = existingFlow.metadata as MCPOAuthFlowMetadata | undefined;
|
||||
if (oldMeta?.reusedStoredClient && this.tokenMethods?.deleteTokens) {
|
||||
await MCPTokenStorage.deleteClientRegistration({
|
||||
userId: this.userId!,
|
||||
serverName: this.serverName,
|
||||
deleteTokens: this.tokenMethods.deleteTokens,
|
||||
}).catch((err) => {
|
||||
logger.debug(`${this.logPrefix} Failed to clear stale client registration`, err);
|
||||
});
|
||||
}
|
||||
const oldState = oldMeta?.state;
|
||||
await this.flowManager!.deleteFlow(newFlowId, 'mcp_oauth');
|
||||
if (oldState) {
|
||||
await MCPOAuthHandler.deleteStateMapping(oldState, this.flowManager!);
|
||||
|
|
@ -413,16 +423,21 @@ export class MCPConnectionFactory {
|
|||
if (result?.tokens) {
|
||||
connection.emit('oauthHandled');
|
||||
} else {
|
||||
// OAuth failed — clear stored client registration so the next attempt
|
||||
// does a fresh DCR instead of reusing a potentially stale client_id
|
||||
if (this.tokenMethods?.deleteTokens) {
|
||||
await MCPTokenStorage.deleteClientRegistration({
|
||||
userId: this.userId!,
|
||||
serverName: this.serverName,
|
||||
deleteTokens: this.tokenMethods.deleteTokens,
|
||||
}).catch((err) => {
|
||||
logger.debug(`${this.logPrefix} Failed to clear stale client registration`, err);
|
||||
});
|
||||
// OAuth failed — if we reused a stored client registration, clear it
|
||||
// so the next attempt falls through to fresh DCR
|
||||
if (result?.clientInfo && this.tokenMethods?.deleteTokens) {
|
||||
const flowId = MCPOAuthHandler.generateFlowId(this.userId!, this.serverName);
|
||||
const failedFlow = await this.flowManager?.getFlowState(flowId, 'mcp_oauth');
|
||||
const failedMeta = failedFlow?.metadata as MCPOAuthFlowMetadata | undefined;
|
||||
if (failedMeta?.reusedStoredClient) {
|
||||
await MCPTokenStorage.deleteClientRegistration({
|
||||
userId: this.userId!,
|
||||
serverName: this.serverName,
|
||||
deleteTokens: this.tokenMethods.deleteTokens,
|
||||
}).catch((err) => {
|
||||
logger.debug(`${this.logPrefix} Failed to clear stale client registration`, err);
|
||||
});
|
||||
}
|
||||
}
|
||||
logger.warn(`${this.logPrefix} OAuth failed, emitting oauthFailed event`);
|
||||
connection.emit('oauthFailed', new Error('OAuth authentication failed'));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue