Using an endpoint like /api/users/me
Server-side
Probably you don't only need to know if a user is already logged in but also who that user is. Therefore many APIs implement an endpoint like /api/users/me which authenticates the request via the sent cookie or authorization header (or however you've implemented your server to authenticate requests).
Then, if the request is successfully authenticated, it returns the current user. If the authentication fails, return a 401 Not Authorized (see Wikipedia for status codes).
The implementation could look like this:
// UsersController.ts
// [...]
initializeRoutes() {
this.router.get('users/me', verifyAuthorization(UserRole.User), this.getMe);
}
async getMe(req: Request, res: Response) {
// an AuthorizedRequest has the already verified JWT token added to it
const { id } = (req as AuthorizedRequest).token;
const user = await UserService.getUserById(id);
if (!user) {
throw new HttpError(404, 'user not found');
}
logger.info(`found user <${user.email}>`);
res.json(user);
}
// [...]
// AuthorizationMiddleware.ts
export function verifyAuthorization(expectedRole: UserRole) {
// the authorization middleware throws a 401 in case the JWT is invalid
return async function (req: Request, res: Response, next: NextFunction) {
const authorization = req.headers.authorization;
if (!authorization?.startsWith('Bearer ')) {
logger.error(`no authorization header found`);
throw new HttpError(401, 'unauthorized');
}
const token = authorization.split(' ')[1];
const decoded = AuthenticationService.verifyLoginToken(token);
if (!decoded) {
logger.warn(`token not verified`);
throw new HttpError(401, 'unauthorized');
}
(req as AuthorizedRequest).token = decoded;
const currentRole = UserRole[decoded.role] ?? 0;
if (currentRole < expectedRole) {
logger.warn(`user not authorized: ${UserRole[currentRole]} < ${UserRole[expectedRole]}`);
throw new HttpError(403, 'unauthorized');
}
logger.debug(`user authorized: ${UserRole[currentRole]} >= ${UserRole[expectedRole]}`);
next();
};
}
Client-side
If the response code is 200 OK and contains the user data, store this data in-memory (or as alternative in the local storage, if it doesn't include sensitive information).
If the request fails, redirect to the login page (or however you want your application to behave in that case).