Reputation: 2959
I need to check if there's a token and if the token expired in getInitialProps, and then if the token is expired clear the Cookies from the browser and sign out the user.
Here's what I'm doing so far ...
const isTokenExpired = (token) => {
const currentTime = new Date().getTime() / 1000;
const decodedToken: MetadataObj = jwt_decode(token);
if (decodedToken.exp < currentTime) {
return true;
} else {
return false;
}
};
import nextCookie from "next-cookies";
import Cookies from "js-cookie";
MyApp.getInitialProps = async ({ctx}: any) => {
const { WebsiteToken } = nextCookie(ctx);
if (WebsiteToken ) {
if (isTokenExpired(WebsiteToken )) {
console.log("Token Expired");
Cookies.remove("WebsiteToken ");
}
}
}
The console log works, but the Cookie is not removed from the browser, I know that this is because it didn't hit the client-side, but how can I do that from the server?
Upvotes: 6
Views: 17150
Reputation: 47
I've spent quite a lot of time on this issue. Finally, the mix of server-side and client-side code works for me. First, return an error on the server side. Then, check it inside the client-side component. I hope it will be helpful for someone else.
// Server-side code: pages/api/auth/[...nextauth].js
import NextAuth from 'next-auth';
import KeycloakProvider from 'next-auth/providers/keycloak';
const ISSUER = '...';
const REALM = '...';
export default async function auth(req, res) {
async function createProviders() {
const config = {
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
issuer: ISSUER,
realm: REALM,
};
return [KeycloakProvider(config)];
}
async function refreshAccessToken(token, issuer) {
try {
/// ... attempt to refresh token here
} catch (error) {
return {
...token,
// This error will be catched on the client-side
error: 'REFRESH_TOKEN_ERROR',
};
}
}
const providers = await createProviders();
const authOptions = {
providers,
callbacks: {
async session({ session, token }) {
// ...
return session;
},
async jwt({ token, user, account }) {
// Initial sign in
if (account && user) {
// ...
return {
accessToken: account.access_token,
accessTokenExpires: account.expires_at * 1000,
refreshToken: account.refresh_token,
user,
realm: REALM,
};
}
// Return previous token if the access token has not expired yet
if (Date.now() < token.accessTokenExpires) {
return token;
}
// Access token has expired, try to update it
return refreshAccessToken(token, ISSUER);
},
},
pages: {
signIn: '/auth/signin',
},
};
return NextAuth(req, res, authOptions);
}
// Client-side code
'use client';
import { useRouter } from 'next/navigation';
import { useSession, signOut } from 'next-auth/react';
import React, { useEffect } from 'react';
import { Page } from '...';
function LoggedIn() {
const { data } = useSession({ required: true });
const router = useRouter();
useEffect(() => {
// check for error
if (data?.error === 'REFRESH_TOKEN_ERROR') {
signOut();
}
}, [data, router]);
if (!data) return null;
return <Page />;
}
Upvotes: 0
Reputation: 61
For my case, for NextJS 12.3.1 I did the following way
import type { NextResponse } from 'next/server'
export async function deleteCookie(res: NextResponse) {
res.cookies.set('cookie_name', '', {
httpOnly: true,
maxAge: 0, // 0 second hours in seconds
})
return res
}
Upvotes: 0
Reputation: 173
You can erase cookies by setting the header:
ctx.res.setHeader(
"Set-Cookie", [
`WebsiteToken=deleted; Max-Age=0`,
`AnotherCookieName=deleted; Max-Age=0`]
);
It will set the cookie value to be "deleted" but that is not important because Max-Age=0
means that cookie will expire immediately and browser will delete it.
Upvotes: 12