Skip to content

Instantly share code, notes, and snippets.

@Jhoem
Last active November 22, 2023 06:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jhoem/0234badd1ca41b0658f2cd78e00ec682 to your computer and use it in GitHub Desktop.
Save Jhoem/0234badd1ca41b0658f2cd78e00ec682 to your computer and use it in GitHub Desktop.
Sample logout on nestjs using Cache manager w/ Redis for invalidating tokens
async logout({ jwt }) {
const { token, exp: expirationTime = 0 } = jwt;
// Convert current date to timestamp in seconds
const currentTimestamp = Math.floor(Date.now() / 1000);
const remainingTTL = expirationTime - currentTimestamp;
if (remainingTTL <= 0) {
throw new UnauthorizedException(AuthErrors.tokenExpired);
}
// Note that multiple jwt tokens can exist at any given time
// Blacklist the token until it expires base from it's original `exp`
await this.cacheManager.set(
`${jwtConstants.prefixExpired}${token}`,
true,
remainingTTL,
);
return {
status: 'success',
message: Messages.loggedOut,
};
}
import { PassportStrategy } from '@nestjs/passport';
import { JwtService } from '@nestjs/jwt';
import {
Injectable, Inject, UnauthorizedException, CACHE_MANAGER,
} from '@nestjs/common';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { Cache } from 'cache-manager';
import { jwtConstants } from 'src/config/auth';
import { AuthErrors } from 'src/common/translation';
import { JwtSession } from 'src/common/interfaces/jwt_session';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(
@Inject(CACHE_MANAGER) private cacheManager: Cache,
private jwtService: JwtService,
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: jwtConstants.options.secret,
passReqToCallback: true,
});
}
async validate(req, { sub: userId, exp }) {
const getJwtToken = ExtractJwt.fromAuthHeaderAsBearerToken();
const jwtToken = getJwtToken(req);
const cachedSessionId = `${jwtConstants.prefix}${userId}`;
const expiredJwtId = `${jwtConstants.prefixExpired}${jwtToken}`;
const isTokenExpired = await this.cacheManager.get<boolean>(expiredJwtId);
const jwtSession = await this.cacheManager.get<JwtSession>(cachedSessionId);
// Check if token has expired or has no active session
if (isTokenExpired || !jwtSession) {
throw new UnauthorizedException(
isTokenExpired ? AuthErrors.tokenExpired : AuthErrors.tokenInvalid,
);
}
// Attach `user` property to `req`
return {
userId,
role: jwtSession.role,
jwt: {
token: jwtToken,
// current token's expiration
exp,
},
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment