TL;DR: In October, 2017, the Internet Engineering Task Force (IETF) released the Best Current Practices (BCP) when using OAuth 2.0 with native mobile applications. This BCP states that OAuth 2.0 authorization requests from native apps should only be made through external user agents, primarily the user's browser. We'll discuss what this means for developers and users and any security considerations involved.
OAuth 2.0 Best Current Practice for Native Apps
The IETF (Internet Engineering Task Force) recently released the Best Current Practice for OAuth 2.0 for Native Apps Request For Comments. This document requires that, in accordance with best practices, only external user agents (such as the browser) should be used with the OAuth 2.0 Authorization Framework by native applications; this is known as the "AppAuth pattern". Embedded user agents should not be implemented.
For authorizing users in native apps, the best current practice is to perform the OAuth authorization request in an external user agent (typically the browser) rather than an embedded user agent (such as one implemented with web-views).
Using the browser to make native app authorization requests results in better security. It also enables use of the user's current authentication state, making single sign-on possible. Embedded user agents are unsafe for third parties. If used, the app has access to the OAuth authorization grant as well as the user's credentials, leaving this data vulnerable to recording or malicious use. Embedded user agents also don't share authentication state, meaning no single sign-on benefits can be conferred.
We'll go into the security and implementation advantages of using the browser for authorization requests in more detail below.
Authorization Flow for Native Apps Using the Browser
The authorization flow for native apps using the browser acts as illustrated in the following diagram:
- Client app opens a browser tab with the authorization request.
- Authorization endpoint receives the authorization request, authenticates the user, and obtains authorization. Authenticating the user may involve chaining to other authentication systems.
- Authorization server issues an authorization code to the redirect URI.
- Client receives the authorization code from the redirect URI.
- Client app presents the authorization code at the token endpoint.
- Token endpoint validates the authorization code and issues the tokens requested.
Figure 1, OAuth 2.0 for Native Apps
URIs are used for OAuth 2.0 on the web for authorization requests and responses. Similarly, URIs can also be used in native apps. When the built-in browser is employed by the user for all native app logins, certain advantages are conferred, such as the ability to use a single sign-on session stored in a central location and additional security afforded by an authentication context that is separated from the app. Browser security is also a major focus of vendors, and they tend to manage security and sessions policies quite well. In addition, supporting and implementing the same approach in web and native apps reduces complexity and increases interoperability.
"Implementing external user agents in both web & native apps reduces complexity and increases interop."
Initiating and Receiving Authorization Requests
Native apps now must request user authorization by creating a URI with the appropriate grant type specified in the OAuth 2.0 Authorization Framework. The app then redirects the user to this request URI. A redirect URI that the native app can receive and parse appropriately must also be supplied. This must be implemented using an external user agent. Use of the device browser is recommended.
The authorization server must permit at least three redirect URI options for the response sent back to the native app:
- Private-Use URI Scheme Redirection
- Claimed "https" Scheme URI Redirection
- Loopback Interface Redirection
You can read about these three options in detail in Section 7 of OAuth 2.0 for Native Apps.
OAuth 2.0 Security Considerations for Native Apps
When implementing OAuth 2.0, there are a number of security considerations that developers must be mindful of when using best current practice with an external user agent. We'll go over a few of them now.
Authorization Code and Grant Flow
Using the redirect options above means that the authorization code can only be received by native apps on the same device. While this increases security, it does still mean that another app on the same device could potentially intercept the code. The Proof Key for Code Exchange (PKCE) protocol was created to defend against this attack vector. Public apps as well as servers must use PKCE, and servers should reject authorization requests from apps that do not.
Authorization Servers and Clients
In most cases, native apps are considered public clients and must be registered with the authorization server. Authorization servers must also register a client's complete redirect URI. If an authorization request does not match the registered redirect URI, the request must be rejected.
User authentication and consent will be required by the authorization server, as per any other web browser based OAuth 2.0 flows.
Embedded user agents should not be used to masquerade as an external user agent. Authorization servers can protect against these fake agents by requiring an authentication factor only available to genuine external user agents.
Cross-Site Request Forgery (CSRF) attacks should also be mitigated by using the
state parameter to link client requests and responses. More details are available in section 5.3.5 of OAuth 2.0 Threat Model and Security Considerations.
The user's browser is the recommended external user agent. Embedded user agents must not be used for authorization requests. Authorization servers may detect and block requests from embedded user agents, as they are unsafe for third parties, such as the authorization server itself. The reason for this is because the app can then access not only the OAuth authorization grant, but also the user's full authentication credentials. The app could then potentially record or use this information maliciously. In addition, embedded user agents don't share authentication state with other apps or the browser and therefore disabling single sign-on benefits.
If you're a native app developer, it's very important to adhere to best current practices. Please take the time to read over the OAuth 2.0 for Native Apps RFC yourself. Using an external user agent for OAuth 2.0 authorization requests provides better security as well as an improved user experience as it enables single sign-on across the device's apps and browser.
Centralized Login with Auth0
Auth0 provides a centralized login approach that adheres to the OAuth 2.0 Best Current Practice for native apps. Centralized login provides the most secure experience and is also easy to implement for developers. A URI is used to trigger an authentication request and the centralized login page is shown to users. This login page can use the Auth0 Lock widget or your own custom UI. After authorization, the user is returned to your app via your provided redirect. Auth0 provides extensive documentation to help you easily implement the appropriate flows to keep your apps secure and user-friendly as well.
Check out the following resources to learn more about implementing Auth0 with centralized login in your native apps in accordance with the OAuth 2.0 Best Current Practice:
- Centralized Login Page
- OAuth 2.0
- Calling APIs from Mobile Apps (Authorization Code PKCE)
- iOS Swift Quickstart - Login
- Android Quickstart - Login