Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sign in with apple #462

Closed
SuperKruse opened this issue Jun 3, 2020 · 5 comments · Fixed by #476
Closed

Sign in with apple #462

SuperKruse opened this issue Jun 3, 2020 · 5 comments · Fixed by #476
Labels
feature New functionality or improvement

Comments

@SuperKruse
Copy link

SuperKruse commented Jun 3, 2020

Support plan

  • which support plan is this issue covered by? (e.g. Community, Core, Plus, or Enterprise): Community
  • is this issue currently blocking your project? (yes/no): no
  • is this issue affecting a production system? (yes/no): no

Context

  • node version: latest
  • module version: latest
  • environment (e.g. node, browser, native): node
  • used with (e.g. hapi application, another framework, standalone, ...): hapi
  • any other relevant information: n/a

What problem are you trying to solve?

I'm setting up "Sign in with Apple" with bell and hapi.

I have made a custom provider and gotten everything to work, but there are a few problems.

The biggest problem is apple uses a JWT as clientSecret, which have an expire date.

My apple strategy looks like this right now.

    server.auth.strategy('apple', 'bell', {
      clientId: oAuthClients.apple.clientId,
      clientSecret: getSecretKey(),
      provider: apple,
      providerParams: { response_mode: 'query' },
    })

The getSecretKey() generates a JWT that expires in six months and then it will stop working (if it doesn't get restarted)

Next problem; apple doesn't have a getProfile-url, instead they return a JWT with the user email when authenticating.

My custom provider:

const apple = {
  auth: 'https://appleid.apple.com/auth/authorize',
  token: 'https://appleid.apple.com/auth/token',
  name: 'apple',
  protocol: 'oauth2',
  useParamsAuth: true,
  profile: async (credentials, params) => {
    const resp = jwt.verify(params.id_token, getSecretKey())
    const { sub, email } = resp
    credentials.profile = { id: sub, email }
    return credentials
  },
}

As you can see in the profile function I use a jwt.verify and the clientSecret to get the token payload.

Do you have a new or modified API suggestion to solve the problem?

Making the clientSecret take a function could fix the token expire issue.

Getting the profile issue could be solved-ish by adding the clientSecret to the profile params, but it would still require a jwt library.

If adding a jwt library is a possibility I think it would make sense to use that to create the clientSecret as well.

Another possibility could be to add a verify/decode-token function to the config object and use that to get the user profile (dependency injection?).
Then it wouldn't be necessary to add a jwt library to bell.

The getSecretKey for reference

const getSecretKey = () => {
    const claims = {
      iss: teamId,
      iat: Math.floor(Date.now() / 1000),
      exp: Math.floor(Date.now() / 1000) + 86400 * 180,
      aud: 'https://appleid.apple.com',
      sub: appId,
    }

    const token = sign(claims, privateKey, {
      algorithm: 'ES256',
      keyid: keyId,
    })

	return token
}

I will gladly make a pull request for an apple provider, if you want that.

@SuperKruse SuperKruse added the feature New functionality or improvement label Jun 3, 2020
@hueniverse
Copy link
Contributor

Adding a JWT library is not possible at this time, but adding function support to enable this to work is something I'm open to. If you want to give it a try and open a PR, I'll take a look.

@lloydbenson
Copy link
Contributor

It looks like a PR was never done here so I'm going to close this issue up. If you do get time later, feel free to open up a new issue.

@annahassel
Copy link

annahassel commented Apr 1, 2021

Maybe that will be useful for someone to avoid problem with "code" parameter and POST callback from Apple server.

const fixAppleCallbackForBell = (request, h) => {
  if (request.method === 'post' && request.path === '/users/oauth/apple') {
    const { raw: { req } } = request;
    let payload = '';

    return new Promise((resolve, reject) => {
      req.on('error', reject);
      req.on('data', (chunk) => { payload += chunk });
      req.on('end', () => {
        request.setUrl(`/users/oauth/apple?${payload}`);
        resolve(h.continue);
      });
    });
  }

  return h.continue;
};

server.ext('onRequest', fixAppleCallbackForBell);

@Nargonath
Copy link
Member

Also @SuperKruse this landed in the latest bell version: #476 which might be of interest to you.

@harryadel
Copy link

For anyone who is trying to implement Apple sign-in using bell. I came up with article that explains everything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New functionality or improvement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants