🔃 fix: Token Refresh in Browser Only, Redirect on Refresh Failure (#9583)

* 🔃 fix: Token Refresh in Browser Only, Redirect on Refresh Failure

* chore: Update import for SearchResultData and fix FormattedToolResponse type build warning
This commit is contained in:
Danny Avila 2025-09-11 16:51:40 -04:00 committed by GitHub
parent 180046a3c5
commit e3a645e8fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 63 additions and 61 deletions

View file

@ -8,7 +8,7 @@ import {
StreamableHTTPOptionsSchema, StreamableHTTPOptionsSchema,
Tools, Tools,
} from 'librechat-data-provider'; } from 'librechat-data-provider';
import type { UIResource, TPlugin, TUser } from 'librechat-data-provider'; import type { SearchResultData, UIResource, TPlugin, TUser } from 'librechat-data-provider';
import type * as t from '@modelcontextprotocol/sdk/types.js'; import type * as t from '@modelcontextprotocol/sdk/types.js';
import type { TokenMethods } from '@librechat/data-schemas'; import type { TokenMethods } from '@librechat/data-schemas';
import type { FlowStateManager } from '~/flow/manager'; import type { FlowStateManager } from '~/flow/manager';
@ -133,7 +133,7 @@ export type Artifacts =
sources: FileSearchSource[]; sources: FileSearchSource[];
fileCitations?: boolean; fileCitations?: boolean;
}; };
[Tools.web_search]?: import('librechat-data-provider').SearchResultData; [Tools.web_search]?: SearchResultData;
files?: Array<{ id: string; name: string }>; files?: Array<{ id: string; name: string }>;
session_id?: string; session_id?: string;
file_ids?: string[]; file_ids?: string[];
@ -144,10 +144,7 @@ export type FormattedContentResult = [string | FormattedContent[], undefined | A
export type ImageFormatter = (item: ImageContent) => FormattedContent; export type ImageFormatter = (item: ImageContent) => FormattedContent;
export type FormattedToolResponse = [ export type FormattedToolResponse = FormattedContentResult;
string | FormattedContent[],
{ content: FormattedContent[] } | undefined,
];
export type ParsedServerConfig = MCPOptions & { export type ParsedServerConfig = MCPOptions & {
url?: string; url?: string;

View file

@ -83,6 +83,7 @@ const processQueue = (error: AxiosError | null, token: string | null = null) =>
failedQueue = []; failedQueue = [];
}; };
if (typeof window !== 'undefined') {
axios.interceptors.response.use( axios.interceptors.response.use(
(response) => response, (response) => response,
async (error) => { async (error) => {
@ -97,6 +98,12 @@ axios.interceptors.response.use(
if (originalRequest.url?.includes('/api/auth/logout') === true) { if (originalRequest.url?.includes('/api/auth/logout') === true) {
return Promise.reject(error); return Promise.reject(error);
} }
if (originalRequest.url?.includes('/api/auth/refresh') === true) {
// Refresh token itself failed - redirect to login
console.log('Refresh token request failed, redirecting to login...');
window.location.href = '/login';
return Promise.reject(error);
}
if (error.response.status === 401 && !originalRequest._retry) { if (error.response.status === 401 && !originalRequest._retry) {
console.warn('401 error, refreshing token'); console.warn('401 error, refreshing token');
@ -117,10 +124,7 @@ axios.interceptors.response.use(
isRefreshing = true; isRefreshing = true;
try { try {
const response = await refreshToken( const response = await refreshToken();
// Handle edge case where we get a blank screen if the initial 401 error is from a refresh token request
originalRequest.url?.includes('api/auth/refresh') === true ? true : false,
);
const token = response?.token ?? ''; const token = response?.token ?? '';
@ -147,6 +151,7 @@ axios.interceptors.response.use(
return Promise.reject(error); return Promise.reject(error);
}, },
); );
}
export default { export default {
get: _get, get: _get,