Welcome to the new Box Support website. Check out all the details here on what’s changed.

iOS SDK - Authentication With JWT

New post

Comments

4 comments

  • johnmartino

    Just elaborating on the initial question:

     

    The BOXAPIAccessTokenDelegate method is being defined.  When we try to authenticate with 

    autheticateAppUser() the delegate method gets called, which provides a callback where we set the accessToken.  What we're missing is getting this token.

     

    func fetchAccessToken(completion: ((String?, Date?, Error?) -> Void)!) {

            let accessToken = getAccessToken() // This is what's missing

            completion(accessToken, Date(timeInterval: 1000, since: Date()), nil)

    }

     

    What we have is:

    - clientID

    - clientSecret

    - publicKeyID

    - privateKey

    - passphrase

    - enterpriseID

     

    The clientID and clientSecret are set in the setClientID(clientSecret:) static method on BOXContentClient.

     

    There is a class in the Java API called BOXConfig, which takes the remaining values but I don't see one for iOS.  Any help would be greatly appreciated.

    0
    Comment actions Permalink
  • apongos

    After about a week of scouring the internet this is what I did to get it to work on swift3:

     

    1. Based off of several blogs, Apple decprecated openssl; so, it might be easier to first decrypt your private key through your terminal like here https://stackoverflow.com/questions/13732826/convert-pem-to-crt-and-key
      1. I ran >> openssl pkcs8 -outform pem -in ecrypted.pem -out decrypted.pem to get a decrypted key.
    2. I then pasted the decrypted pem string into a struct so I could easily import it later (don't recommend doing this with data sensitive app).

      struct dKey {

         static let pKey =

      "-----BEGIN PRIVATE KEY-----\n"

      + "-----END PRIVATE KEY-----\n" }

    3. Using SwiftyCrypto I imported the key and created a JWT assertion https://github.com/Wstunes/SwiftyJWT:
      1. let privateKeyD = try! RSAKey.init(base64String: dKey.pKey, keyType: .PRIVATE)

                let headerWithKeyId = JWTHeader.init(keyId: appAuthJson["publicKeyID"] as? String)

                let alg = JWTAlgorithm.rs256(privateKeyD)

                var payload = JWTPayload()

                payload.issuer = configJson["clientID"] as? String

                payload.subject = configJ["enterpriseID"] as? String

                payload.jwtId = generateRandomBytes()!.hexEncodedString()

                payload.audience = "https://api.box.com/oauth2/token"

                payload.expiration = Int(Date().addingTimeInterval(1.0 * 60.0).timeIntervalSince1970)

                payload.customFields = ["box_sub_type": EncodableValue(value: "enterprise")]

                

                let jwtWithKeyId = try? JWT.init(payload: payload, algorithm: alg, header: headerWithKeyId)

    4. I then created params to pass into a Request:

      let params = ["grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",

                            "assertion" : jwtWithKeyId!!.rawString!,

                            "client_id" : tmpClientID,

                            "client_secret": tmpClientSecret,

                              ]

    5. I then submitted a request through the http body, NOT url query
      1.  let urlParams = params.flatMap({ (key, value) -> String in

                    return "\(key)=\(value)"

                }).joined(separator: "&")

                

                let bodyString = urlParams

                print("bodyString \(bodyString)")

                // create post request

                let url = URL(string: "https://api.box.com/oauth2/token")!

                var request = URLRequest(url: url)

                request.httpMethod = "POST"

                

                // insert json data to the request

                request.httpBody = bodyString.data(using: .utf8)

                

                let task = URLSession.shared.dataTask(with: request) { data, response, error in

                    guard let data = data, error == nil else {

                        print(error?.localizedDescription ?? "No data")

                        return

                    }

                    let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])

                    if let responseJSON = responseJSON as? [String: Any] {

                        print(responseJSON)

                    }

                }

                

                task.resume()

    You should have your access token now in responseJSON.

    This was using a play app, and I don't recommend pasting decrypted key into a struct for apps dealing with sensitive data. 

    1
    Comment actions Permalink
  • Ghaith

    Hello,

     

    Thank you for sharing that info. I am facing the same problem and I hope if you can give the source file on Github or share it with me on Drive, here is my email:

     

    ***email address removed for privacy***

    0
    Comment actions Permalink
  • Bryan Allebone

    Did anyone resolve this to completion? I've been stuck on the same problem for quite a while, but no good examples seem to show a complete solution.

     

    ~Bryan

    0
    Comment actions Permalink

Please sign in to leave a comment.