Sign In With Apple on IPhone

Hello there, I have been facing an issue with apple sign in on react native app. I have been able to get the authorization and all codes in frontend part.

The issue is on backend that is in php. We are firstly validating our identity token phone generated, and then we are creating a client secret and then trying to fetch the user info the issue relies in the api call of getAppleUser($authorizationCode, $clientId, $clientSecret);: function below where we are recieving error like: {"error":"invalid_grant","error_description":"client_id mismatch. The code was not issued to com.marchup.prod.AppSSO."}

public function appleAuth($identityToken,$authorizationCode)
{

    if (!$identityToken || !$authorizationCode) {
        return $this->returnError(400,'Missing identity token or authorization code');
    }

    try {
        // Validate identity token
        $decodedToken = $this->validateAppleToken($identityToken);

        // Generate client secret
        $teamId = isset(Yii::$app->params['apple-auth']['teamId'])?Yii::$app->params['apple-auth']['teamId']:'';
        $clientId = isset(Yii::$app->params['apple-auth']['clientId'])?Yii::$app->params['apple-auth']['clientId']:'';
        $keyId = isset(Yii::$app->params['apple-auth']['keyId'])?Yii::$app->params['apple-auth']['keyId']:'';
        $privateKey = isset(Yii::$app->params['apple-auth']['privateKey'])?Yii::$app->params['apple-auth']['privateKey']:'';

        $clientSecret = $this->generateClientSecret($teamId, $clientId, $keyId, $privateKey);

        // Get user info from Apple
         $appleUser = $this->getAppleUser($authorizationCode, $clientId, $clientSecret);

        // Verify the authorization code is valid
        if (!isset($appleUser['id_token'])) {
            throw new \Exception('Invalid authorization code');
        }

        // Extract user info from the identity token
        $userId = $decodedToken->sub;
        $email = $decodedToken->email ?? '';

        // login or signup code need to know about object definition to add login and signup logic
        return $this->returnSuccess('Request successful',200,[
            'userId' => $userId, 'email' => $email
        ]);
    } catch (\Exception $e) {
        // Handle errors
        Yii::error('Error on apple login '.$e->getMessage());

        return $this->returnError(500,'Server Error');
    }
}

**This function is where i am creating a clientSecret as per apples guidelines: **

function createClientSecret($teamId, $clientId, $keyId, $privateKey) {
    // $key = file_get_contents($privateKeyPath);

    $key=$privateKey;
    $headers = [
        'kid' => $keyId,
        'alg' => 'ES256'
    ];
    $claims = [
        'iss' => $teamId,
        'iat' => time(),
        'exp' => time() + 86400 * 180,
        'aud' => 'https://appleid.apple.com',
        'sub' => $clientId
    ];
    return JWT::encode($claims, $key, 'ES256', $headers['kid']);
}

**This is the validate Apple Token that is not giving me error: **

function validateAppleToken($identityToken) {
    $client = new Client();
    $response = $client->get('https://appleid.apple.com/auth/keys');
    $keys = json_decode($response->getBody(), true)['keys'];

    $header = JWT::urlsafeB64Decode(explode('.', $identityToken)[0]);
    $headerData = json_decode($header, true);
    $kid = $headerData['kid'];

    $publicKey = null;
    foreach ($keys as $key) {
        if ($key['kid'] === $kid) {

            $publicKey = JWK::parseKey($key);
            break;
        }
    }

    if (!$publicKey) {
        throw new \Exception('Public key not found');
    }

    try {
        $decoded = JWT::decode($identityToken, $publicKey, ['RS256']);
        return $decoded;
    } catch (\Exception $e) {
        throw new \Exception('Token validation failed: ' . $e->getMessage());
    }
}

The response i got was :

{

aud: "com.abc"

auth_time: 1718017883

c_hash: "HSNFJSBdut5vk84QyK0xHA"

exp: 1718104283

iat: 1718017883

iss: "https://appleid.apple.com"

nonce:"2878cd1ac1fa121f75250f453edaac47365f5144f2e605e8b526a29cb62c83da"

nonce_supported: true

sub: "001703.2a52ec72cb874a93986522fa35742bd4.1219"

}

After that we are mainly getting error as

{"error":"invalid_grant","error_description":"client_id mismatch. The code was not issued to com.marchup.prod.AppSSO."} in this function:

function getAppleUser($authorizationCode, $clientId, $clientSecret) { try { $client = new Client();

        $response = $client->post('https://appleid.apple.com/auth/token', [
            'form_params' => [
                'client_id' => $clientId,
                'client_secret' => $clientSecret,
                'code' => $authorizationCode,
                'grant_type' => 'authorization_code'
            ]
        ]);

        if ($response->getStatusCode() !== 200) {
            throw new \Exception('Failed to get user information from Apple. Status code: ' . $response->getStatusCode());
        }

        $data = json_decode($response->getBody(), true);

        // Check if the response contains the expected data
        if (!isset($data['access_token']) || !isset($data['id_token'])) {
            throw new \Exception('Invalid response from Apple. Missing access token or ID token.');
        }

        // Return the decoded data
        return $data;
    } catch (\Exception $e) {
        // Log any other unexpected errors
        Yii::error('Unexpected error: ' . $e->getMessage());

        // Re-throw the exception to propagate it further
        throw $e;
    }
}

Assumptions: bundleId = com.marchup serviceId i created as client_id= com.marchup.prod.AppSSO team ID= as usual keyId= is the id i created in apple developer consonsole. And the private key is the key inside the private key file.

Can anyone please answer. What is mismatched here

Answered by DTS Engineer in 806632022

Hi @kundanray1,

When validating tokens, the client ID provided to the token validation server must match the client ID where the initial authorization request was performed.

For instance, if the native app performed the authorization via the Authentication Services framework, you must use the bundle ID as the client ID for all subsequent token validation requests. Otherwise, if the REST API performed the authorization request, the client ID should match your Services ID associated with the primary native app.

For more information about these errors, please see the following technote:

TN3107: Resolving Sign in with Apple response errors https://developer.apple.com/documentation/technotes/tn3107-resolving-sign-in-with-apple-response-errors

Cheers,

Paris X Pinkney |  WWDR | DTS Engineer

Hi @kundanray1,

When validating tokens, the client ID provided to the token validation server must match the client ID where the initial authorization request was performed.

For instance, if the native app performed the authorization via the Authentication Services framework, you must use the bundle ID as the client ID for all subsequent token validation requests. Otherwise, if the REST API performed the authorization request, the client ID should match your Services ID associated with the primary native app.

For more information about these errors, please see the following technote:

TN3107: Resolving Sign in with Apple response errors https://developer.apple.com/documentation/technotes/tn3107-resolving-sign-in-with-apple-response-errors

Cheers,

Paris X Pinkney |  WWDR | DTS Engineer

Sign In With Apple on IPhone
 
 
Q