Skip to content

Commit

Permalink
feat: refactored to logout user when refresh token expires
Browse files Browse the repository at this point in the history
  • Loading branch information
NithinKuruba committed Nov 26, 2023
1 parent b94d1f5 commit 600c8e7
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 33 deletions.
24 changes: 14 additions & 10 deletions app/layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCommentDots, faEnvelope, faFileAlt } from '@fortawesome/free-solid-svg-icons';
import Button from '@button-inc/bcgov-theme/Button';
import Footer from '@button-inc/bcgov-theme/Footer';
import StyledLink from '@button-inc/bcgov-theme/Link';
import styled from 'styled-components';
import { startCase } from 'lodash';
import BCSans from './BCSans';
import Navigation from './Navigation';
import BottomAlertProvider from './BottomAlert';
import { useSession } from 'next-auth/react';
import { getSession, useSession } from 'next-auth/react';
import { useEffect } from 'react';
import { User } from 'next-auth';

Expand Down Expand Up @@ -164,15 +162,21 @@ function Layout({ children, onLoginClick, onLogoutClick }: any) {
const currentUser: Partial<User> = session?.data?.user!;
const pathname = router.pathname;

useEffect(() => {
// logout user when both access and refresh tokens expire
const interval = setInterval(() => {
if (Date.now() > session?.data?.refreshTokenExpired && Date.now() > session?.data?.accessTokenExpired) {
const checkSession = async () => {
if (Date.now() > session?.data?.accessTokenExpiry) {
const session: any = await getSession();
if (session?.error === 'RefreshAccessTokenError') {
onLogoutClick();
}
}, 1000 * 5);
return () => clearInterval(interval);
}, [session]);
}
};

useEffect(() => {
if (session?.status === 'authenticated') {
const interval = setInterval(checkSession, 1000 * 1);
return () => clearInterval(interval);
}
});

const rightSide = currentUser ? (
<LoggedUser>
Expand Down
37 changes: 14 additions & 23 deletions app/pages/api/auth/[...nextauth].ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@ async function refreshAccessToken(token: any) {
},
);
const refreshedTokens = await response.data;

return {
...token,
accessToken: refreshedTokens.access_token,
accessTokenExpired: Date.now() + (refreshedTokens.expires_in - 15) * 1000,
refreshToken: refreshedTokens.refresh_token ?? token.refreshToken,
refreshTokenExpired: Date.now() + (refreshedTokens.refresh_expires_in - 15) * 1000,
refreshToken: refreshedTokens.refresh_token,
};
} catch (error) {
console.error('refresh token error', error);
Expand Down Expand Up @@ -55,39 +54,31 @@ export const authOptions: NextAuthOptions = {
},
}),
],
session: {
strategy: 'jwt',
maxAge: 10 * 60 * 60, //10 hours, same as sso/client session max
},
secret: process.env.JWT_SECRET,
callbacks: {
async jwt({ token, account, user }: { token: any; account: any; user: any }) {
if (account) {
token.accessToken = account?.access_token;
token.refreshToken = account.refresh_token;
token.accessTokenExpired = Date.now() + (account?.expires_at - 15) * 1000;
token.refreshTokenExpired = Date.now() + (account?.refresh_expires_in - 15) * 1000;
token.user = user;
token.accessToken = account.access_token;
token.refreshToken = account.refresh_token;
}

const decodedToken = jwt.decode(token.accessToken || '') as any;

token.client_roles = decodedToken?.client_roles;
token.given_name = decodedToken?.given_name;
token.family_name = decodedToken?.family_name;
token.preferred_username = decodedToken?.preferred_username;
token.email = decodedToken?.email;
token.idir_username = decodedToken?.idir_username;

if (Date.now() < token.accessTokenExpired) {
return refreshAccessToken(token);
const decodedAccessToken = jwt.decode(token.accessToken || '') as any;
if (Date.now() > decodedAccessToken.exp) {
token = await refreshAccessToken(token);
}

token.accessTokenExpiry = decodedAccessToken?.exp;
return token;
},
async session({ session, token }: { session: any; token: any }) {
// Send properties to the client, like an access_token from a provider.
if (token) {
session.accessToken = token.accessToken;
session.user = token.user;
session.refreshTokenExpired = token.refreshTokenExpired;
session.accessTokenExpired = token.accessTokenExpired;
session.error = token.error || '';
session.accessTokenExpiry = token.accessTokenExpiry;
}

return session;
Expand Down

0 comments on commit 600c8e7

Please sign in to comment.