We have begun implementing Sign in with Apple in our mobile app but cannot seem to call the token endpoint successfully (https://appleid.apple.com/auth/token). The response we get is 400 with the body [{"error":"invalid_client"}]. I have read and re-read the details on how to generate the client-secret. We are using a java backend and specifically the nimbus library to create the signed JWT.
final JWSHeader clientSecretHeader =
new JWSHeader.Builder(JWSAlgorithm.ES256)
.keyID("7N5XJ*****")
.build();
final Date issuedAtTime = Date.from(Instant.now());
final Date expirationTime = Date.from(Instant.now().plusSeconds(3600));
final JWTClaimsSet clientSecretClaims =
new JWTClaimsSet.Builder()
.issuer("HL46P*****")
.issueTime(issuedAtTime)
.expirationTime(expirationTime)
.audience("https://appleid.apple.com")
.subject("com.company.app")
.build();
final ECPrivateKey signingKey = ...private key loaded from p8 file...;
final JWSSigner jwtSigner = new ECDSASigner(signingKey);
final SignedJWT clientSecretJwt = new SignedJWT(clientSecretHeader, clientSecretClaims);
clientSecretJwt.sign(jwtSigner);
MultiValueMap<string, string=""> map= new LinkedMultiValueMap<>();
map.add("grant_type", "authorization_code");
map.add("client_id", "HL46P*****");
map.add("client_secret", clientSecretJwt.serialize());
map.add("code", "code receiged from app...");
final HttpEntity<multivaluemap<string, string="">> request = new HttpEntity<>(map);
final RestTemplate restTemplate = new RestTemplateBuilder().build();
final ResponseEntity response = response = restTemplate.postForEntity(
"https://appleid.apple.com/auth/token",
request,
GetTokenResponse.class
);
The resulting JWT looks like the following:
Header
{
"kid": "7N5XJ*****",
"alg": "ES256"
}
Claims
{
"aud": "https://appleid.apple.com",
"sub": "com.company.app",
"iss": "HL46P.....",
"exp": 1585583898,
"iat": 1585580298
}
I am out of ideas on what we are doing wrong.