Problem
Hello, I'm currently utilizing middleware to verify whether the user's access token stored in cookies has expired. If it has, the middleware automatically initiates a request to an API I created. This API generates a new access token using the refresh token, also found in the cookies.
However, I'm encountering an issue. When I intentionally expire the token for testing purposes and refresh the page to activate the middleware, I notice that the tokens in the cookies are simply replaced with their previous values, instead of being updated.
The primary objective is to use the middleware to monitor the expiration status of the user's access token. This approach is ideal as the middleware can be activated across the entire application. If the token is found to be expired, the middleware should then acquire new tokens and update them in the cookies.
Files
middleware.ts
import { cookies } from "next/headers";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
export async function middleware(request: NextRequest) {
const { cookies } = request;
const logged_in = cookies.get("logged_in");
const path = request.nextUrl.pathname;
const access_token = cookies.get("access_token");
const refresh_token = cookies.get("refresh_token");
const generated_at = cookies.get("generated_at");
const expires_in = cookies.get("expires_in");
// Check if the access token is expired
if (access_token && refresh_token && generated_at && expires_in) {
const now = Date.now();
const expires_at =
parseInt(generated_at.value) + parseInt(expires_in.value) * 1000;
if (now > expires_at) {
// EXPIRED
console.log("EXPIRED");
const result = await fetch("https://localhost:3000/api/refresh-token", {
method: "POST",
body: JSON.stringify({ refresh_token: refresh_token.value }),
});
if (result) {
console.log("REFRESHED");
}
}
}
if (path === "/") {
if (!logged_in) {
return NextResponse.redirect(new URL("/login", request.url));
}
}
if (path === "/login") {
if (logged_in) {
return NextResponse.redirect(new URL("/", request.url));
}
}
}
app\api\refresh-token\route.ts
import { BungieTokensResponseType } from "@/types";
import StoreTokensInCookies from "@/utils/StoreTokensInCookies";
export async function POST(
request: Request,
): Promise<BungieTokensResponseType | Response> {
const { refresh_token }: { refresh_token: string } = await request.json();
if (!refresh_token) {
return Response.json(
{ message: "No refresh token provided" },
{ status: 400 },
);
}
if (refresh_token) {
const options = {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
grant_type: "refresh_token",
refresh_token,
client_id: process.env.BUNGIE_CLIENT_ID as string,
client_secret: process.env.BUNGIE_CLIENT_SECRET as string,
}),
};
const result = await fetch(
"https://www.bungie.net/Platform/App/OAuth/token/",
options,
);
const Tokens: BungieTokensResponseType = await result.json();
StoreTokensInCookies(Tokens);
return new Response(JSON.stringify(Tokens), { status: 200 });
}
return Response.json({ message: "Unknown error" }, { status: 500 });
}