1

I am using Xcode10, Swift 5 and SwiftJWT to generate JSON Web token in order to authenticate Device Check API. Below is the method

let key8 = """
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCq...
-----END PRIVATE KEY-----
"""

let myHeader = Header(kid: m_key)
struct MyClaims: Claims {
  let iat: Date
  let iss: String
}

var jwt = JWT(header: myHeader, claims: MyClaims(iat: Date(timeIntervalSinceNow: 3600), iss: m_iss))
    let privateKey = key8.data(using: .utf8)!
    let rsaJWTEncoder = JWTEncoder(jwtSigner: JWTSigner.es256(privateKey: privateKey))
    do {
        let jwtString = try rsaJWTEncoder.encodeToString(jwt)

        print("endcode header: \(jwtString)")
    } catch {
        print("Failed to encode JWT: \(error)")
    }
}

getting the result something like eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIs...

Using the above header to connect the Apple server. I keep getting this response from Apple’s server: 401 Unable to verify authorization token.

I am also trying to create JSON Web token from jwt

but same error. Any help would be appreciated. Thanks in advance

Ashfaque
  • 1,254
  • 1
  • 22
  • 38

1 Answers1

1

I tried multiple ways to resolve the issue. But what worked for me, describing here step by step how to get device two bits status using DeviceCheck API.

Step 1- Generate Token

let currentDevice = DCDevice.current
if currentDevice.isSupported {
currentDevice.generateToken(completionHandler: { (data, error) in
    if let tokenData = data {
        print("Token: \(tokenData)")
    } else {
        print("Error: \(error?.localizedDescription ?? "")")
    }
})
}

Step 2 - Accessing and Modifying Per-Device Data

Create an APNs authentication token signing key

1- In your developer account, go to Certificates, Identifiers & Profiles.

2 - Under Keys, select All and click the Add button (+) in the upper-right corner.

3- Under Key Description, enter a unique name for the signing key.

4- Under Key Services, select the APNs checkbox, then click Continue.

5- Review the key configuration, then click Confirm.

6- Optionally, click Download to generate and download the key now. If you download the key, it is saved as a text file with a .p8 file extension. Save the file in a secure place because the key is not saved in your developer account and you won’t be able to download it again.

7- Click Done.

Step 3- Create the Payload for a Query Request

func generateJWTToken() -> String{

     let key8 = """
     -----BEGIN PRIVATE KEY-----

    MIGTAgEAMBMGByqGSM49...
    -----END PRIVATE KEY-----
    """

    let myHeader = Header(kid: "2YHFSDF45")

    let timeStamp = Date.currentTimeStamp
    let teamId = "xyz"

    let jwt = JWT(header: myHeader, claims: MyClaims(iat:timeStamp, iss: teamId))

    let privateKey = key8.data(using: .utf8)!
    let rsaJWTEncoder = JWTEncoder(jwtSigner: JWTSigner.es256(privateKey: privateKey))

    do {
        let jwtString = try rsaJWTEncoder.encodeToString(jwt)

        //print(jwtString)

        return jwtString
    } catch {
        print("Failed to encode JWT: \(error)")
    }

    return ""
}

Step 4- Query DeviceCheckApi

To get the two bits state of a device, we will make a HTTP request Using Alamofire to https://api.devicecheck.apple.com/v1/query_two_bits

    //MARK:- method call device check API
func callAppleDeviceCheckApi(_ token: String){

    let mUrl : URL = NSURL(string: "https://api.devicecheck.apple.com/v1/query_two_bits") as! URL

    let mHeaders = generateJWTToken()
    let mDeviceToken = token
    let mTimeStampMili = Date.currentTimeStampMili

    let headers: HTTPHeaders = ["Authorization": "Bearer "+mHeaders,
                                "Content-Type" : "application/json"]

    let params = ["device_token": mDeviceToken, "transaction_id": "dfgsdfgddfc", "timestamp": mTimeStampMili] as [String : Any]

    var request = URLRequest(url: mUrl)
    request.httpMethod = "POST"

    request.headers = headers

    request.httpBody = try! JSONSerialization.data(withJSONObject: params)
    AF.request(request).responseString(){
        response in

        switch response.result {
        case .success(let value):

            let json = JSON(value)

            //print("JSON: \(json)") 

        case .failure(let error):
            print("ERROR: \(error)")

        }
    }
}

Note- Go through this & this for better understanding.

Ashfaque
  • 1,254
  • 1
  • 22
  • 38
  • can you please post the full code ? This will help me in my journey thank you – Iamwhoiam May 04 '22 at 15:42
  • I have received the same error code `401` and it turned out that you need to wait up to 12-24 hours (in my case it was approximately 7 hours) after the creation of the private key until the verification succeeded with `200`. Beyond this, you need to create a key for `DeviceCheck`because the one stated here for `APN` didn't work for me! – Hans Bondoka Jul 28 '22 at 19:02