mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
fix: create new flows on invalid_grant errors
This commit is contained in:
parent
7ea9cc06f2
commit
00c320ccae
3 changed files with 25 additions and 5 deletions
|
|
@ -272,16 +272,28 @@ export class FlowStateManager<T = unknown> {
|
|||
): Promise<T> {
|
||||
const flowKey = this.getFlowKey(flowId, type);
|
||||
let existingState = (await this.keyv.get(flowKey)) as FlowState<T> | undefined;
|
||||
if (existingState) {
|
||||
logger.debug(`[${flowKey}] Flow already exists`);
|
||||
const hasAccessTokenExpired =
|
||||
existingState?.result &&
|
||||
typeof existingState.result === 'object' &&
|
||||
'expires_at' in existingState.result &&
|
||||
typeof existingState.result.expires_at === 'number' &&
|
||||
existingState.result.expires_at < Date.now();
|
||||
if (existingState && !hasAccessTokenExpired) {
|
||||
logger.debug(`[${flowKey}] Flow already exists with valid token`);
|
||||
return this.monitorFlow(flowKey, type, signal);
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 250));
|
||||
|
||||
existingState = (await this.keyv.get(flowKey)) as FlowState<T> | undefined;
|
||||
if (existingState) {
|
||||
logger.debug(`[${flowKey}] Flow exists on 2nd check`);
|
||||
const hasAccessTokenExpiredRecheck =
|
||||
existingState?.result &&
|
||||
typeof existingState.result === 'object' &&
|
||||
'expires_at' in existingState.result &&
|
||||
typeof existingState.result.expires_at === 'number' &&
|
||||
existingState.result.expires_at < Date.now();
|
||||
if (existingState && !hasAccessTokenExpiredRecheck) {
|
||||
logger.debug(`[${flowKey}] Flow exists on 2nd check with valid token`);
|
||||
return this.monitorFlow(flowKey, type, signal);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,10 @@ export class MCPConnectionFactory {
|
|||
config?.oauth,
|
||||
);
|
||||
|
||||
// Delete any existing flow state to ensure we start fresh
|
||||
// This prevents stale codeVerifier issues when re-authenticating
|
||||
await this.flowManager!.deleteFlow(flowId, 'mcp_oauth');
|
||||
|
||||
// Create the flow state so the OAuth callback can find it
|
||||
// We spawn this in the background without waiting for it
|
||||
this.flowManager!.createFlow(flowId, 'mcp_oauth', flowMetadata).catch(() => {
|
||||
|
|
|
|||
|
|
@ -615,7 +615,7 @@ export class MCPConnection extends EventEmitter {
|
|||
}
|
||||
|
||||
// Check if it's an OAuth authentication error
|
||||
if (errorCode === 401 || errorCode === 403) {
|
||||
if (this.isOAuthError(error)) {
|
||||
logger.warn(`${this.getLogPrefix()} OAuth authentication error detected`);
|
||||
this.emit('oauthError', error);
|
||||
}
|
||||
|
|
@ -778,6 +778,10 @@ export class MCPConnection extends EventEmitter {
|
|||
if (message.includes('invalid_token')) {
|
||||
return true;
|
||||
}
|
||||
// Check for invalid_grant (OAuth servers return this for expired/revoked grants)
|
||||
if (message.includes('invalid_grant')) {
|
||||
return true;
|
||||
}
|
||||
// Check for authentication required
|
||||
if (message.includes('authentication required') || message.includes('unauthorized')) {
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue