Like single-page apps, mobile apps also cannot maintain the confidentiality of a client secret. Because of this, mobile apps must also use an OAuth flow that does not require a client secret. The current best practice is to use the Authorization Flow along with launching an external browser, in order to ensure the native app cannot modify the browser window or inspect the contents.
Many websites provide mobile SDKs which handle the authorization process for you. For those, you are probably better off using their SDKs directly, since they may have augmented their APIs with non-standard additions. Google provides an open source library called AppAuth which handles the implementation details of the flow described below. It is meant to be able to work with any OAuth 2.0 server that implements the spec. In the case that the service does not a provide their own abstraction, and you have to use their OAuth 2.0 endpoints directly, this section describes how to use the Authorization grant to interface with an API.
Create a “Log in” button that will either open an
SFSafariViewController or launch a native browser. You’ll use the same parameters for the authorization request as described in Server-Side Apps.
For the redirect URL of the native app, on iOS, apps can register a custom URL scheme such as
org.example.app:// so the application is launched whenever a URL with that scheme is visited. On Android, apps can register URL matching patterns which will launch the native app if a URL matching the pattern is visited.
In this example we will create a simple iPhone application that obtains authorization to access a fictional API.
The app initiates the authorization request
To begin the authorization process, the app should have a “sign in” button. The link should be constructed as a full URL to the service’s authorization endpoint.
The authorization URL is usually in a format such as:
https://authorization-server.com/authorize ?client_id=eKNjzFFjH9A1ysYd &response_type=code &redirect_uri=exampleapp://auth &state=1234zyx
Note in this case the custom scheme of the redirect URL. iOS provides the ability for apps to register custom URL schemes. On Android, apps can instead match specific URL patterns so that the app is presented in a list of apps to handle when visiting a certain URL. On iOS, you should register the custom scheme you will be using in the app’s
.plist file. This will cause the device to launch your app any time a URL that begins with your custom scheme is visited, including from mobile Safari or from within other iOS apps.
When the user taps the “Sign In” button, the app should open the login URL in a
SFSafariViewController to open an embedded browser that shares system cookies. Using an embedded
WebView window within the app is considered extremely dangerous, as this provides the user no guarantee they are looking at the service’s own website, and is an easy source of a phishing attack. By using the
SFSafariViewController API, which shares the Safari cookies, you have the advantage of the user potentially already being signed in to the service as well.
The user approves the request
Upon being directed to the auth server, the user sees an authorization request shown below.
The service redirects the user back to the app
When the user finishes signing in, the service will redirect back to your app’s redirect URL, which in this case, has a custom scheme that will trigger the
application:openURL:options: method in your app delegate. The
Location header from the redirect will look something like the following, which will be passed in as the
url parameter to your method.
Your app should then parse out the authorization code from the URL, exchange the code for an access token, and dismiss the
SFSafariViewController. Exchanging the code for an access token is the same as in the Authorization Code flow, except without using the client secret.
Always open a native browser or use
You should never open an embedded web view with the OAuth prompt, since it provides no way for the user to verify the origin of the web page they’re looking at. It would be trivial for an attacker to create a web page that looks just like the authorization web page and embed it in their own malicious app, giving them the ability to steal usernames and passwords.
If the service you are using supports the PKCE extension (RFC 7636 https://tools.ietf.org/html/rfc7636), then you should take advantage of the additional security it provides. Often times, such as in the case with the Google OAuth APIs, the native SDKs provided by the service will handle this transparently so that you don’t have to worry about the details and you can benefit from the additional security without any additional work.
We cover the PKCE extension in PKCE.