Needed: Apple Sign-In JWT Not Returning Email for Users Except Using My AppleID

Hi everyone,

I've been working on integrating Apple Sign-In with my web app and have hit a roadblock that I can't seem to resolve.

I've successfully set up an Nginx reverse-proxy for development purposes enabling SSL/TLS to provide HTTPS. I have configured everything using the values from the Apple Developer Console, including identifiers, keys, and IDs.

The sign-in flow works perfectly when I use my Apple ID (which is linked to my developer account). The Apple Sign-In REST API returns a JWT with my email, as expected.

However, when other users sign in with their Apple IDs, the returned JWT doesn't include their email addresses. I am aware that Apple only provides the email on the first sign-in, but this doesn't seem to be the issue here.

Below is the relevant code I'm using (Bun.js, Elysia, Arctic):

import Bun from 'bun';
import { Apple, type AppleCredentials, type AppleTokens } from 'arctic';
import type { BaseAuthAccountInfo } from './type';
import { createPrivateKey } from 'crypto';
import { sign, decode } from 'jsonwebtoken';

const {
    APPLE_CLIENT_ID,
    APPLE_TEAM_ID,
    APPLE_KEY_ID,
    APPLE_CLIENT_SECRET,
    APPLE_CLIENT_SECRET_JWT,
} = Bun.env;

type AppleReponseJWTPayload = {
    iss: string;
    aud: string;
    exp: number;
    iat: number;
    sub: string;
    at_hash: string;
    email: string;
    email_verified: boolean;
    auth_time: number;
    nonce_supported: boolean;
};

const credentials: AppleCredentials = {
    clientId: APPLE_CLIENT_ID!,
    teamId: APPLE_TEAM_ID!,
    keyId: APPLE_KEY_ID!,
    certificate: `-----BEGIN PRIVATE KEY-----\n${APPLE_CLIENT_SECRET}\n-----END PRIVATE KEY-----`,
};

const apple = new Apple(credentials, 'https://intellioptima.com/api/v1/aus/auth/apple/callback');

const appleAuthUrl = async (state: string) => {
    const appleUrl = await apple.createAuthorizationURL(state);

    appleUrl.searchParams.set('response_mode', 'form_post');
    appleUrl.searchParams.set('scope', 'email');

    return appleUrl;
};

const getAppleTokens = async (code: string) => {
    console.log('Authorization code:', code);
    const appleResponse = await apple.validateAuthorizationCode(code);
    console.log('Apple Response:', appleResponse);
    return appleResponse;
};

const getAppleAccount = async (tokens: AppleTokens): Promise<BaseAuthAccountInfo> => {
    const token = generateJWTApple();

    const response = await fetch('https://appleid.apple.com/auth/token', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: new URLSearchParams({
            client_id: credentials.clientId,
            client_secret: token,
            grant_type: 'refresh_token',
            refresh_token: tokens.refreshToken!,
        }).toString(),
    });

    if (!response.ok) {
        throw new Error('Failed to fetch user info');
    }

    const appleResponse = await response.json();
    console.log('APPLE_RESPONSE', appleResponse);

    const decodedUser = decode(appleResponse.id_token) as AppleReponseJWTPayload;
    if (!decodedUser || !decodedUser.email) {
        throw new Error('The user does not have an email address.');
    }

    return {
        id: decodedUser.sub as string,
        username: decodedUser.email.split('@')[0],
        email: decodedUser.email!,
        name: decodedUser.email.split('@')[0],
        emailVerified: decodedUser.email_verified ?? false,
        iconUrl: `https://robohash.org/${decodedUser.email.split('@')[0]}.png`,
    };
};

function generateJWTApple() {
    const MINUTE = 60;
    const HOUR = 60 * MINUTE;
    const DAY = 24 * HOUR;
    const MONTH = 30 * DAY;

    const tokenKey = `-----BEGIN PRIVATE KEY-----\n${APPLE_CLIENT_SECRET_JWT!.replace(/\\n/g, '\n')}\n-----END PRIVATE KEY-----`;

    const privateKey = createPrivateKey(tokenKey);
    const now = Math.ceil(Date.now() / 1000);
    const expires = now + MONTH * 3;

    const claims = {
        iss: APPLE_TEAM_ID,
        iat: now,
        exp: expires,
        aud: 'https://appleid.apple.com',
        sub: 'com.intellioptima.aichat',
    };

    return sign(claims, privateKey, {
        header: {
            kid: APPLE_KEY_ID,
            alg: 'ES256',
        },
    });
}

export { apple, appleAuthUrl, getAppleAccount, getAppleTokens };

I would greatly appreciate any insights or suggestions on what might be going wrong. I'm at a loss, and any help would be invaluable!

Thanks in advance! <3333

Answered by DTS Engineer in 801268022

HI @realkoder,

You wrote:

[...] However, when other users sign in with their Apple IDs, the returned JWT doesn't include their email addresses. I am aware that Apple only provides the email on the first sign-in, but this doesn't seem to be the issue here. [...]

I need more information from you and your client configuration to begin my investigation into your issue.

For Sign in with Apple issues occurring with your native app, perform the following steps:

  1. Install the Accounts/AuthKit profile on your iOS, macOS, tvOS, watchOS, or visionOS device.
  2. Reproduce the issue and make a note of the timestamp when the issue occurred, while optionally capturing screenshots or video.
  3. Gather a sysdiagnose on the same iOS, macOS, tvOS, watchOS, or visionOS device.
  4. Ensure your feedback contains the following information:
    1. the primary App ID or Bundle ID
    2. the user’s Apple ID, email address, and/or identity token
    3. the sysdiagnose gathered after reproducing the issue
    4. the timestamp of when the issue was reproduced
    5. screenshots or videos of errors and unexpected behaviors (optional)

Submitting your feedback

Before you submit to Feedback Assistant, please confirm the requested information above (for your native app or web service) is included in your feedback. Failure to provide the requested information will only delay my investigation into the reported issue within your Sign in with Apple client.

After your submission to Feedback Assistant is complete, please respond here with the Feedback ID. Once received, I can begin my investigation and determine if this issue is caused by an error within your client, a configuration issue within your developer account, or an underlying system bug.

Cheers,

Paris X Pinkney |  WWDR | DTS Engineer

HI @realkoder,

You wrote:

[...] However, when other users sign in with their Apple IDs, the returned JWT doesn't include their email addresses. I am aware that Apple only provides the email on the first sign-in, but this doesn't seem to be the issue here. [...]

I need more information from you and your client configuration to begin my investigation into your issue.

For Sign in with Apple issues occurring with your native app, perform the following steps:

  1. Install the Accounts/AuthKit profile on your iOS, macOS, tvOS, watchOS, or visionOS device.
  2. Reproduce the issue and make a note of the timestamp when the issue occurred, while optionally capturing screenshots or video.
  3. Gather a sysdiagnose on the same iOS, macOS, tvOS, watchOS, or visionOS device.
  4. Ensure your feedback contains the following information:
    1. the primary App ID or Bundle ID
    2. the user’s Apple ID, email address, and/or identity token
    3. the sysdiagnose gathered after reproducing the issue
    4. the timestamp of when the issue was reproduced
    5. screenshots or videos of errors and unexpected behaviors (optional)

Submitting your feedback

Before you submit to Feedback Assistant, please confirm the requested information above (for your native app or web service) is included in your feedback. Failure to provide the requested information will only delay my investigation into the reported issue within your Sign in with Apple client.

After your submission to Feedback Assistant is complete, please respond here with the Feedback ID. Once received, I can begin my investigation and determine if this issue is caused by an error within your client, a configuration issue within your developer account, or an underlying system bug.

Cheers,

Paris X Pinkney |  WWDR | DTS Engineer

Needed: Apple Sign-In JWT Not Returning Email for Users Except Using My AppleID
 
 
Q