rkusa/koa-passport

passport serialize user: next is not a function

m0g opened this issue · 2 comments

m0g commented

Hello,

I'm experiencing an issue with koa-passport and can't be a 100% sure that the problem is due to this library.
I'm using an Azure B2C authentication and I'm getting the following error:

  TypeError: next is not a function
      at p.then.cont (/my-custom-path/node_modules/koa-passport/lib/framework/koa.js:150:16)
      at process._tickCallback (internal/process/next_tick.js:68:7)

it seems that problem is occuring right after the done() callback is passport.serializeUser

Here is my passport.ts:

import { Repository } from 'typeorm';
import { validate, ValidationError } from 'class-validator';
import { User, getManager } from 'my-project-shared';
import * as passport from 'koa-passport';
import { OIDCStrategy } from 'passport-azure-ad';

...

const azureOIDCOptions = {
  identityMetadata,
  clientID,
  isB2C: true,
  validateIssuer: true,
  loggingLevel: 'info',
  responseType: 'id_token',
  responseMode: 'query',
  allowHttpForRedirectUrl: true, 
  redirectUrl,
  passReqToCallback: false,
}

/**
 * Sign in using Azure B2C for Web
 */
passport.use(new OIDCStrategy(azureOIDCOptions, async (profile, done) => {
  console.log('AZURE B2C')
  // get a user repository to perform operations with user
  const userRepository: Repository<User> = getManager().getRepository(User);
  const userToBeSaved: User = new User();

  userToBeSaved.firstName = profile.name.givenName;
  userToBeSaved.lastName = profile.name.familyName;
  userToBeSaved.email = profile.emails[0];

  // validate user entity
  const errors: ValidationError[] = await validate(userToBeSaved); // errors is an array of validation errors

  if (errors.length === 0) {
    try {
      const user = await userRepository.save(userToBeSaved);
      done(null, user.id);
    } catch (e) {
      done(e)
    }
  }
}));

passport.serializeUser((user, done) => {
  console.log('serialize', user);
  done(null, user)
})

passport.deserializeUser(async (userId, done) => {
  console.log('deserialize');
  const userRepository: Repository<User> = getManager().getRepository(User);
  const user: User = await userRepository.findOne(userId);

  return user;
});
rkusa commented

Can you show the code where you call passport.authenticate?

m0g commented

My bad, I was actually missing the next function.

  public static async adb2c(ctx: BaseContext, next: Function) {
    return passport.authenticate(
      'azuread-openidconnect',
      {
        // Let the frontend provide options for the user to proceed
        failureRedirect: frontendUrl
      },
      (a, user) => {
        ctx.login(user);
        ctx.redirect(`${frontendUrl}/successful-login`);
      }
    )(ctx, next);
  }