mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 06:00:56 +02:00
🔃 fix: Refresh Token Edge Cases (#9625)
* 🔃 fix: Refresh Token Edge Cases
* chore: Update parameter type for setAuthTokens function
This commit is contained in:
parent
5245aeea8f
commit
1a47601533
4 changed files with 28 additions and 23 deletions
|
@ -96,14 +96,17 @@ const refreshController = async (req, res) => {
|
||||||
return res.status(200).send({ token, user });
|
return res.status(200).send({ token, user });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the session with the hashed refresh token
|
/** Session with the hashed refresh token */
|
||||||
const session = await findSession({
|
const session = await findSession(
|
||||||
|
{
|
||||||
userId: userId,
|
userId: userId,
|
||||||
refreshToken: refreshToken,
|
refreshToken: refreshToken,
|
||||||
});
|
},
|
||||||
|
{ lean: false },
|
||||||
|
);
|
||||||
|
|
||||||
if (session && session.expiration > new Date()) {
|
if (session && session.expiration > new Date()) {
|
||||||
const token = await setAuthTokens(userId, res, session._id);
|
const token = await setAuthTokens(userId, res, session);
|
||||||
res.status(200).send({ token, user });
|
res.status(200).send({ token, user });
|
||||||
} else if (req?.query?.retry) {
|
} else if (req?.query?.retry) {
|
||||||
// Retrying from a refresh token request that failed (401)
|
// Retrying from a refresh token request that failed (401)
|
||||||
|
|
|
@ -357,23 +357,18 @@ const resetPassword = async (userId, token, password) => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Auth Tokens
|
* Set Auth Tokens
|
||||||
*
|
|
||||||
* @param {String | ObjectId} userId
|
* @param {String | ObjectId} userId
|
||||||
* @param {Object} res
|
* @param {ServerResponse} res
|
||||||
* @param {String} sessionId
|
* @param {ISession | null} [session=null]
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const setAuthTokens = async (userId, res, sessionId = null) => {
|
const setAuthTokens = async (userId, res, _session = null) => {
|
||||||
try {
|
try {
|
||||||
const user = await getUserById(userId);
|
let session = _session;
|
||||||
const token = await generateToken(user);
|
|
||||||
|
|
||||||
let session;
|
|
||||||
let refreshToken;
|
let refreshToken;
|
||||||
let refreshTokenExpires;
|
let refreshTokenExpires;
|
||||||
|
|
||||||
if (sessionId) {
|
if (session && session._id && session.expiration != null) {
|
||||||
session = await findSession({ sessionId: sessionId }, { lean: false });
|
|
||||||
refreshTokenExpires = session.expiration.getTime();
|
refreshTokenExpires = session.expiration.getTime();
|
||||||
refreshToken = await generateRefreshToken(session);
|
refreshToken = await generateRefreshToken(session);
|
||||||
} else {
|
} else {
|
||||||
|
@ -383,6 +378,9 @@ const setAuthTokens = async (userId, res, sessionId = null) => {
|
||||||
refreshTokenExpires = session.expiration.getTime();
|
refreshTokenExpires = session.expiration.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const user = await getUserById(userId);
|
||||||
|
const token = await generateToken(user);
|
||||||
|
|
||||||
res.cookie('refreshToken', refreshToken, {
|
res.cookie('refreshToken', refreshToken, {
|
||||||
expires: new Date(refreshTokenExpires),
|
expires: new Date(refreshTokenExpires),
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
|
|
|
@ -873,6 +873,13 @@
|
||||||
* @typedef {import('@librechat/data-schemas').IMongoFile} MongoFile
|
* @typedef {import('@librechat/data-schemas').IMongoFile} MongoFile
|
||||||
* @memberof typedefs
|
* @memberof typedefs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @exports ISession
|
||||||
|
* @typedef {import('@librechat/data-schemas').ISession} ISession
|
||||||
|
* @memberof typedefs
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @exports IBalance
|
* @exports IBalance
|
||||||
* @typedef {import('@librechat/data-schemas').IBalance} IBalance
|
* @typedef {import('@librechat/data-schemas').IBalance} IBalance
|
||||||
|
|
|
@ -98,12 +98,6 @@ if (typeof window !== 'undefined') {
|
||||||
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');
|
||||||
|
@ -124,7 +118,10 @@ if (typeof window !== 'undefined') {
|
||||||
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 ?? '';
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue