sbkl
sbkl

Reputation: 2321

oauth2.0 - token access request with password grant type with ios/swift 2 client

I have my own web application using laravel as back-end which works fine.

Now, I'm starting coding the IOS app (IOS 9, Xcode 7, Swift 2) and would like to connect it to my web app database so I can use API for queries.

My first step which I'm stuck is about the login/password for the user to connect to the web app database through the IOS app.

I have installed an oauth 2.0 configuration on my web app and using the password grant type. Tested with Postman and I can get the access token using the following parameter in the body with x-www-form-urlencoded:

Now, I want to access to the database of this web app with these credentials from the IOS app.

I have created a login form in the view controller. When I tap the login button, I launch an IBAction as follow:

    @IBAction func login(sender: UIButton){

    let myURL = NSURL(string: "http://myWebApplication.com/oauth/access_token")!
    let request = NSMutableURLRequest(URL: myURL)
    request.HTTPMethod = "POST"
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.setValue("application/json", forHTTPHeaderField: "Accept")
    let bodyStr:String = "grant_type=password&client_id=f3d259ddd3ed8ff3843839b&client_secret=4c7f6f8fa93d59c45502c0ae8c4a95b&[email protected]&password=123456"
    request.HTTPBody = bodyStr.dataUsingEncoding(NSUTF8StringEncoding)
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in

        // Your completion handler code here
    }
    task.resume()


}

But nothing happened.

Could you please tell me where I'm wrong?

I spent hours searching for solution and the code above is the result of this search. Unfortunately, not sufficient.

On top of that, what is the next step to store the access token that the web app will return and use it so I can send queries related to this particular user?

Thank you in advance for your help

Upvotes: 2

Views: 7077

Answers (2)

sbkl
sbkl

Reputation: 2321

Thank you Frederico for your help.

I finally managed this way using KeychainWrapper (very useful to manage keychain for sensitive information).

Let me know if anything comment:

    @IBAction func loginButtonTapped(sender: UIButton) {
    self.emailTextField.resignFirstResponder()
    self.passwordTextField.resignFirstResponder()

    if (self.emailTextField.text == "" || self.passwordTextField.text == "") {
        let alertView = UIAlertController(title: "Login failed",
        message: "Wrong username or password." as String, preferredStyle:.Alert)
        let okAction = UIAlertAction(title: "Try Again!", style: .Default, handler: nil)
        alertView.addAction(okAction)
        self.presentViewController(alertView, animated: true, completion: nil)
        return
    }

    // Check if the user entered an email
    if let actualUsername = self.emailTextField.text {

        // Check if the user entered a password
        if let actualPassword = self.passwordTextField.text {

            // Build the body message to request the token to the web app
            self.bodyStr = "grant_type=password&client_id=f3d259ddd3ed8ff3843839b&client_secret=4c7f6f8fa93d59c45502c0ae8c4a95b&username=" + actualUsername + "&password=" + actualPassword

            // Setup the request
            let myURL = NSURL(string: "http://test.com/oauth/access_token")!
            let request = NSMutableURLRequest(URL: myURL)
            request.HTTPMethod = "POST"
            request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
            request.setValue("application/json", forHTTPHeaderField: "Accept")
            request.HTTPBody = bodyStr.dataUsingEncoding(NSUTF8StringEncoding)!

            let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
                (data, response, error) -> Void in
                if let unwrappedData = data {

                    do {

                        // Convert the Json object to an array of dictionaries
                        let tokenDictionary:NSDictionary = try NSJSONSerialization.JSONObjectWithData(unwrappedData, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary

                        // Get the token
                        let token:String = tokenDictionary["access_token"] as! String

                        // Keep record of the token
                        let saveToken:Bool = KeychainWrapper.setString(token, forKey: "access_token")

                        // Dismiss login view and go to the home view controller
                        self.dismissViewControllerAnimated(true, completion: nil)

                    }
                    catch {
                        // Wrong credentials
                        // Reset the text fields
                        self.emailTextField.text = ""
                        self.passwordTextField.text = ""

                        // Setup the alert
                        let alertView = UIAlertController(title: "Login failed",
                            message: "Wrong username or password." as String, preferredStyle:.Alert)
                        let okAction = UIAlertAction(title: "Try Again!", style: .Default, handler: nil)
                        alertView.addAction(okAction)
                        self.presentViewController(alertView, animated: true, completion: nil)
                        return
                    }
                }
            }
            task.resume()
        }
    }
}

Upvotes: 1

Frederico
Frederico

Reputation: 203

I was having the same issue.. Mostly from Cristina Moulton's iOS with REST APIs book, hope it helps.

try this: # using Alamofire & SwiftyJSON #

    func loginUser() {

    var code:String?
    var accessToken:String?

    let path:String = EndPoints.kRestEndpoint + EndPoints.kToken

    let parameters:[String:String] = ["grant_type": "password","client_id": "[email protected]", "client_secret": "123456"]
    let headers:[String:String] = ["Content-Type": "application/x-www-form-urlencoded","Accept": "application/json"]

    Alamofire.request(.POST, path, parameters: parameters, encoding: .URL, headers: headers).responseString { response in

      // Handle response to extract the OAuth Token
      if let error = response.result.error {
        print(error)
        return
      }

      // The access token + type
      print(response.result.value)

      if let receivedResults = response.result.value, jsonData = receivedResults.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
        let jsonResults = JSON(data: jsonData)

        for (key, value) in jsonResults {
          switch key {
          case "access_token":
            if let token = value.string {
              code = token
            }
          case "token_type":
            if let type = value.string {
              accessToken = "\(type) \(code!)"
            }
          case "expires_in":
            // Handle expiration
            print("It has expiration")
          default:
            print("got more than I expected from the OAuth token exchange")
            print(key)
          }
        }
        print("AccessToken: \(accessToken!)")
      } //End of receivedResults

      let defaults = NSUserDefaults.standardUserDefaults()
      defaults.setBool(true, forKey: "loadingOAuthToken")
    }
  }

Upvotes: 1

Related Questions