-
-
Save ameen-sarsour/e14a1d5bae5b61080dfdd5b1430c3e10 to your computer and use it in GitHub Desktop.
| <?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); | |
| } |
it's working for me, I used it in real application.
@ihemantkumar, do you faced any issue?
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.
I think on line 52 $key should be $ecdsa_key because its not used anywhere, right?
Yes, that's right.
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.
Hi @ameen-sarsour
I am getting error {"error":"invalid_client"}
- and from App need to use code
Is this code generated from flutter appappleCredential.identityToken
I am getting error {"error":"invalid_client"}
me too invalid_client
if o create the client_id on ruby it works but client_id created on php doesnt works!
me too invalid_client . I am using this code and create client_secret but show this error
Client error:
POST https://appleid.apple.com/auth/tokenresulted in a400 Bad Requestresponse: {"error":"invalid_client","email_verified":false}
Is this code working for anyone?