Thanks for reading this!
I am following nestjs official course on authentication and authorization. But I am using graphql code first approach instead of rest api that was used in the course. I successfully implemented the logic until I reach the implementation of the creation of an access token guard. I really don’t know what the problem is but it seems that the token is not being extracted to be verified.Or it has something to do with the context.
this is the original code snippet from the official auth course using rest api
import {
CanActivate,
ExecutionContext,
Inject,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { ConfigType } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import jwtConfig from 'src/iam/config/jwt.config';
import { REQUEST_USER_KEY } from 'src/iam/iam.constant';
@Injectable()
export class AccessTokenGuard implements CanActivate {
constructor(
private readonly jwtService: JwtService,
@Inject(jwtConfig.KEY)
private readonly jwtConfiguration: ConfigType<typeof jwtConfig>,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
if (!token) {
throw new UnauthorizedException();
}
try {
const payload = await this.jwtService.verifyAsync(
token,
this.jwtConfiguration,
);
request[REQUEST_USER_KEY] = payload;
console.log(payload);
} catch {
throw new UnauthorizedException();
}
return true;
}
private extractTokenFromHeader(request: Request): string | undefined {
const [_, token] = request.headers.authorization?.split('') ?? [];
return token;
}
}
this is iam.constant.ts file code
export const REQUEST_USER_KEY = 'user';
This is my version with graphql
import {
CanActivate,
ExecutionContext,
Inject,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { ConfigType } from '@nestjs/config';
import { GqlExecutionContext } from '@nestjs/graphql';
import { JwtService } from '@nestjs/jwt';
import jwtConfig from 'src/iam/config/jwt.config';
import { REQUEST_USER_KEY } from 'src/iam/iam.constant';
@Injectable()
export class AccessTokenGuard implements CanActivate {
constructor(
private readonly jwtService: JwtService,
@Inject(jwtConfig.KEY)
private readonly jwtConfiguration: ConfigType<typeof jwtConfig>,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const ctx = GqlExecutionContext.create(context);
const { req } = ctx.getContext(); // Assuming context provides access to request object
// Extract authorization header (adjust based on your context structure)
const authorization = req?.headers?.authorization;
if (!authorization) {
throw new UnauthorizedException(
'Invalid or missing authorization header',
);
}
const token = this.extractTokenFromHeader(authorization);
if (!token) {
throw new UnauthorizedException('Invalid or missing token');
}
try {
const payload = await this.jwtService.verifyAsync(
token,
this.jwtConfiguration,
);
req[REQUEST_USER_KEY] = payload; // Store in context data if applicable
console.log(payload);
} catch (error) {
console.error('JWT verification error:', error);
throw new UnauthorizedException('Invalid token');
}
return true;
}
private extractTokenFromHeader(authorization: string): string | undefined {
const [_, token] = authorization?.split('') ?? [];
return token;
}
}
I am not sure if I should configure the GraphqlModule within the app.module.ts , but after reading some articles I added the context line. Not sure if it’s right or wrong.
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { join } from 'path';
import { ConfigModule } from '@nestjs/config';
import { UsersModule } from './users/users.module';
import * as Joi from 'joi';
import { PrismaModule } from './prisma/prisma.module';
import { PrismaService } from './prisma/prisma.service';
import { IamModule } from './iam/iam.module';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
validationSchema: Joi.object({
DATABASE_URL: Joi.string().required(),
}),
}),
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
context: ({ req }) => ({ req }),
}),
UsersModule,
PrismaModule,
IamModule,
],
controllers: [AppController],
providers: [AppService, PrismaService],
})
export class AppModule {}
I am still getting “Invalid token” error message in the playground as
enter image description here
I really hope to get any sort of guidance or help with this. It’s about a week now I am trying to figure it out. thanks in advance
frdm212 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.