96
votes

I am trying to implement delegated authorization in a Web API for mobile apps using OAuth 2.0. According to specification, the implicit grant flow does not support refresh tokens, which means once an access token is granted for an specific period of time, the user must grant permissions to the app again once the token expires or it is revoked.

I guess this is a good scenario for some javascript code running on a browser as it is mentioned in the specification. I am trying to minimize the times the user must grant permissions to the app to obtain a token, so it looks like the Authorization Code flow is a good option as it supports refresh tokens.

However, this flow seems to rely heavily on a web browser for performing the redirections. I am wondering if this flow is still a good option for a mobile app if a embedded web browser is used. Or should I go with the implicit flow ?

5
The question would be - is it like the highest priority that the user never ever has to type in a password again after the first login?leastprivilege
Yes, that's exactly my requirement. The user should type the password just once. However, I don't want to setup a token with infinite lifetime and keep it in the mobile app, as that would go against the ability of revoking the token. (Unless I add some logic in the mobile app to detect that the request was unauthorized so I request a new token after that)Pablo Cibraro
You can add a token with infinite lifetime and still revoke it. And yes, the app logic should be able to detect that. RFC 6750 defines a way to check if the error is due to a revoked token.Pedro Felix
Please avoid web views (unless you own the full stack and are not using social login) which open the possibility of compromising passwords. When I am asked for credentials by a third-party embedded user-agent I would uninstall the app. Some APIs now even ban such integrations such as this one dev.fitbit.com/docs/oauth2 I have provided another answer to further clarify some of these concepts (stackoverflow.com/a/38582630/752167)Matt C

5 Answers

99
votes

Clarification: Mobile App = Native App

As stated in other comments and a few sources online, implicit seems like a natural fit for mobile apps, however the best solution is not always clear cut (and in fact implicit is not recommended for reasons discussed below).

Native App OAuth2 Best Practises

Whatever approach you choose (there are a few trade offs to consider), you should pay attention to the best practices as outlined here for Native Apps using OAuth2: https://tools.ietf.org/html/rfc8252

Consider the following options

Implicit

Should I use implicit?

To quote from Section 8.2 https://tools.ietf.org/html/rfc8252#section-8.2

The OAuth 2.0 implicit grant authorization flow (defined in Section 4.2 of OAuth 2.0 [RFC6749]) generally works with the practice of performing the authorization request in the browser and receiving the authorization response via URI-based inter-app communication.
However, as the implicit flow cannot be protected by PKCE [RFC7636] (which is required in Section 8.1), the use of the Implicit Flow with native apps is NOT RECOMMENDED.

Access tokens granted via the implicit flow also cannot be refreshed without user interaction, making the authorization code grant flow -- which can issue refresh tokens -- the more practical option for native app authorizations that require refreshing of access tokens.

Authorization Code

If you do go with Authorization Code, then one approach would be to proxy through your own web server component which enriches the token requests with the client secret to avoid storing it on the distributed app on devices.

Excerpt below from: https://dev.fitbit.com/docs/oauth2/

The Authorization Code Grant flow is recommended for applications that have a web service. This flow requires server-to-server communication using an application's client secret.

Note: Never put your client secret in distributed code, such as apps downloaded through an app store or client-side JavaScript.

Applications that do not have a web service should use the Implicit Grant flow.

Conclusion

The final decision should factor in your desired user experience but also your appetite for risk after doing a proper risk assessment of your shortlisted approaches and better understanding the implications.

A great read is here https://auth0.com/blog/oauth-2-best-practices-for-native-apps/

Another one is https://www.oauth.com/oauth2-servers/oauth-native-apps/ which states

The current industry best practice is to use the Authorization Flow while omitting the client secret, and to use an external user agent to complete the flow. An external user agent is typically the device’s native browser, (with a separate security domain from the native app,) so that the app cannot access the cookie storage or inspect or modify the page content inside the browser.

PKCE Consideration

You should also consider PKCE which is described here https://www.oauth.com/oauth2-servers/pkce/

Specifically, if you are also implementing the Authorization Server then https://www.oauth.com/oauth2-servers/oauth-native-apps/checklist-server-support-native-apps/ states that you should

  • Allow clients to register custom URL schemes for their redirect URLs.
  • Support loopback IP redirect URLs with arbitrary port numbers in order to support desktop apps.
  • Don’t assume native apps can keep a secret. Require all apps to declare whether they are public or confidential, and only issue client secrets to confidential apps.
  • Support the PKCE extension, and require that public clients use it.
  • Attempt to detect when the authorization interface is embedded in a native app’s web view, instead of launched in a system browser, and reject those requests.

Web Views Consideration

There are many examples in the wild using Web Views i.e. an embedded user-agent but this approach should be avoided (especially when the app is not first-party) and in some cases may result in you being banned from using an API as the excerpt below from here demonstrates

Any attempt to embed the OAuth 2.0 authentication page will result in your application being banned from the Fitbit API.

For security consideration, the OAuth 2.0 authorization page must be presented in a dedicated browser view. Fitbit users can only confirm they are authenticating with the genuine Fitbit.com site if they have the tools provided by the browser, such as the URL bar and Transport Layer Security (TLS) certificate information.

For native applications, this means the authorization page must open in the default browser. Native applications can use custom URL schemes as redirect URIs to redirect the user back from the browser to the application requesting permission.

iOS applications may use the SFSafariViewController class instead of app switching to Safari. Use of the WKWebView or UIWebView class is prohibited.

Android applications may use Chrome Custom Tabs instead of app switching to the default browser. Use of WebView is prohibited.

To further clarify, here is a quote from this section of a previous draft of the best practise link provided above

Embedded user-agents, commonly implemented with web-views, are an alternative method for authorizing native apps. They are however unsafe for use by third-parties by definition. They involve the user signing in with their full login credentials, only to have them downscoped to less powerful OAuth credentials.

Even when used by trusted first-party apps, embedded user-agents violate the principle of least privilege by obtaining more powerful credentials than they need, potentially increasing the attack surface.

In typical web-view based implementations of embedded user-agents, the host application can: log every keystroke entered in the form to capture usernames and passwords; automatically submit forms and bypass user-consent; copy session cookies and use them to perform authenticated actions as the user.

Encouraging users to enter credentials in an embedded web-view without the usual address bar and other identity features that browsers have makes it impossible for the user to know if they are signing in to the legitimate site, and even when they are, it trains them that it's OK to enter credentials without validating the site first.

Aside from the security concerns, web-views do not share the authentication state with other apps or the system browser, requiring the user to login for every authorization request and leading to a poor user experience.

Due to the above, use of embedded user-agents is NOT RECOMMENDED, except where a trusted first-party app acts as the external user- agent for other apps, or provides single sign-on for multiple first- party apps.

Authorization servers SHOULD consider taking steps to detect and block logins via embedded user-agents that are not their own, where possible.

Some interesting points are also raised here: https://security.stackexchange.com/questions/179756/why-are-developers-using-embedded-user-agents-for-3rd-party-auth-what-are-the-a

26
votes

Unfortunately, I don't think there is a clear answer to this question. However, here are the options that I've identified:

  • If it is ok to ask the user for his/her credentials, then use the Resource Owner Password Credentials. However, this may not be possible for some reasons, namely

    • Usability or security policies forbid the insertion of the password directly at the app
    • The authentication process is delegated on an external Identity Provider and must be performed via an HTTP redirect-based flow (e.g. OpenID, SAMLP or WS-Federation)
  • If usage of a browser based flow is required, then use the Authorization Code Flow. Here, the definition of the redirect_uri is a major challenge, for which there are the following options:

    • Use the technique described in https://developers.google.com/accounts/docs/OAuth2InstalledApp, where a special redirect_uri (e.g. urn:ietf:wg:oauth:2.0:oob) signals the authorization endpoint to show the authorization code instead of redirecting back to the client app. The user can manually copy this code or the app can try to obtain it from the HTML document title.
    • Use a localhost server at the device (the port management may not be easy).
    • Use a custom URI scheme (e.g. myapp://...) that when dereferenced triggers a registered "handler" (the details depend on the mobile platform).
    • If available, use a special "web view", such as the WebAuthenticationBroker on Windows 8, to control and access the HTTP redirect responses.

Hope this helps

Pedro

10
votes

TL;DR: Use Authorization Code Grant with PKCE

1. Implicit Grant Type

The implicit grant type is quite popular with mobile apps. But it was not meant to be used like this. There are security concerns around the redirect. Justin Richer states:

The problem comes when you realize that unlike with a remote server URL, there is no reliable way to ensure that the binding between a given redirect URI and a specific mobile application is honored. Any app on the device can try to insert itself into the redirection process and cause it to serve the redirect URI. And guess what: if you’ve used the implicit flow in your native application, then you just handed the attacker your access token. There’s no recovery from that point — they’ve got the token and they can use it.

And together with the fact, that it does not let you refresh the access token, better avoid it.

2. Authorization Code Grant Type

The authorization code grant requires a client secret. But you should not store sensitive information in the source code of your mobile app. People can extract them. To not expose the client secret, you have to run a server as a middleman as Facebook writes:

We recommend that App Access Tokens should only be used directly from your app's servers in order to provide the best security. For native apps, we suggest that the app communicates with your own server and the server then makes the API requests to Facebook using the App Access Token.

Not an ideal solution but there is new, a better way to do OAuth on mobile devices: Proof Key for Code Exchange

3. Authorization Code Grant Type with PKCE (Proof Key for Code Exchange)

Out of the limitations, a new technique was created that let you use the Authorization Code without a client secret. You can read the full RFC 7636 or this short introduction.

PKCE (RFC 7636) is a technique to secure public clients that don't use a client secret.

It is primarily used by native and mobile apps, but the technique can be applied to any public client as well. It requires additional support by the authorization server, so it is only supported on certain providers.

from https://oauth.net/2/pkce/

-4
votes

Using a webview in your mobile application should be an affordable way to implement OAuth2.0 protocol on Android platform.

As for redirect_uri field, I think http://localhost is a good choice and you don't have to port a HTTP server inside your application, because you can override the implementation of onPageStarted function in the WebViewClient class and stop loading the web page from http://localhost after you check the url parameter.

public void onPageStarted(final WebView webView, final String url,
        final Bitmap favicon) {}
-5
votes

The smoothest user experience for authentication, and the easiest to implement is to embed a webview in your app. Process the responses received by the webview from the authentication point and detect error (user cancel) or approval (and extract token from url query parameters). And I think you can actually do that in all platforms. I have successfully made this work for the following: ios, android, mac, windows store 8.1 apps, windows phone 8.1 app. I did this for the following services: dropbox, google drive, onedrive, box, basecamp. For the non-windows platforms, I was using Xamarin which supposedly does not expose the entire platform specific APIs, yet it did expose enough for making this possible. So it is a pretty accessible solution, even from a cross platform perspective, and you don't have to worry about the ui of the authentication form.