1

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);
}
Tiago Brandão
  • 207
  • 3
  • 12

0 Answers0