OAuth2 implementation with ORY Hydra, Vapor 3 and iOS 12

Part 4: Set up OAuth2 authorization on iOS with AppAuth

This part of our tutorial series about setting up OAuth2 with ORY Hydra, Vapor and iOS will focus on building the iOS client. It will be a very simple app that only shows a button to create an account and switches to a success message, in case the user successfully logged in. We will use a library called AppAuth to interact with our authorization server.

Tutorial series

Part 1: Introduction and setup of ORY Hydra authorization server

Part 2: User management in Vapor backend

Part 3: Set up Vapor backend as identity provider for ORY Hydra

Part 4: Set up OAuth2 authorization on iOS with AppAuth (you are here)

Prerequisites

You should checkout the previous parts of the series listed above.

Create iOS Xcode project

Open up Xcode or your editor of choice and create a new Single View application. You will be provided with a ViewController.swift class already, its view is configured in the storyboard.

Open the storyboard and add a button on the ViewController that triggers the authentication flow. Then add a hidden label with a success message, that we can show instead after the user logged in successfully.

Storyboard for iOS project

Next, open the ViewController.swift file and drag outlets for the two buttons in there and also one for the button action. Call that function authorize .

Outlets in ViewController.swift

Now we got the basic setup of the iOS project. Next we want to integrate a 3rd party library called AppAuth that will take care of interacting with the authorization server.

Interaction with the authorization server via AppAuth

We use Cocoapods to integrate AppAuth in our sample project, but you can also use something else if you like. Checkout AppAuth’s Github project for different integration options.

After adding AppAuth to our project, we want to have a dedicated service that is taking care of everything related to authentication. Create a new file called AuthService.swift and import AppAuth as a dependency.

Create authorization request

To authorize a user using AppAuth we’ll need to create an OIDAuthorizationRequest . Create a function in the AuthService called authorize and create an authorization request in there:

Authorize function in AuthService.swift

The authorization request takes quite a few parameters:

configuration : The configuration is needed to construct an OIDAuthorizationService . It contains the URLs for accessing the Hydra authorization server.

: The configuration is needed to construct an . It contains the URLs for accessing the Hydra authorization server. clientId : The identifier of the client we registered on our Hydra server.

: The identifier of the client we registered on our Hydra server. clientSecret : The secret of the client we registered on our Hydra server (in production you should definitely not store this information on the iOS client).

: The secret of the client we registered on our Hydra server (in production you should definitely not store this information on the iOS client). scopes : The scope describes what kind of information we want to access, similar to the requested_scope parameter in the consent request of the identity provider. In our case we want to make an OpenID connect request and want to be able to receive refresh tokens (this is what offline is used for).

: The scope describes what kind of information we want to access, similar to the parameter in the consent request of the identity provider. In our case we want to make an OpenID connect request and want to be able to receive refresh tokens (this is what is used for). redirectURL : The redirect URL that should be called after a successful login.

: The redirect URL that should be called after a successful login. responseType : The response type of the authorization request, could be e.g. code or token . As we are using the authorization code flow, we want to use code .

: The response type of the authorization request, could be e.g. or . As we are using the authorization code flow, we want to use . additionalParameters : Any additional parameters needed for authorization. None needed in our case.

Define authorization URLs

So, there is some information we need to pass to AppAuth to enable it to request authorization from our Hydra server. Add the following properties at the top of our AuthService :

Authorization URLs in AuthService.swift

authEndpoint and tokenEndpoint : URLs of Hydra’s Public API

and : URLs of Hydra’s Public API redirectURL : can be chosen by us, but needs to follow a certain URL scheme to be able to be detected by the app

: can be chosen by us, but needs to follow a certain URL scheme to be able to be detected by the app clientId and clientSecret : identifier and secret of the client we registered on our Hydra server

and : identifier and secret of the client we registered on our Hydra server config : service configuration for AppAuth containing the authEndpoint and the tokenEndpoint

To enable the iOS app to handle the redirectURL we need to add the URL scheme in the Info.plist . Open it and add a new entry called URL types like this:

Add custom URL scheme in Info.plist

In addition we need to allow the app to handle non-SSL URLs. For that we need to add another entry to the Info.plist called App Transport Security Settings :

Allow usage of non-SSL URLs in Info.plist

Trigger authorization request

After creating the authorization request, we now need to actually trigger that request. We can use a convenience function provided by AppAuth that creates a new OIDExternalUserAgentSession , which we’ll need to hold in our AuthService . Add this line at the top of our AuthService :

Hold current auth flow in AuthService.swift

Then modify authorize to look like this:

Authorize function in AuthService.swift

First we changed the signature of the function to take in a UIViewController and callbacks for the success and error cases. Then we trigger the authorization request by creating a new authorization session using the request we created before.

After creating the authorization session we’ll receive either an OIDAuthState object or an error. OIDAuthState is a convenience class by AppAuth that contains all relevant information about the authorization state of the user.

Go back to the ViewController and call this function when the create account button is tapped.

Authorize function in ViewController.swift

We created an instance of AuthService and call authorize on button tap. If we can successfully authorize the user, we show the success message instead of the button.

That’s it for the iOS part.

Testing our setup

We now developed all three parts we need for implementing an OAuth2 authorization. To be able to test it, we need to start our Hydra server, run our backend and run the iOS client.

Start Hydra Server: Revisit Part 1 and follow the steps to start the Hydra server and create the client Run Backend in Xcode: Just start the Run configuration of our Vapor backend in Xcode Run iOS Client in Xcode: Also here, just run the default scheme in Xcode

In your iOS simulator you should now see a white screen with the Create Account button. If you tap it, you should be redirected to a web browser that is displaying the Login UI. Try registering a user and see the success message afterwards. You can checkout the short video in the beginning of Part 1 to see the expected result.

Congrats! You’ve made it all the way and implemented your own authorization code flow with ORY Hydra, Vapor and iOS.

Prospects

We plan on writing follow-up parts for this tutorial about authorization of users using ORY Oathkeeper and making the whole setup production ready.

If you have problems with the tutorial or comments, feel free to contact us via our website!

Further Reading

AppAuth documentation

https://github.com/openid/AppAuth-iOS

OAuth2 for mobile

https://www.ory.sh/oauth2-for-mobile-app-spa-browser

Resources

You can find the fully implemented iOS app for this tutorial on Github!

Stay updated

If you liked this tutorial and are interested in further articles from us, follow us here or on Twitter and checkout our website!