简体   繁体   中英

Error: Invalid Client - Sign In With Apple with Spring Boot

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM