According to apple doc to validate the auth code against Apple we need to POST to http://appleid.apple.com/auth/token with this parameters:
#!java
token = generateJWT(keyId, teamId, clientId, certificatePath);
HttpResponse<String> response = Unirest.post(authUrl)
.header("Content-Type", "application/x-www-form-urlencoded")
.field("client_id", clientId)
.field("client_secret", token)
.field("grant_type", "authorization_code")
.field("code", authorizationCode)
.asString();
where:
authorization_code: Is the auth code provided by app client.
clientId: is provided by Apple
token: is Client Secret. A JWT generate with this code:
#!java
private static String generateJWT(String keyId, String teamId, String clientId, String certificatePath) throws Exception {
if (pKey == null) {
pKey = getPrivateKey(certificatePath);
}
return Jwts.builder()
.setHeaderParam(JwsHeader.KEY_ID, keyId)
.setIssuer(teamId)
.setAudience("https://appleid.apple.com")
.setSubject(clientId)
.setExpiration(new Date(System.currentTimeMillis() + (1000 * 60 * 5)))
.setIssuedAt(new Date(System.currentTimeMillis()))
.signWith(pKey, SignatureAlgorithm.ES256)
.compact();
}
private static PrivateKey getPrivateKey(String certificatePath) throws Exception {
//read your key
try (PEMParser pemParser = new PEMParser(new FileReader(certificatePath))) {
final JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
final PrivateKeyInfo object = (PrivateKeyInfo) pemParser.readObject();
final PrivateKey pKey = converter.getPrivateKey(object);
return pKey;
}
}
We check that, the JWT, contains all the fields needed by apple:
#!json
{
"alg": "ES256",
"typ": "JWT",
"kid": "6876D87D6"
}
{
"iat": 1578654031,
"exp": 1578740431,
"aud": "https://appleid.apple.com",
"iss": "57675576576",
"sub": "com.blahblah.client"
}
But this is the problem. It always return a 400 HTTP Error with this body:
#!json
{"error":"invalid_grant"}
From here we are completely lost. We do not understand why the code is not correct or why it has an invalid_grant error.
In my case, front-end sent identityToken
by mistake, instead of authorizationCode
. That caused b'{"error":"invalid_grant"}'
I was only able to get the invalid_grant
error when sending requests with incorrect authorizationCode
to https://appleid.apple.com/auth/token. Make sure you get the code the same way as in the swift code sample below.
I think this error is not about the client_secret
. When I change the client_secret
from a valid value to an empty string or some incorrect value, I just get the invalid_client
error. And when both the authorizationCode
and the
client_secret
are wrong, I also get the invalid_client
error.
This is what is needed for the request:
- app_id is the bundle identifier for the app
client_secret is the jwt token you create using the information shown in the question and sign with your private key you download from developer.apple.com also see my answer here
grant_type is just the string "authorization_code"
- code is the authorizationCode you get from inside the app on a string format, not data format
data = {
'client_id': app_id,
'client_secret': client_secret,
'grant_type': grant_type,
'code': authorizationCode,
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
}
//python example request
response = requests.request(
method='POST',
url='https://appleid.apple.com/auth/token',
data=data,
headers=headers,
)
if response.status_code == 200:
print("200")
else:
print("error")
print(response.text)
The following swift code can be used to get the authorizationCode
, identityToken
and userIdentifier
on the correct format.
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
let userIdentifier = appleIDCredential.user
print("userIdentifier: \(userIdentifier)")
let authorizationCode = String(data: appleIDCredential.authorizationCode!, encoding: .utf8)!
print("authorizationCode: \(authorizationCode)")
let identityToken = String(data: appleIDCredential.identityToken!, encoding: .utf8)!
print("identityToken: \(identityToken)")
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With