Last active
April 6, 2024 21:49
-
-
Save SirojbekMaqsudov/0c6a1e690e9e52c5fd54376bd5ced235 to your computer and use it in GitHub Desktop.
next-auth token refresh rotation and axios interceptor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import axios from "axios"; | |
import {getCsrfToken, getSession, signOut} from "next-auth/react"; | |
const refreshToken = async (token) => { | |
const response = await fetch(`${process.env.API_URL}/auth/refresh`, { | |
method: 'POST', | |
headers: { | |
'Authorization': `Bearer ${token}`, | |
'Content-Type': 'application/json' | |
} | |
}); | |
const res = await response.json(); | |
if (res.code && res.code === 401) { | |
await signOut() | |
return; | |
} | |
await updateSession(res.data) | |
const reloadSession = () => { | |
const event = new Event("visibilitychange"); | |
document.dispatchEvent(event); | |
}; | |
if (document) reloadSession() | |
return res.data; | |
}; | |
const updateSession = async (data) => { | |
const session = await getSession(); | |
const csrfToken = await getCsrfToken(); | |
const updatedSessionData = { ...session, ...data}; | |
await fetch(`${process.env.NEXTAUTH_URL}/api/auth/session`, { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ | |
csrfToken: csrfToken, | |
data: { | |
...updatedSessionData | |
} | |
}) | |
}); | |
}; | |
let isRefreshing = false; | |
let refreshAndRetryQueue = [] | |
const Api = () => { | |
const instance = axios.create({ | |
baseURL: process.env.API_URL | |
}) | |
instance.interceptors.request.use(async (request) => { | |
const session = await getSession(); | |
if (session && session.user) { | |
request.headers.Authorization = `Bearer ${session.token}`; | |
} | |
return request; | |
}); | |
instance.interceptors.response.use( | |
(response) => response, | |
async (error) => { | |
const originalRequest = error.config; | |
const session = await getSession(); | |
if (error?.response?.status === 401 && session && session.user) { | |
if (!isRefreshing) { | |
isRefreshing = true | |
try { | |
const data = await refreshToken(session.refresh_token); | |
originalRequest.headers.Authorization = `Bearer ${data.token}`; | |
refreshAndRetryQueue.forEach(({ config, resolve, reject }) => { | |
instance.request(config) | |
.then(response => resolve(response)) | |
.catch(err => reject(err)) | |
}) | |
refreshAndRetryQueue.length = 0 | |
return axios(originalRequest); | |
}catch (e) { | |
console.log(e) | |
}finally { | |
isRefreshing = false | |
} | |
} | |
return new Promise((resolve, reject) => { | |
refreshAndRetryQueue.push({config: originalRequest, resolve, reject}) | |
}) | |
} | |
return Promise.reject(error); | |
} | |
); | |
return instance | |
} | |
export default Api() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
don't forget to ⭐ it