I am building an auth flow using NextAuth on a Next.js frontend, and Passport JWT on a NestJS + GraphQL backend. NextAuth gets a JWT token from a third party provider, and then attaches it to the auth header. In the backend, it is handled by a global auth guard.
Here is the guard:
@Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') {
constructor(@Inject(UserRoleMetadataService) private readonly userRoleMetadataService: UserRoleMetadataService) {
super();
}
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
if (this.userRoleMetadataService.isPublicResource(context)) {
return true;
}
return super.canActivate(context);
}
getRequest(context: ExecutionContext) {
const ctx = GqlExecutionContext.create(context);
return this.userRoleMetadataService.getRequestWithAuthHeaders(ctx);
}
}
Validate method from strategy:
async validate(req, payload: KnomeJwtPayload): Promise<UserEntity> {
const user = await this.userService.getOrCreateUser(payload);
await this.verifyAuthorization(req, user.roles);
const isOwnerRequired = this.userRoleMetadataService.readIsOwnerRequiredHeader(req);
if (isOwnerRequired) {
this.verifyOwnership(req, user.id);
}
return user;
}
and user decorator:
const CurrentUser = createParamDecorator((data, ctx) => {
const context = GqlExecutionContext.create(ctx).getContext();
return context.req.user;
})
Everything is working as expected up until the return statement from the strategy. I logged the user object that is returned, and it is exactly what I expect. However, for some reason that user object is not being attached to the request and is therefore undefined in the decorator. What am I doing wrong?
The object returned by the
getRequestmethod needs to be the same instance asctx.reqso that when you accessctx.reqit has the new properties. As you mentioned in a comment it was a shallow copy but has been reworked to be the same object reference