55 lines
1.4 KiB
TypeScript
55 lines
1.4 KiB
TypeScript
import { getSession } from "next-auth/react";
|
|
import { useAuthStore } from "@/store/authStore";
|
|
|
|
const decodeJwtPayload = (token: string) => {
|
|
const parts = token.split(".");
|
|
if (parts.length < 2) {
|
|
console.warn("Invalid JWT format.");
|
|
return null;
|
|
}
|
|
const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
|
|
try {
|
|
const json =
|
|
typeof window !== "undefined"
|
|
? window.atob(padded)
|
|
: Buffer.from(padded, "base64").toString("utf-8");
|
|
return JSON.parse(json);
|
|
} catch (error) {
|
|
console.warn("Failed to decode JWT payload.", error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const isTokenExpired = (token: string) => {
|
|
const payload = decodeJwtPayload(token);
|
|
if (!payload) {
|
|
return true;
|
|
}
|
|
if (typeof payload.exp !== "number") {
|
|
return false;
|
|
}
|
|
const now = Date.now();
|
|
return now >= payload.exp * 1000 - 30_000;
|
|
};
|
|
|
|
export const getAccessToken = async () => {
|
|
const { accessToken, setAccessToken } = useAuthStore.getState();
|
|
if (accessToken && !isTokenExpired(accessToken)) {
|
|
return accessToken;
|
|
}
|
|
if (accessToken) {
|
|
setAccessToken(null);
|
|
}
|
|
const session = await getSession();
|
|
if (session?.error) {
|
|
return null;
|
|
}
|
|
const token = typeof session?.accessToken === "string" ? session.accessToken : null;
|
|
if (token && !isTokenExpired(token)) {
|
|
setAccessToken(token);
|
|
return token;
|
|
}
|
|
return null;
|
|
};
|