OAuth 2.0 with Swift Tutorial

Corinne Krych
Take a look at a few OAuth2 libraries, and find out how to integrate them into an app.

Take a look at a few different OAuth2 libraries, and find out how to integrate them into an app.

It’s likely that you’ve bumped into OAuth2 and the different families of flows while building apps to share content with your favorite social network (Facebook, Twitter, etc) or with your enterprise OAuth2 server — even if you weren’t aware of what was going on under the hood. But do you know how to hook up to your service using OAuth2 in an iOS app?

In this tutorial, you’ll work on a selfie-sharing app named Incognito as you learn how to use the AeroGear OAuth2, AFOAuth2Manager and OAuthSwift open source OAuth2 libraries to share your selfies to Google Drive.

Getting Started

Download the Incognito starter project. The starter project uses CocoaPods to fetch AeroGear dependencies and contains everything you need, including generated pods and xcworkspace directories.

Open Incognito.xcworkspace in Xcode. The project is based on a standard Xcode Single View Application template, with a single storyboard that contains a single view controller ViewController.swift. All UI actions are already handled in ViewController.swift.

Build and run your project to see what the app looks like:


The app lets you pick your best selfie and add some accessories to the image. Did you recognize me behind my disguise? :]

Note: To add photos in the simulator, simply go to the home screen using Cmd + Shift + H and drag and drop your images onto the simulator.

All that’s left to add to the app is the share to Google Drive feature using three different OAuth2 libraries.

Mission impossible? Nope, it’s nothing you can’t handle! :]

Instead of boring you with an introduction to the RFC6749 OAuth2 specification, let me tell you a story…

Explaining the Need for OAuth2

On Monday morning, Bob, our mobile nerd bumps into Alice, another friendly geek, in front of the coffee machine. Bob seems busy, carrying a heavy bunch of documents: his boss wants him to delve into the OAuth2 specification for the Incognito app.

Put any two developers in a coffee room and soon they’ll chat about geeky things, of course. Bob asks Alice:

“…what problem are we trying to solve with OAuth2?”


On one side, you have services in the form of APIs, such as the Twitter API, which you can use to get a list of followers or Tweets. Those APIs handle your confidential data, which is protected by a login and password.

On the other side, you have apps that consume those services. Those apps need to access your data, but do you want to trust all of them with your credentials? Maybe — but maybe not.

This brings up the concept of delegated access. OAuth2 lets users grant third-party apps access to their web resources, without sharing their passwords, through a security object known as an access token. It’s impossible to obtain the password from the access token, meaning your password is safe inside the main service, and each app that wants to connect to the service just gets their own access token. Access tokens can then be revoked if you ever want to revoke access to just that app.

OAuth2 works with the following four actors:

  • authorization server: responsible for authentication and authorization; provides the access token.
  • resource server: in charge of serving up resources if a valid token is provided.
  • resource owner: the owner of the data — that is, the end user of Incognito.
  • client: the Incognito mobile app.

The OAuth2 specification describes the interactions between these actors as grant flows.

The specification details four different grant flows that can be grouped into two different families:

  • 3-legged flows: the end user needs to grant permission in these cases. The implicit grant is for browser-based apps that aren’t capable of keeping tokens secure. The authorization code grant, which generates an access token and optionally a refresh token, is for clients capable of keeping tokens secure. Such clients include mobile apps which have somewhere secure they can store the token, such as in the keychain on iOS.
  • 2-legged flows: the credentials are given to the app. The key difference here is that the resource owner has inputs the credentials directly into the client. An example of where you see this in practice is when accessing many APIs, e.g. Parse, as a developer and put your key and secret in your app.

You’ll use your existing Google Drive account and upload your Incognito selfies there. This is a good case for implementation of the 3-legged authorization code grant.

The Authorization Dance

Although using open source libraries hides most of the sticky details of the OAuth2 protocol from you, knowing its basic inner workings will help you get the configuration right.

Here are the steps involved in the authorization code grant dance:

Step 0: Registration

Your application needs to be registered with the service you want to access. In your case, for Incognito, that’s Google Drive. Don’t worry, the following section will explain how to do that.

Step 1: Authorization Code

The dance begins when Incognito sends a request for an authorization code to the third-party service that includes:

  • client ID: Provided during service registration. Defines which app is talking to the service.
  • client secret: Provided during service registration. A secret between the service and the app, bundles into the app’s binary.
  • redirect URI: Where the user should be redirected after entering their credentials into the service, and granting permission.
  • scope: Used to tell the service what level of permission the app should have.

The app then switches to the web browser. Once the user logs in, the Google authorization server displays a grant page: “Incognito would like to access your photos: Allow/Deny”. When the end user clicks “Allow”, the server redirects to the Incognito app using the redirect URI and sends an authorization code to the app.


Step 2: Exchange Code for Token

The authorization code is only temporary; therefore the OAuth2 library has to exchange this temporary code for a proper access token, and optionally, a refresh token.

Step 3: Get Resources

Using the access token, Incognito can access protected resources on the server — that is, the resources the end-user granted access to. Your upload is free to proceed.

Ready to see this in action? First, you need to register with the OAuth2 provider: Google.

Registering With your OAuth2 Provider

If you don’t have a Google account, go create one now. It’s OK; I’ll wait for you. :]

Open http://console.developer.google.com in your browser; you’ll be prompted to authenticate with Google.

Click Create Project and name your new project Incognito:


Next, you need to enable the Drive API.

Navigate to APIs & auth\APIs, then click Google Apps APIs\Drive API. On the next screen, click Enable API:


Now you need to create new credentials to access your Drive accounts from the app.

Go to APIs & auth\Credentials and click the blue Create new Client ID button inside the OAuth area.

Then click Configure consent screen and in the screen that appears, fill out the following information:

  • Email address: Select your email address
  • Product name: Incognito
  • Homepage URL: http://www.raywenderlich.com

Click Save and you’ll return to the Client ID screen.

Select Installed application, then select iOS and enter com.raywenderlich.Incognito as your Bundle ID.

The authorization server will use the bundle id entered above as the redirect URI.

Finally, click Create Client ID. The final screen will show you value of the generated Client ID, Client secret, and redirect URIs, which you’ll make use of later on:


Now that you’ve registered with Google, you’re ready to start your OAuth2 implementation using the first OAuth2 library: AeroGear with an external browser.

Authenticating with AeroGear and External Browsers

Open ViewController.swift and add the following imports to the top of the file:

import AeroGearHttp
import AeroGearOAuth2

Now, add the following instance variable inside the ViewController class:

var http: Http!

Now instantiate it by adding the following at the end of viewDidLoad():

self.http = Http()

You’ll use this instance of Http, which comes from the AeroGearHttp library, to perform HTTP requests.

Still in ViewController.swift, find the empty share(:) method and add the following code to it:

let googleConfig = GoogleConfig(
clientId: "YOUR_GOOGLE_CLIENT_ID",                               // [1] Define a Google configuration
scopes:["https://www.googleapis.com/auth/drive"])                // [2] Specify scope
let gdModule = AccountManager.addGoogleAccount(googleConfig)     // [3] Add it to AccountManager
self.http.authzModule = gdModule                                 // [4] Inject the AuthzModule 
                                                                 // into the HTTP layer object 
let multipartData = MultiPartData(data: self.snapshot(),         // [5] Define multi-part 
          name: "image",
          filename: "incognito_photo",
          mimeType: "image/jpg")
let multipartArray =  ["file": multipartData]
self.http.POST("https://www.googleapis.com/upload/drive/v2/files",   // [6] Upload image
               parameters: multipartArray,
               completionHandler: {(response, error) in
  if (error != nil) {
    self.presentAlert("Error", message: error!.localizedDescription)
  } else {
    self.presentAlert("Success", message: "Successfully uploaded!")

Here’s what’s going on in the method above:

  1. You’ll need to replace YOUR_GOOGLE_CLIENT_ID above with the Client ID from your Google Console to use the correct authorization configuration.
  2. This defines the scope of the grant request. In the case of Incognito, you need access to the Drive API.
  3. You then instantiate an OAuth2 module via AccountManager utility methods.
  4. Next you inject the OAuth2 module into the HTTP object, which links the HTTP object to the authorization module.
  5. Then you create a multi-part data object to encapsulate the information you wish to send to the server.
  6. Finally, you use a simple HTTP call in to upload the photo. POST() checks that an OAuth2 module is plugged into HTTP and makes the appropriate call for you. One of the following:
    • start the authorization code grant if no access token exists.
    • refresh the access token if needed.
    • if all tokens are available, simply run the POST call.
Note: For more information on how to use AeroGear OAuth2, check out AeroGear’s the online documentation and API reference, or browse through the source code in the Pods section.

Build and run your app; select an image, add an overly of your choosing, then tap the Share button. Enter your Google credentials if you’re prompted; if you’ve logged in before, your credentials may be cached. You’ll be redirected to the grant page. Tap Accept and…

Boom — you receive the Safari Cannot Open Page error message. :[ What’s up with that?

Invalid address in OAuth2 flow

Once you tap Accept, the Google OAuth site redirects you to com.raywenderlich.Incognito://[some url]. Therefore, you’ll need to enable your app to open this URL scheme.

Note: Safari stores your authentication response in a cookie on the simulator, so you won’t be prompted again to authenticate. To clear these cookies in the simulator, go to iOS simulator\Reset content and Settings.

Configuring the URL Scheme

To allow your user to be re-directed back to Incognito, you’ll needs to associate a custom URL scheme with your app.

Go to the Incognito\Supporting Files group in Xcode and find Info.plist. Right click on it and choose Open As\Source Code.

Add the following to the bottom of the plist, right before the closing </dict> tag:


The scheme is the first part of a URL. In web pages, for example, the scheme is usually http or https. iOS apps can specify their own custom URL schemes, such as com.raywenderlich.Incognito://doStuff. The important point is to choose a custom scheme that it unique among all apps installed on your users’ devices.

The OAuth2 dance uses your custom URL scheme to re-enter the application from which the request came. Custom schemes, like any URL, can have parameters. In this case, the authorization code is contained in the code parameter. The OAuth2 library will extract the authorization code from the URL and pass it in the next request in exchange for the access token.

You’ll need to implement a method in Incognito’s AppDelegate class for the app to respond when it’s launched via a custom URL scheme.

Open AppDelegate.swift and add the following import statement to the top of the file:

import AeroGearOAuth2

Next, implement application(_: openURL: sourceApplication: annotation) as shown below:

func application(application: UIApplication,
  openURL url: NSURL,
  sourceApplication: String?,
  annotation: AnyObject?) -> Bool {
    let notification = NSNotification(name: AGAppLaunchedWithURLNotification,
    return true

This method simply creates an NSNotification containing the URL used to open the app. The AeroGearOAuth2 library listens for the notification and calls the completionHandler of the POST method you invoked above.

Build and run your project again, take a snazzy selfie and dress it up. Click the share button, authenticate yourself, and lo and behold:


You can download the finished Incognito AeroGear project from this section if you wish.

Switching context to an external browser during the OAuth2 authentication step is a bit clunky. There must be a more streamlined approach…

Using Embedded Web Views

Embedded web views make for a more user-friendly experience. This can be achieved by using a UIWebView rather than switching to Safari. From a security point of view, it’s a less-secure approach since your app’s code sits between the login form and the provider. Your app could use Javascript to access the credentials of the user as they type them. However, this could be an acceptable option if your end users trust your app to be secure.


You’ll revisit the share method using the OAuthSwift library, but this time, you’ll implement OAuth2 using an embedded web view.

OAuthSwift with Embedded Web View

You’re going to start again with a different project. So close the existing Xcode workspace, download this version of the Incognito starter project, and open the project in Xcode using the Incognito.xcworkspace file.

Build and run the project; things should look pretty familiar.

As before, you first need to import the OAuthSwift library included in the project.

Open ViewController.swift and add the following import to the top of the file:

import OAuthSwift

Still in ViewController.swift, add the following code to share():

// 1 Create OAuth2Swift object
let oauthswift = OAuth2Swift(
  consumerKey:    "YOUR_GOOGLE_DRIVE_CLIENT_ID",         // 2 Enter google app settings
  authorizeUrl:   "https://accounts.google.com/o/oauth2/auth",
  accessTokenUrl: "https://accounts.google.com/o/oauth2/token",
  responseType:   "code"
// 3 Trigger OAuth2 dance
  NSURL(string: "com.raywenderlich.Incognito:/oauth2Callback")!,
  scope: "https://www.googleapis.com/auth/drive",        // 4 Scope
  state: "",
  success: { credential, response in
    var parameters =  [String: AnyObject]()
    // 5 Get the embedded http layer and upload
      parameters: parameters,
      image: self.snapshot(),
      success: { data, response in
        let jsonDict: AnyObject! = NSJSONSerialization.JSONObjectWithData(data,
          options: nil,
          error: nil)
        self.presentAlert("Success", message: "Successfully uploaded!")
      }, failure: {(error:NSError!) -> Void in
        self.presentAlert("Error", message: error!.localizedDescription)
  }, failure: {(error:NSError!) -> Void in
    self.presentAlert("Error", message: error!.localizedDescription)

Here’s what’s going on in the code above:

  1. You first create the OAuth2Swift that will handle the OAuth dance for you.
  2. You’ll need to replace YOUR_GOOGLE_CLIENT_ID and YOUR_GOOGLE_DRIVE_CLIENT_SECRET with the client id and client secret from the Google console.
  3. Here you request authorization via the oauthswift instance.
  4. The scope parameter indicates that you are requesting access to the Drive API.
  5. If authorization is granted, you can go ahead and upload the image.

Configuring URL Handling

Just as in the previous project, this version of Incognito has been set up to accept a custom URL scheme; all you need to do is implement the code to handle the custom URL.

Open AppDelegate.swift and add the following import:

import OAuthSwift

Then, implement application(_:openURL: sourceApplication: annotation:) as shown below:

func application(application: UIApplication,
  openURL url: NSURL,
  sourceApplication: String?,
  annotation: AnyObject?) -> Bool {
    return true

Unlike AeroGearOAuth2, OAuthSwift uses a class method to handle parsing the returned URL. However, if you inspect the handleOpenURL(_) method, you’ll see that it simply sends an NSNotification, just like AeroGearOAuth2 required you to do!

Build and run your project; create a new selfie and upload it. Woo! It works again! That was easy. :]

Displaying the UIWebView

As promised, you’ll now add the web view. In Xcode, click on the Incognito file group in Project Navigator and choose the File\New\File… menu option. Select iOS\Source\Swift File then click Next. Name it WebViewController and save it with your project.

Then open WebViewController.swift and add the following content to it:

import UIKit
import OAuthSwift
class WebViewController: OAuthWebViewController {
  var targetURL : NSURL?
  var webView : UIWebView = UIWebView()
  override func viewDidLoad() {
    webView.frame = view.bounds
    webView.autoresizingMask =
      UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleHeight
    webView.scalesPageToFit = true
  override func setUrl(url: NSURL) {
    targetURL = url
  func loadAddressURL() {
    if let targetURL = targetURL {
      let req = NSURLRequest(URL: targetURL)

In the above code, you create a WebViewController class that extends OAuthWebViewController. This class only implements one method: setUrl:. In viewDidLoad() you adjust the size of the web view and add it to the view controller’s superview. Additionally, you load the URL passed in by the OAuth2Swift instance that made the request.

Next, open ViewController.swift and locate the share() method. Then add the following line immediately after the creation of the oauthswift instance and before the call to authorizeWithCallbackURL:

oauthswift.webViewController = WebViewController()

This tells the oauthswift instance to use the web view controller you just created.

Finally, open AppDelegate.swift and modify application(_:openURL: sourceApplication: annotation:) by adding the following line just above return true:

// [1] Dismiss webview once url is passed to extract authorization code
UIApplication.sharedApplication().keyWindow?.rootViewController?.dismissViewControllerAnimated(true, completion: nil)

Build and run your project again; note that when the authentication form appears, it’s not displayed within Safari, and no app switching happens. As well, the authentication form is presented each time you run the app since no web cookies are stored in your app by default.

Using a UIWebView is to authenticate with Google looks more streamlined, for sure! :]

You can download the final Incognito OAuthSwift project here.

There’s one thing left to look at in this tutorial. You’ll revisit the share() method and make use of the well-known HTTP library AFNetworking with its OAuth2 companion.

Authenticating with AFOAuth2Manager

AFOAuth2Manager takes a different approach than other OAuth2 libraries: it’s a lower-level API based on the well known AFNetworking framework. Whether you want to use a UIWebView or open an external browser is entirely up to you; the developer is free to choose either mechanism to initiate step 1 of the OAuth2 dance.

Once again there’s another starter project for this part of the tutorial. Close your existing project and then download the new one here: Incognito starter project.

Open the new project and then open ViewController.swift. You’ll begin by defining some helper methods and extensions.

Add the following String extension to the top of the file:

extension String {
  public func urlEncode() -> String {
    let encodedURL = CFURLCreateStringByAddingPercentEscapes(
      self as NSString,
    return encodedURL as String

The above code simply extends the String class by adding a function that URL encodes a given string.

Now, add the following method to to ViewController:

func parametersFromQueryString(queryString: String?) -> [String: String] {
  var parameters = [String: String]()
  if (queryString != nil) {
    var parameterScanner: NSScanner = NSScanner(string: queryString!)
    var name:NSString? = nil
    var value:NSString? = nil
    while (parameterScanner.atEnd != true) {
      name = nil;
      parameterScanner.scanUpToString("=", intoString: &name)
      parameterScanner.scanString("=", intoString:nil)
      value = nil
      parameterScanner.scanUpToString("&", intoString:&value)
      parameterScanner.scanString("&", intoString:nil)
      if (name != nil && value != nil) {
          = value!.stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
  return parameters

This simply extracts query string parameters from a string representation of a URL. For example, if the query string is name=Bob&age=21 this method would return a dictionary containing name => Bob, age => 21.

Next, you’ll need to define a helper function in ViewController to extract the OAuth code from the URL passed in a NSNotification.

Simply add the following method below the existing share() method:

func extractCode(notification: NSNotification) -> String? {
  let url: NSURL? = (notification.userInfo as!
    [String: AnyObject])[UIApplicationLaunchOptionsURLKey] as? NSURL
  // [1] extract the code from the URL
  return self.parametersFromQueryString(url?.query)["code"]

This grabs the code key from the query string dictionary, obtained using the method you implemented just now.

Now add the following code to share():

// 1 Replace with client id /secret
let clientSecret = "YOUR_GOOGLE_CLIENT_SECRET"
let baseURL = NSURL(string: "https://accounts.google.com")
let scope = "https://www.googleapis.com/auth/drive".urlEncode()
let redirect_uri = "com.raywenderlich.Incognito:/oauth2Callback"
if !isObserved {
  // 2 Add observer
  var applicationLaunchNotificationObserver = NSNotificationCenter.defaultCenter().addObserverForName(
    object: nil,
    queue: nil,
    usingBlock: { (notification: NSNotification!) -> Void in
      // [5] extract code
      let code = self.extractCode(notification)
      // [6] carry on oauth2 code auth grant flow with AFOAuth2Manager
      var manager = AFOAuth2Manager(baseURL: baseURL,
        clientID: clientID,
        secret: clientSecret)
      manager.useHTTPBasicAuthentication = false
      // [7] exchange authorization code for access token
        code: code,
        redirectURI: redirect_uri,
        success: { (cred: AFOAuthCredential!) -> Void in
          // [8] Set credential in header
          manager.requestSerializer.setValue("Bearer \(cred.accessToken)",
            forHTTPHeaderField: "Authorization")
          // [9] upload photo
            parameters: nil,
            constructingBodyWithBlock: { (form: AFMultipartFormData!) -> Void in
            }, success: { (op:AFHTTPRequestOperation!, obj:AnyObject!) -> Void in
              self.presentAlert("Success", message: "Successfully uploaded!")
            }, failure: { (op: AFHTTPRequestOperation!, error: NSError!) -> Void in
              self.presentAlert("Error", message: error!.localizedDescription)
        }) { (error: NSError!) -> Void in
          self.presentAlert("Error", message: error!.localizedDescription)
  isObserved = true
// 3 calculate final url
var params = "?scope=\(scope)&redirect_uri=\(redirect_uri)&client_id=\(clientID)&response_type=code"
// 4 open an external browser
UIApplication.sharedApplication().openURL(NSURL(string: "https://accounts.google.com/o/oauth2/auth\(params)")!)

Whoa, that’s a big method! But it makes a lot of sense when you break it down, step-by-step:

  1. As always, you need to replace YOUR_GOOGLE_CLIENT_ID and YOUR_GOOGLE_DRIVE_CLIENT_SECRET with the client id and client secret from Google console.
  2. You next add an observer for the notification that will be sent by the AppDelegate.
  3. Here you build a list of parameters that will be used by OAuth.
  4. Then you kick off the OAuth dance by opening the URL in Safari.
  5. Once the user grants access, this block executes, and you start by extracting the code from the callback URL.
  6. You then you carry on with step two of the OAuth2 flow: Exchange Code for Token.
  7. Once you get the token…
  8. …you attach it to the HTTP header…
  9. …and finally, make the call to upload the photo to Google Drive.

This approach is a bit more involved than the other libraries, as you have to extract the authorization code yourself. The above code reuses some of the functionality from the AeroGear library.

There’s just one more step!

As you’ve done before, open AppDelegate.swift and add the following method:

func application(application: UIApplication,
  openURL url: NSURL,
  sourceApplication: String?,
  annotation: AnyObject?) -> Bool {
    let notification = NSNotification(
      name: "AGAppLaunchedWithURLNotification",
    return true

This fires a notification, that the authorization code listens to, in order to obtain the code from the URL.

Build and run your project one final time. It works again! Just like before, but using AFOAuth2Manager this time!

You can download the final Incognito AFOAuth2Manager project here.

More About Tokens

One thing you haven’t looked at is how to store those precious access and refresh tokens you receive as part of the OAuth2 dance. Where do you store them? How do you refresh an expired access token? Can you revoke your grants?

Storing tokens

The best way to store them is…on your Keychain, of course! :]


This is the default strategy adopted by AFOAuthCredential (from AFOAuth2Manager) and OAuth2Session (from AeroGear).

If you would like to read more about the keychain, then I recommend reading our other tutorials on the subject.

Refreshing and Revoking

To refresh the access token, you simply make an HTTP call to an access token endpoint and pass the refresh token as parameter.

For example, AeroGear leaves it up to the library to determine whether the token is still valid by using requestAccess:completionHandler: method.

OAuth2 defines a different specification for revoking tokens, which makes it possible to either revoke tokens separately or all at once. Most providers revoke both access and refresh tokens at the same time.

Where To Go From Here?

You covered not one, not two, but three open source libraries that implement OAuth2 – and hopefully learned a little more about how OAuth2 works under the hood.

Maybe now you’re ready to read the OAuth2 specification, RFC6749?! OK, maybe not. It’s a beast of a document! But at least you now understand the fundamentals and how it relates to your app.

I hope you use one of them in your app. Once you’ve picked your favorite open source OAuth2 library, contributing to it is essential. If you notice a bug, report an issue. If you know how to fix it, even better – propose a pull request.

If you have any comments or questions about this tutorial, please join the forum discussion below!

Corinne Krych

Dev for over many years (when you like it you don't really count), iOS tech lead for Red Hat, I never go too far from coding. Polyglot by heart and addicted to clean code, I like to share and exchange ideas in user groups or conferences. Mobile is my playground, AeroGear my open source family and iOS my platform by heart.

Other Items of Interest

raywenderlich.com Weekly

Sign up to receive the latest tutorials from raywenderlich.com each week, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

PragmaConf 2016 Come check out Alt U

Our Books

Our Team

Video Team

... 19 total!

Swift Team

... 16 total!

iOS Team

... 30 total!

Android Team

... 15 total!

macOS Team

... 11 total!

Apple Game Frameworks Team

... 10 total!

Unity Team

... 11 total!

Articles Team

... 11 total!

Resident Authors Team

... 11 total!