ios – Auth0’s JWT not working with Apple’s REST API

[ad_1]

I’m trying to get an access code via Apple’s REST API.

To do so, I’m following the instructions at https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens entitled “Generate and validate tokens.”

Creating a JWT is a requirement. Based on the instructions, I create the following JWT header:

 {
     "alg": "ES256",
     "kid": "<kid>"
 }
 

Above, “kid” is my private 10-character key identifier I get from App Store Connect following Apple’s instructions. Some people have mentioned that the JWT header must also include “typ”: “JWT”. So, I’ve also used a version of the header that does.

Next, I create the following JWT payload:

 {
     "iss": "<iss>",
     "iat": <UNIX epoch time>,
     "exp": <UNIX epoch time>,
     "aud": "https://appleid.apple.com",
     "sub": "<client_id>"
 }
 

Above, “iss” is my 10-character Team ID associated with my developer account as instructed by Apple. In a different set of instructions, Apple mentions that “iss” should be my issuer ID from the API Keys page in App Store Connect. So, I’ve also used a version of the payload that uses this other version of “iss.”

“client_id” is my App ID. According to some people, my App ID is my app’s Bundle Identifier. According to others, it’s the number that appears at the very end of the url that links to my app in the App Store. So, I’ve used a version of the payload that uses this number and also one that uses the Bundle Identifier. I’ve also used a version of the payload that doesn’t include the “sub” parameter because in a different set of instructions by Apple, it’s not included.

I’ve used an “exp” that expires 10min in the future. According to some people, “iat” should be set to a few seconds or minutes ago. I’ve taken this into consideration.

Based on all the above info, I’ve tried using 2 different JWT headers and 8 different JWT payloads. Subsequently, I’ve used 16 different JWT tokens.

To creat and sign my JWT token, Apple links to Auth0’s website JWT.io. There, I start by selecting the ES256 algorithm in the debugger because according to the JWT header, “alg” is “ES256”.

I then paste my JWT header into the HEADER section of the debugger and my payload into the PAYLOAD section.

The private key I downloaded from App Store Connect is in .p8 format. In order for it to work with Auth0’s debugger, I convert it to PKCS #8 format as follows:

First, I convert it to .pem format:

 openssl pkcs8 -in AuthKey_<kid>.p8 -nocrypt -out Auth0_<kid>.pem
 

I then convert the .pem to PKCS #8 format:

 openssl pkcs8 -topk8 -inform PEM -in Auth0_<kid>.pem \
     -nocrypt > Auth0_priv_pkcs8
 

Finally, I generate a public key that corresponds with Auth0_priv_pkcs8:

 openssl ec -in Auth0_priv_pkcs8 -pubout > Auth0_pub_pkcs8
 

In Auth0’s debugger, I paste Auth0_pub_pkcs8 in the public key section and Auth0_priv_pkcs8 in the private key section.

Auth0 states, “Signature Verified.” So, I immediately copy my signed JWT and paste it in the following iOS func, assigning it to client_secret:

 func get_accessToken(code: String) {
     
     let client_id = "<JWT payload's sub value>",
         client_secret = "<JWT signed using Auth0's website>",
         url = URL(string: "https://appleid.apple.com/auth/token")!
    
     var urlRequest = URLRequest(url: url, cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalCacheData, timeoutInterval: 60.0)
     
     urlRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
     urlRequest.httpMethod = "POST"
     
     let parameters: [String: Any] = [
         "client_id": client_id,
         "client_secret": client_secret,
         "code": code,//An authorization_code that has just been received. Example: cb45463c23057491faf97ac07f111a143.0.rryus.CX5XwXNQ04461uwcZhQStg
         "grant_type": "authorization_code"
     ]
     
     urlRequest.httpBody = parameters.percentEncoded()
   
     let session = URLSession.shared,
         task = session.dataTask(with: urlRequest) { data, response, error in
             
         guard let data = data,
               let response = response as? HTTPURLResponse,
                   error == nil else {
             
             // check for fundamental networking error
             print(error!)
             return
                 
         }
             
         do {
             
             let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
             print(json)
             
         } catch {
             
             print(error)//error = "invalid_client"; all the time
             
         }
          
         guard (200 ... 299) ~= response.statusCode else {
             
             // check for http errors
             return
             
         }
        
     }
     
     task.resume()
     
 }
 

The above func executes as soon as I get an authorization code from Apple’s API. After it executes, I always get error = “invalid_client”;

As mentioned earlier, I have changed the JWT header and payload parameters multiple times based on various guidelines and opinions. This has resulted into me having 16 different signed JWTs from Auth0’s website and they’ve all yielded error = “invalid_client”.

My team has multiple apps on the App Store. My understanding is that the private key I downloaded from App Store Connect should work for all apps. But I’m also wondering if perhaps Apple’s API expects an App ID that belongs to one of my other apps and not the one I’m currently working on. If that’s the case, then could this be an Apple API bug? If not, then have I made an error anywhere or is there an issue with Auth0’s debugger?

[ad_2]

Source link

Leave a Reply

Your email address will not be published.