NestJS Get current user in GraphQL resolver authenticated with JWT
Wish I could take any sort of credit here, I'm simply passing along information from the course, NestJS Zero To Hero (absolutely fantastic btw).
For NestJS 7:
// get-user.decorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { User } from '../../user/entity/user.entity';
export const GetAuthenticatedUser = createParamDecorator((data, ctx: ExecutionContext): User => {
const req = ctx.switchToHttp().getRequest();
return req.user;
});
You can implement this however you like. I have an auth.controller
that looks something like this:
// auth.controller.ts
import { GetAuthenticatedUser } from './decarator/get-user.decorator';
...
@Controller('api/v1/auth')
export class AuthController {
constructor(private authService: AuthService) {
//
}
...
/**
* Get the currently authenticated user.
*
* @param user
*/
@Post('/user')
@UseGuards(AuthGuard())
async getAuthenticatedUser(@GetAuthenticatedUser() user: User) {
console.log('user', user);
}
Result is something like this:
// console.log output:
user User {
id: 1,
email: '[email protected]',
...
}
In order to use an AuthGuard with GraphQL, extend the built-in AuthGuard class and override the getRequest()
method.
Create a file called gql.guard.ts
(Naming your wish)
@Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') {
getRequest(context: ExecutionContext) {
const ctx = GqlExecutionContext.create(context);
return ctx.getContext().req;
}
}
To get the current authenticated user in your graphql resolver, you can define a @CurrentUser()
decorator (create a file called user.decorator.graphql.ts
)
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
export const CurrentUser = createParamDecorator(
(data: unknown, context: ExecutionContext) => {
const ctx = GqlExecutionContext.create(context);
return ctx.getContext().req.user;
},
);
To use above decorator in your resolver, be sure to include it as a parameter of your query or mutation
@Query(returns => User)
@UseGuards(GqlAuthGuard)
whoAmI(@CurrentUser() user: User) {
return this.usersService.findById(user.id);
}
Read More : https://docs.nestjs.com/security/authentication#graphql
Finally found the answer ... https://github.com/nestjs/graphql/issues/48#issuecomment-420693225 pointed me into the right direction of creating a user decorator
// user.decorator.ts
import { createParamDecorator } from '@nestjs/common';
export const CurrentUser = createParamDecorator(
(data, req) => req.user,
);
And then use this in my resolver method:
import { User as CurrentUser } from './user.decorator';
@Query(returns => User)
@UseGuards(GqlAuthGuard)
whoami(@CurrentUser() user: User) {
console.log(user);
return this.userService.findByUsername(user.username);
}
Now everything works as expected. So all credits of this answer goes to https://github.com/cschroeter
Another approach is to validate web token with whatever package you are using, then create decorator get-user.decorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
export const GetUser = createParamDecorator((data, context: ExecutionContext) => {
const ctx = GqlExecutionContext.create(context).getContext();
return ctx.user
});
then in your resolver, you can use this decorator (@GetUser() user: User) to access the user