英文:
NestJS - Passport JWT strategy does not attach user to request object
问题
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?
英文:
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?
答案1
得分: 1
The object returned by the getRequest
method needs to be the same instance as ctx.req
so that when you access ctx.req
it 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.
英文:
The object returned by the getRequest
method needs to be the same instance as ctx.req
so that when you access ctx.req
it 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论