I am receiving an 400: [{"error":"invalid_client"}]
error when trying to exchange my authorization code for a refresh token. I tried everything and double-checked many times. I am using this libary for generating the client secret. Below I used a sample key for demonstrating the issue. What could be wrong?
Apple Client Secret Generator
public class AppleClientSecretGenerator {
private String team_id;
private String sub;
private String key_id;
private long expiration_time;
private String secret_key;
private String aud;
public AppleClientSecretGenerator() {
super();
this.team_id = "***********";
this.sub = "com.example.app";
this.key_id = "**********";
this.expiration_time = 200000;
this.secret_key = "MIGTAFKMN23SFF2SFGSM49AgEGCCqGSM49AwEHBHdfDSFFDe09hGVEu5sesMNNF" +
"pet8GJDZIL0inL4oxgIJNF0i3Q8MYKOgsdCgYIKoZIzj0DAQehRANCAAQhAVyKVrFGWEw+" +
"gkWyeQNxopjG30iF56DXM0QfqwbffKmsdPkjfe3FKDDFyDYmk+XZM4qj6aIZKLy" +
"KLM4Nd23";
this.aud = "https://appleid.apple.com";
}
public String generate() {
String jws = "";
try {
byte[] keyBytes = Base64.getDecoder().decode(secret_key);
//byte[] keyBytes = Files.readAllBytes(Paths.get(filename));
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.ES256;
long nowSeconds = System.currentTimeMillis();
Date now = new Date(nowSeconds);
long expMillis = nowSeconds + expiration_time;
Date exp = new Date(expMillis);
jws = Jwts.builder()
.setHeaderParam("kid", key_id)
.setIssuedAt(now)
.setSubject(sub)
.setIssuer(team_id)
.setAudience(aud)
.setExpiration(exp)
.signWith(key, signatureAlgorithm)
.compact();
} catch (JwtException e) {
//don't trust the JWT!
System.out.println("Error: " + e.getMessage());
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
System.out.println("Error: " + e.getMessage());
e.printStackTrace();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
System.out.println("Error: " + e.getMessage());
e.printStackTrace();
}
System.out.println("Client Secret: " + jws);
return jws;
}
}
Authorization Request
public class AuthorizationRequest {
private String client_id;
private String client_secret;
private String code;
private String grant_type;
private String redirect_uri;
public AuthorizationRequest(String client_secret, String code) {
super();
this.client_id = "com.maxtrauboth.BopdropSwiftUI";
this.client_secret = client_secret;
this.code = code;
this.grant_type = "authorization_code";
this.redirect_uri = "http://mylocaladdr.test/";
}
// Getters and Setters here
Verify User
@PostMapping("verify")
public UserCredentials verify(@RequestBody UserCredentials credentials) {
Jwk jwk;
Algorithm algorithm;
// Validate identity token
DecodedJWT jwt = JWT.decode(credentials.getToken());
JwkProvider provider = new UrlJwkProvider("https://appleid.apple.com/auth/keys");
try {
jwk = provider.get(jwt.getKeyId());
algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);
algorithm.verify(jwt);
// Check expiration
if (jwt.getExpiresAt().before(Calendar.getInstance().getTime())) {
throw new RuntimeException("Expired token!");
}
// Create client_secret
AppleClientSecretGenerator generator = new AppleClientSecretGenerator();
String client_secret = generator.generate();
// Refreshing the token by sending the authorization code
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_FORM_URLENCODED));
headers.set("User-Agent", "Mozilla/5.0 Firefox/26.0");
System.out.println("Authorization Code: " + credentials.getAuthorization_code());
AuthorizationRequest request = new AuthorizationRequest(client_secret, credentials.getAuthorization_code());
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);
RestTemplate restTemplate = new RestTemplate();
// send POST request
TokenResponse response = restTemplate.postForObject("https://appleid.apple.com/auth/token", entity, TokenResponse.class);
// do some database work here
} catch (JwkException e) {
// error
} catch (IllegalArgumentException e) {
// error
}
// sending the token back to the user
return credentials;
}
Generated Client Secret
{
"kid": "*********",
"alg": "ES256"
}
{
"iss": "*********",
"iat": 1587930164,
"exp": 1587930364,
"aud": "https://appleid.apple.com",
"sub": "com.example.app"
}
The Issued at and Expiry time should be in seconds, not milliseconds.
I did not find the cause for the issue. However, I solved the problem by following the exact steps mentioned here .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.