Solution:
This explanation is an addition to the tutorial that exists in
https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple
. If you don’t understand something please ask me to clarify and,
if necessary, correct the reply.
First I installed Ruby on the server with the JWT dependency. In it I created the following script:
require 'jwt'
require 'json'
key_file = '../configs/applekey_12345ABCDE.p8'
team_id = '12345ABCDE'
key_id = 'ABCDE12345'
client_id = 'br.com.myapp'
headers = {
'kid' => key_id
}
ecdsa_key = OpenSSL::PKey::EC.new IO.read key_file
claims = {
'iss' => team_id,
'iat' => Time.now.to_i,
'exp' => Time.now.to_i + 15777000,
'aud' => 'https://appleid.apple.com',
'sub' => client_id,
}
token = JWT.encode claims, ecdsa_key, 'ES256', headers
File.write('native_token.txt', token)
client_id = 'br.com.myapp.signin'
claims = {
'iss' => team_id,
'iat' => Time.now.to_i,
'exp' => Time.now.to_i + 12777000,
'aud' => 'https://appleid.apple.com',
'sub' => client_id,
}
token = JWT.encode claims, ecdsa_key, 'ES256', headers
File.write('legacy_token.txt', token)
The above script creates two distinct files: the first is for native login (which is used in iOS 13 and higher) and the other is for legacy (iOS 12 and lower, which occurs via Webview).
For these two login types to occur the app programmer will have to register the two names (the Bundle id and the service id), where the Bundle id is used for the Native and the service id is for the legacy.
It is generating code with 6 months validity, and a CRON on the server renews it monthly, superimposing on the same files.
Once generated these two Txts PHP will consume them to make the request to Apple and thus fetch the user’s email information in this way:
function getUserData($code,$is_legacy){
$key = preg_replace( "/\r|\n/", "", file_get_contents('ruby/'.($is_legacy=='native'?'native':'legacy').'_token.txt'));
$client_id = 'br.com.myapp'.($is_legacy=='native'?'':'.signin');
$data = array(
'client_id' => $client_id,
'client_secret' => $key,
'code' => $code,
'grant_type' => 'authorization_code'
);
$ch = curl_init();
$headers = array
(
'Content-Type: application/x-www-form-urlencoded'
);
curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );
curl_setopt( $ch, CURLOPT_URL, 'https://appleid.apple.com/auth/token');
curl_setopt( $ch, CURLOPT_POST, true);
curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query($data) );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
$serverOutput = json_decode(curl_exec($ch),true);
curl_close ($ch);
$user_email = json_decode(base64_decode(explode('.',$serverOutput['id_token'])[1]),true)['email'];
// FAÇA AQUI ALGO COM O $user_email
}
Explaining in kids: $key receives the contents of the file generated by the Ruby script through a file_get_contents (consider that it should point to where the TXT is). It takes the client_id according to the type of authentication and the $code the app receives when authentication is authorized. So he sends everything to Apple.
The return of this is a JSON which, within the id_token object, nothing else is various data in Base64 separated by points. Here just take the object in the second position, "decrypt" it and thereby get the JSON with the data where the email is perhaps the only one that really matters, since the name and surname are delivered to the app as soon as it gets the authorization (and the app should pass it to the backend along with the code for you to save/update it to your database).