On this page
This tutorial shows how to run a code example that implements mobile OpenID Connect in a Swift App using the Hypermedia Authentication API (HAAPI). See also the API Driven Demo Client tutorial for an introductory guide that runs a simple web client.
Note
Curity Identity Server is used in this example, but other OAuth servers can also be used.
Overview
The code sample consists of an initial Unauthenticated View
used to trigger the sign-in, but before a login attempt is allowed, the app must cryptographically prove its identity using Client Attestation
:

The authentication workflow is then managed as a series of fast API requests that return JSON responses. The mobile app processes each API response to perform various actions including the rendering of forms:

Once authentication completes, the app presents its Authenticated View
, to simulate a mobile app that works with access tokens to call APIs. The app can then easily perform other OAuth operations such as refreshing tokens and ending the authenticated session:

Get the Code
First, ensure that you are running an up-to-date version of Xcode, then clone the GitHub repository and open its folder to view the Swift classes used.
Quick Start
The easiest way to run the code example is to point it to a deployed and preconfigured instance of the Curity Identity Server, running in Docker. This is done via a script included with the example that is explained in the Mobile Setup how-to:
./start-idsvr.sh
The result is a working instance of the Curity Identity Server, listening on localhost: https://localhost:8443
, ready for the mobile app to connect to. The Admin UI is also available and can be accessed using the following details:
Property | Value |
---|---|
URL | https://localhost:6749/admin |
User | admin |
Password | Password1 |
The deployed system also includes a user account of demouser / Password1
that can be used to sign in.
Deploying the Curity Identity Server with a Remote URL
It will sometimes be necessary to access the instance of the Curity Identity Server remotely. E.g., when you want to test the mobile app from a physical device, that is not connected to the same network where you run the server. You can use the ngrok tool to quickly expose local applications on the Internet. You can edit the start-idsvr.sh
and stop-idsvr.sh
files to use ngrok (set USE_NGROK=true
). This will result in exposing the containerized instance of the Curity Identity Server under a random domain similar to https://87ce095409f9.ngrok.io
. Should you use this option you will have to update the apps' configuration (see Updating the App Configuration).
If you want more control over exposing the Curity Identity Server with ngrok, then have a look at the Exposing with ngrok tutorial.
Configuration
The code example uses the following client settings, including the haapi
and code
capabilities. For best reliability, configure use-legacy-dpop=false
. This prevents potential clock skew problems between devices and the Curity Identity Server. Further details on HAAPI specific settings are explained in the iOS HAAPI SDK tutorial.
<config xmlns="http://tail-f.com/ns/config/1.0"><profiles xmlns="https://curity.se/ns/conf/base"><profile><id>token-service</id><type xmlns:as="https://curity.se/ns/conf/profile/oauth">as:oauth-service</type><settings><authorization-server xmlns="https://curity.se/ns/conf/profile/oauth"><client-store><config-backed><client><id>haapi-ios-dev-client</id><client-name>haapi-ios-dev-client</client-name><no-authentication>true</no-authentication><redirect-uris>haapi:start</redirect-uris><proof-key><require-proof-key>false</require-proof-key></proof-key><refresh-token-ttl>3600</refresh-token-ttl><scope>openid</scope><scope>profile</scope><user-authentication><allowed-authenticators>Username-Password</allowed-authenticators></user-authentication><capabilities><code></code><haapi><use-legacy-dpop>false</use-legacy-dpop></haapi></capabilities><validate-port-on-loopback-interfaces>true</validate-port-on-loopback-interfaces><attestation><disable-attestation-validation>true</disable-attestation-validation><ios><app-id>io.curity.cat.ios.client</app-id><ios-policy>ios-haapi-dev</ios-policy></ios></attestation></client></config-backed></client-store></authorization-server></settings></profile></profiles></config>
Updating the App Configuration
In XCode, the demo app's configuration settings are specified in the Demo/Settings/Profile
module. If using the quick start, you can just use the default values.
If you deployed the Curity Identity Server with ngrok, or have your own configuration, then you need to provide the details to the app configuration.
This can be achieved in two ways.
- Update the relevant fields in the
Constants
enum to return proper defaults:
private enum Constants {static let defaultName = "Default"static let scopes = ["openid", "profile"]static let defaultAuthorizationEndpointURI = "https://idsvr.example.com/authorize"static let defaultTokenEndpointURI = "https://idsvr.example.com/token"static let defaultUserinfoEndpointURI = "https://idsvr.example.com/userinfo"static let defaultClientId = "haapi-ios-dev-client"static let defaultBaseURLString = "https://idsvr.example.com"static let defaultMetaBaseURLString = "https://idsvr.example.com/issuer"}
- In the app itself, you can use the Profile editor to change current settings and create profiles to quickly jump between different environments. To open the settings editor, click on the settings icon while on the app's home page. You can edit an existing profile, or create a new one, then set it as active. As a convenience, you can provide the issuer URI and tap "Fetch the latest configuration". The app will query the server's metadata endpoint to fetch relevant configuration.
Run the App
Once the above configuration is complete you are ready to run the app and use whichever authenticators and users you have configured in the Curity Identity Server. In the following sections, we will explain the key technical behavior implemented in the code example.
HAAPI Integration
Integrating the Hypermedia Authentication API is done in three layers summarized below. Curity will be providing libraries for the view layer in the near future so that integration requires very little code:
Layer | Implemented By | Description |
---|---|---|
Driver | Curity Library | Processing of low-level messages used for client attestation to prove the app's identity. |
Controller | Curity Library | Processing HAAPI responses, including form submitting, following redirects, and polling the server. |
View | Your App | Overriding the defaults and customizing presentation to take full control over the login user experience. |
Client Attestation Overview
When authentication is first triggered, the app sends a number of low-level messages to prove it is the genuine app, based on the digital identity with which the app is signed and delivered to the App Store.
This must be done before the app is allowed to attempt to authenticate the user. The main request to prove the client's identity is a client assertion request with the following parameters:
Form Parameter | Example Value |
---|---|
client_id | haapi-ios-dev-client |
scope | urn:se:curity:scopes:haapi |
grant_type | client_credentials |
client_assertion_type | urn:se:curity:attestation:client |
client_assertion | eyJraWQi...paTubjbwReZ0A |
The server verifies these details and returns a JWT access token in a JSON response that must be sent with subsequent requests in the authentication workflow, along with a separate proof of possession
token. See the HAAPI Whitepaper for further details on security.
Response Field | Example Value |
---|---|
access_token | eyJraWQi...JUHpZbxbstkK41RJhA7vw |
scope | urn:se:curity:scopes:haapi |
token_type | DPoP |
HAAPI Messages
Once the client is attested it can start authenticating the user, which is done using standard OpenID Connect parameters, but with a custom accept
header to indicate that the client wants to receive hypermedia responses. The HAAPI models iOS SDK exposes a HaapiManager
class which is used to communicate with the Curity Identity Server. The manager exposes these relevant methods:
start
submit
followLink
Each returns a HaapiResult
object, which encloses a HaapiRepresentation
, a ProblemRepresentation
, or an Error
. HaapiRepresentation
is a sealed interface that might represent:
- Forms to be rendered
- Redirects to be followed
- Instructions to open the system browser or an external app
- Polling responses
- Error Responses
Response models can be processed in a generic way within the mobile app to deal with finer-grained work such as rendering the set of fields within a form model. Have a look at the Views
package group of the sample app to check how such rendering could be implemented.
Eventually, the manager will return an OAuthAuthorizationResponseStep
, which signals that the authentication has finished, and the app can now obtain access, refresh, and ID tokens from the Curity Identity Server. This can be easily done using the OAuthTokenManager
object. The token manager exposes two methods: fetchAccessToken
and refreshAccessToken
.
HAAPI Extensible Authentication
HAAPI supports many authentication methods in addition to passwords, so you are encouraged to try additional authentication options such as these:
Authentication Flow | Characteristics |
---|---|
Google Sign In | With this type of personal password, HAAPI will open the system browser to sign the user in |
CIBA Flow | With this authentication flow, HAAPI polls while a client waits for a remote user to sign in |
WebAuthn | This authenticator demonstrates passwordless and user friendly logins |
For further detail about the requests and responses used by the Hypermedia Authentication API, see the HAAPI Data Model, which provides full details on schemas for all areas, including authentication, consent, polling, and error responses.
Using and Refreshing Access Tokens
Once the client obtains an access token it will use it to call APIs in the standard way, by sending them as bearer tokens in the HTTP Authorization header. When the access token expires, the refreshAccessToken
method of the token manager is used to get a new token.
Logout
Logout can be implemented in a simple manner, by just removing tokens from the app and redirecting the user back to the Unauthenticated View
. Subsequent sign-in behavior can then be controlled via the following OpenID Connect fields. This can also be useful when testing, in order to sign in as multiple users on the same device:
OpenID Connect Request Parameter | Usage |
---|---|
prompt | Set prompt=login to force the user to re-authenticate immediately |
max-age | Set max-age=N to specify the maximum elapsed time in seconds before which the user must re-authenticate |
Conclusion
The Hypermedia Authentication API provides a number of benefits to mobile apps, in terms of both financial grade security and login usability:
- The app gets an improved login user experience
- The Identity Server continues to dictate security
- The authentication workflow can be updated without needing to redeploy the app
- Only genuine mobile clients can attempt user authentication
Man In the Browser (MITB)
risks are eliminated for most authentication methods