ananay / passport-apple

Passport strategy for Sign in with Apple
https://passport-apple.ananay.dev
142 stars 49 forks source link

Profile is empty in Nestjs #47

Open sujayroro opened 1 year ago

sujayroro commented 1 year ago

Profile parameter returns empty object on validate function Nestjs.

ananay commented 1 year ago

Hello, this seems to be working for me.

Please note that the profile info (a.k.a the First and Last Name) are shown only the FIRST time you sign in to the app. The next time you sign in, Apple will not provide you with this information.

image

You can revoke the app by going into Sign in with Apple section on appleid.apple.com

image
utshomax commented 1 year ago

Same issue here with express. returns empty object.

zenstok commented 1 year ago

It will always return empty object for profile, because this package actually never sets the profile attribute. @ananay if you want to implement it, you will need to override this method https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js#L318, but from what i've seen, Apple is not using access token, so I don't think it's possible now.

You can use my template below which should work with @nestjs/passport 10.0.2.

@Injectable()
export class AppleStrategy extends PassportStrategy(Strategy, 'apple', 6) {
  constructor(
    configService: ConfigService,
    configHelperService: ConfigHelperService,
  ) {
    super({
      clientID: configService.get('APPLE_CLIENT_ID'),
      teamID: configService.get('APPLE_TEAM_ID'),
      keyID: configService.get('APPLE_KEY_ID'),
      privateKeyLocation: configService.get('APPLE_APPLICATION_CREDENTIALS'),
      callbackURL: configHelperService.getAppleCallbackUrl(),
      passReqToCallback: true,
    });
  }

  async validate(
    req: any,
    accessToken: string,
    refreshToken: string,
    idToken: string,
    profile: any,
    done: VerifyCallback,
  ): Promise<any> {
    console.log('apple profile', req.appleProfile); // this will be available only on first request, subsequent requests will give you undefined
    console.log('accessToken', accessToken);
    console.log('refreshToken', refreshToken);
    console.log('idToken', idToken); // from this you can retrieve the user id and email (email can be hidden)
    console.log('profile', profile); // this will always be an empty object
    console.log('done', done);

    // for security reasons, you should also check if the token is valid, check iss, aud, exp, etc.

    done(null, {});
  }
}
BijanRegmi commented 5 months ago

It will always return empty object for profile, because this package actually never sets the profile attribute. @ananay if you want to implement it, you will need to override this method https://github.com/jaredhanson/passport-oauth2/blob/master/lib/strategy.js#L318, but from what i've seen, Apple is not using access token, so I don't think it's possible now.

You can use my template below which should work with @nestjs/passport 10.0.2.

@Injectable()
export class AppleStrategy extends PassportStrategy(Strategy, 'apple', 6) {
  constructor(
    configService: ConfigService,
    configHelperService: ConfigHelperService,
  ) {
    super({
      clientID: configService.get('APPLE_CLIENT_ID'),
      teamID: configService.get('APPLE_TEAM_ID'),
      keyID: configService.get('APPLE_KEY_ID'),
      privateKeyLocation: configService.get('APPLE_APPLICATION_CREDENTIALS'),
      callbackURL: configHelperService.getAppleCallbackUrl(),
      passReqToCallback: true,
    });
  }

  async validate(
    req: any,
    accessToken: string,
    refreshToken: string,
    idToken: string,
    profile: any,
    done: VerifyCallback,
  ): Promise<any> {
    console.log('apple profile', req.appleProfile); // this will be available only on first request, subsequent requests will give you undefined
    console.log('accessToken', accessToken);
    console.log('refreshToken', refreshToken);
    console.log('idToken', idToken); // from this you can retrieve the user id and email (email can be hidden)
    console.log('profile', profile); // this will always be an empty object
    console.log('done', done);

    // for security reasons, you should also check if the token is valid, check iss, aud, exp, etc.

    done(null, {});
  }
}

even with this implementation i am receiving empty idToken {}

VinzSpring commented 3 months ago

My idToken is an empty object aswell!