Skip to content

Instantly share code, notes, and snippets.

@ameen-sarsour
Last active November 20, 2023 13:37
Show Gist options
  • Save ameen-sarsour/e14a1d5bae5b61080dfdd5b1430c3e10 to your computer and use it in GitHub Desktop.
Save ameen-sarsour/e14a1d5bae5b61080dfdd5b1430c3e10 to your computer and use it in GitHub Desktop.
this code to try php sign in,
<?php
/**
* This file to test apple sign in,
* Need to app information from Apple
*
* Team Id
* Client Id
* Key Id
* and Private key
*
* and from App need to use code
*
* Note: Some of this codde is taken from firebase JWT library, I just copy&paste to make
* this code runnable withouy any dependency
*
*/
const TEAM_ID = 'XXXXXXXXXX';
const CLIENT_ID = 'com.XXXXXXXX.App';
const KEY_ID = 'XXXXXXXXXX';
$key = <<<KEY
-----BEGIN PRIVATE KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXX
-----END PRIVATE KEY-----
KEY;
$ecdsa_key = openssl_pkey_get_private($key);
$header = array('typ' => 'JWT', 'alg' => 'ES256');
$header['kid'] = KEY_ID;
$payload = [
'iss' => TEAM_ID,
'iat' => time(),
'exp' => time() + 86400*180,
'aud' => 'https://appleid.apple.com',
'sub' => CLIENT_ID,
];
$segments = array();
$segments[] = urlsafeB64Encode(json_encode($header));
$segments[] = urlsafeB64Encode(json_encode($payload));
$signing_input = \implode('.', $segments);
$signature = '';
$success = \openssl_sign($signing_input, $signature, $key, 'SHA256');
if (!$success) {
throw new DomainException("OpenSSL unable to sign data");
} else {
if ($header['alg'] === 'ES256') {
$signature = signatureFromDER($signature, 256);
}
}
$segments[] = urlsafeB64Encode($signature);
$clientSecret = \implode('.', $segments);
$code = 'CODE GENERATED FROM APP';
$curl = curl_init();
$postData = [
"client_id=CLIENT_ID",
"client_secret=$clientSecret",
"code=$code",
"grant_type=authorization_code"
];
curl_setopt_array($curl, array(
CURLOPT_URL => "https://appleid.apple.com/auth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => implode('&', $postData),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
function urlsafeB64Encode($input)
{
return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_'));
}
function signatureFromDER($der, $keySize)
{
// OpenSSL returns the ECDSA signatures as a binary ASN.1 DER SEQUENCE
list($offset, $_) = readDER($der);
list($offset, $r) = readDER($der, $offset);
list($offset, $s) = readDER($der, $offset);
// Convert r-value and s-value from signed two's compliment to unsigned
// big-endian integers
$r = \ltrim($r, "\x00");
$s = \ltrim($s, "\x00");
// Pad out r and s so that they are $keySize bits long
$r = \str_pad($r, $keySize / 8, "\x00", STR_PAD_LEFT);
$s = \str_pad($s, $keySize / 8, "\x00", STR_PAD_LEFT);
return $r . $s;
}
function readDER($der, $offset = 0)
{
$ASN1_BIT_STRING = 0x03;
$pos = $offset;
$size = \strlen($der);
$constructed = (\ord($der[$pos]) >> 5) & 0x01;
$type = \ord($der[$pos++]) & 0x1f;
// Length
$len = \ord($der[$pos++]);
if ($len & 0x80) {
$n = $len & 0x1f;
$len = 0;
while ($n-- && $pos < $size) {
$len = ($len << 8) | \ord($der[$pos++]);
}
}
// Value
if ($type == $ASN1_BIT_STRING) {
$pos++; // Skip the first contents octet (padding indicator)
$data = \substr($der, $pos, $len - 1);
$pos += $len - 1;
} elseif (!$constructed) {
$data = \substr($der, $pos, $len);
$pos += $len;
} else {
$data = null;
}
return array($pos, $data);
}
@ihemantkumar
Copy link

Is this code working for anyone?

@ameen-sarsour
Copy link
Author

it's working for me, I used it in real application.

@ameen-sarsour
Copy link
Author

@ihemantkumar, do you faced any issue?

@ihemantkumar
Copy link

It only worked to me once, and I created my application on the base of that and later Apple started throwing me an error, invalid_grant. I was positive that the error wasn't at my end but it has to be the issue on the auth_token from the App. But I am not the App developer. App developer was only saying 1 thing, they have to send the auth_token only, nothing else is to be at their end. We abandon this feature now. Added this feature from the App instead of the Server end.

@teoalexopoulos
Copy link

I think on line 52 $key should be $ecdsa_key because its not used anywhere, right?

@ihemantkumar
Copy link

Yes, that's right.

@yurik94
Copy link

yurik94 commented Dec 18, 2020

https://sarunw.com/posts/sign-in-with-apple-3/

$key is constantly changing, you can't hardcode it, that's why this doesn't work.

@VaseemDeveloper
Copy link

Hi @ameen-sarsour
I am getting error {"error":"invalid_client"}

@yogeshtandel
Copy link

Hi @ameen-sarsour

  • and from App need to use code
    Is this code generated from flutter app appleCredential.identityToken

I am getting error {"error":"invalid_client"}

@ramaces
Copy link

ramaces commented Nov 20, 2023

me too invalid_client
if o create the client_id on ruby it works but client_id created on php doesnt works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment