I'm learning NestJS and trying to implement a login function in GraphQL using Passport's local strategy but always get user = undefined
on the serializeUser function. What am I missing?
// auth.module.ts
@Module({
imports: [UsersModule, PassportModule.register({ session: true })],
providers: [AuthService, AuthResolver, LocalStrategy, LocalSerializer],
})
export class AuthModule {}
// auth.resolver.ts
@Mutation(() => AuthResponse)
@UseGuards(LocalGuard)
login(
@Args('email') _email: string,
@Args('password') _password: string,
@Context() context,
) {
return { userId: context.user.id };
}
// local.strategy.ts
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({ usernameField: 'email' });
}
async validate(email: string, password: string) {
const id = await this.authService.validateUser(email, password);
return id;
}
}
// local.guard.ts
@Injectable()
export class LocalGuard extends AuthGuard('local') {
constructor() {
super();
}
async canActivate(context: ExecutionContext) {
console.log(context.switchToHttp().getRequest());
const result = (await super.canActivate(context)) as boolean;
const ctx = GqlExecutionContext.create(context);
const request = ctx.getContext().req;
await super.logIn(request);
return result;
}
getRequest(context: ExecutionContext) {
const ctx = GqlExecutionContext.create(context);
const req = ctx.getContext();
const args = ctx.getArgs();
req.body = args;
return req;
}
}
// local.serializer.ts
@Injectable()
export class LocalSerializer extends PassportSerializer {
constructor(private readonly usersService: UsersService) {
super();
}
serializeUser(user: User, done: CallableFunction) {
// user = undefined here!
done(null, user.id);
}
async deserializeUser(userId: string, done: CallableFunction) {
const user = await this.usersService.findOne({ where: { id: userId } });
done(null, user);
}
}
// main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const configService = app.get(ConfigService);
const redisClient = createClient({
url: `redis://${configService.get('REDIS_HOST')}:${configService.get(
'REDIS_PORT',
)}`,
});
await redisClient.connect();
app.use(
session({
store: new RedisStore({ client: redisClient }),
secret: configService.get('SESSION_SECRET'),
resave: false,
saveUninitialized: false,
cookie: { secure: true },
}),
);
app.use(passport.initialize());
app.use(passport.session());
await app.listen(3000);
}