Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
Using Postman to test my endpoints, I am able to successfully "login" and receive a JWT token. Now, I am trying to hit an endpoint that supposedly has an
AuthGuard
to ensure that now that I am logged in, I can now access it.
However, it constantly returns
401 Unauthorized
even when presented the JWT token in Postman.
Here is my code:
user.controller.ts
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@UseGuards(AuthGuard())
@Get()
getUsers() {
return this.usersService.getUsersAsync();
jwt.strategy.ts
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authenticationService: AuthenticationService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: 'SuperSecretJWTKey',
async validate(payload: any, done: Function) {
console.log('I AM HERE'); // this never gets called.
const user = await this.authenticationService.validateUserToken(payload);
if (!user) {
return done(new UnauthorizedException(), false);
done(null, user);
I have tried ExtractJWT.fromAuthHeaderWithScheme('JWT')
as well but that does not work.
authentication.module.ts
@Module({
imports: [
ConfigModule,
UsersModule,
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secret: 'SuperSecretJWTKey',
signOptions: { expiresIn: 3600 },
controllers: [AuthenticationController],
providers: [AuthenticationService, LocalStrategy, JwtStrategy],
exports: [AuthenticationService, LocalStrategy, JwtStrategy],
export class AuthenticationModule {}
authentication.controller.ts
@Controller('auth')
export class AuthenticationController {
constructor(
private readonly authenticationService: AuthenticationService,
private readonly usersService: UsersService,
@UseGuards(AuthGuard('local'))
@Post('login')
public async loginAsync(@Response() res, @Body() login: LoginModel) {
const user = await this.usersService.getUserByUsernameAsync(login.username);
if (!user) {
res.status(HttpStatus.NOT_FOUND).json({
message: 'User Not Found',
} else {
const token = this.authenticationService.createToken(user);
return res.status(HttpStatus.OK).json(token);
In Postman, I am able to use my login endpoint to successfully login with the proper credentials and receive a JWT token. Then, I add an Authentication
header to a GET request, copy and paste in the JWT token, and I have tried both "Bearer" and "JWT" schemes and both return 401 Unauthorized
as you can see in the images below.
I used the JWT.IO debugger, to check if there's anything wrong with my token and it appears correct:
I am at a lost as to what could be the issue here. Any help would be greatly appreciated.
–
Note that the validate()
function in your JWT strategy is only called after successful validation of the JWT. If you are consistently getting a 401 response when trying to use the JWT then you can't expect this function to be called.
The return
from the validate()
method is injected into the request object of any operation that's guarded with JWT authentication.
I'm not sure about the done()
function that you're calling, but here's a working validate()
method from a current project of mine:
async validate(payload: JwtPayload): Promise<User> {
const { email } = payload
const user = await this.authService.getActiveUser(email)
if (!user) {
throw new UnauthorizedException()
return user
It looks like you're on the right track in the desire to return a user. Be sure that's what authenticationService.validateUserToken()
actually does.
In the strategy, jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
seems correct, and in Postman using Authorization header with Bearer TOKEN
also looks correct.
Regarding your authentication.controller.ts
file, be careful about using @Request
and @Response
objects directly within your controllers in NestJS. These access the underlying framework e.g. Express and are liable to bypass many of the features implemented by Nest. Refer to https://docs.nestjs.com/faq/request-lifecycle to see what you're skipping out on...
You can return objects and throw errors directly from a decorated controller method (e.g. @Get()
, Post()
, etc) in NestJS and the framework will take care of the rest: HTTP code, JSON, etc.
From your controller consider ditching the @Reponse res
and using throw new UnauthorizedException('User Not Found')
and a simple return { token }
(or similar) approach instead.
In your protected route I have found that explicitly declaring AuthGuard('jwt')
works better and doesn't produce warnings in certain cases, even if you did set your default strategy to be JWT.
Do you actually need the AuthGuard('local')
on your login route?
Inside your loginAsync()
method DO NOT forget the crucial step of actually signing your token with your payload. You didn't provide your code for the createToken()
method implementation in your authentication service, but I suspect that this may be what you're missing.
Consider this working implementation of a login service (which is simply called by it's controller's login function):
async login(authCredentialsDto: AuthCredentialsDto): Promise<{ accessToken: string }> {
const { email, password } = authCredentialsDto
const success = await this.usersRepository.verifyCredentials(email, password)
if (!success) {
throw new UnauthorizedException('Invalid credentials')
// roles, email, etc can be added to the payload - but don't add sensitive info!
const payload: JwtPayload = { email }
const accessToken = this.jwtService.sign(payload)
this.logger.debug(`Generated JWT token with payload ${JSON.stringify(payload)}`)
return { accessToken }
Note that the jwtService
is injected into the class via Dependency Injection by adding private jwtService: JwtService
to the constructor params.
Also note in the above how an interface is defined for the JwtPayload
so it is explicitly typed. This is better than using any
as you are in your code.
Finally, if your JWT still doesn't validate, make absolutely sure that you are correctly using your token in Postman. Be extremely careful that you're not adding leading/trailing spaces, newlines, etc. I have made this mistake myself. You may want to sanity check by writing a quick JS file to try your API and make a fetch request that sets the Authorization header with value Bearer ${token}
.
I hope this helps, good luck!
–
–
–
I had the same issue.
The issue in my case that the validate endpoint params where email
and password
,
while the nest auth documentation states that they should be username
and password
as the following:
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) {
throw new UnauthorizedException();
return user;
Also be aware to send username
and password
in the body of the request.
Credits:
https://github.com/nestjs/docs.nestjs.com/issues/875#issuecomment-619472086
–
Mine was that I was using RS256 algorithm to sign the JWT and I had a "Invalid algorithm" error.
So I added the "RS256"
to my jwtStrategy
constructor so now it look like this:
constructor(private configService: ConfigService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
algorithms:["RS256"],
secretOrKey: configService.get('jwtPublicKey'),
Then it gave me an error complaining about "no start line" on my public key file, the error was that I had an ssh-rsa key format instead of rsa-pem format, I solved with Get PEM file from ssh-rsa key pair
And the finally it worked.
I got all this info, putting a logger between the strategy output and the guard output, doing this JWT Auth Guard example
–
Make Sure that inside your strategy the path of secretKey in
secretOrKey is implemented correctly.
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: appConfig().appSecret,
async validate(payload: any) {
return { userId: payload.userId, username: payload.username };
I had a similar 401 status. My problem was that the token expiration was set to '240' I thought wrong it is 240 seconds... but not it was 240 miliseconds...
after i change to '240s' it works fine../
read more about the 'zeit/ms' format here
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.