OAuth mobile implementation details

Maxim Myalkin
Lonto
Published in
11 min readOct 25, 2022

Hey! My name is Maxim Myalkin, I am a mobile lead at Lonto.

No service can be used without a login. Often mobile apps require login via third-party social networks, for example, Google or Meta. And when training mobile development, open APIs are used, where OAuth is used for authorization.

Therefore, mobile app developers have to work with OAuth. There are different materials on this topic on the internet.

In this series of article, I am going to explain OAuth nuances in mobile applications in a structured way: which points should be noticed, which methods of implementation to choose. I am also going to share my experience in configuring OAuth in an Android app using the AppAuth library.

  1. OAuth mobile implementation details (you are here)
  2. Implementing Android OAuth with AppAuth library
  3. Implementing iOS OAuth in 30 minutes

Сontent of this article:

OAuth and flow
How Authorization Code Flow with PKCE works
Intercepting auth by malicious app
Implementation details
How to open the login page:
→→ WebView
→→ Browser
→→ ChromeCustomTabs, SafariVC
Redirect doesn’t work in Chrome
Token refreshing
Missing browser
Logout
OAuth implementation options
Service SDK
Manual implementation
OAuth libraries

📱OAuth and flow

When it comes to authorization and authentication, concepts such as OAuth2 and OpenID are used. In this article I am not going to disclose them, on Medium there is already such material.

Below we are going to look at the details regarding mobile development. For our purposes, the differences between OAuth2 and OpenID are irrelevant, so we are going to use the overall term OAuth.

There are different flow in OAuth, but not all are suitable for use in the application:

  • Authorization Code Flow. Not suitable: the code can be intercepted by a malicious app.
  • Resource Owner Password Credentials Flow. It requires credentials to be entered inside the application. This is not desirable if the application and service are not developed by the same team.
  • Client Credentials Flow. Suitable for authorization of the client based on client_id, client_password. It does not require the user to enter credentials.
  • Implicit Flow. Unsafe and outdated.

📱How Authorization Code Flow with PKCE works

For mobile clients, we recommend using Authorization Code Flow with the addition: Authorization Code Flow with Proof Key for Code Exchange (PKCE). Using this particular flow is important for the user safely application login. Let’s consider its features.

This flow is based on the basic Authorization Code Flow. First, let’s check its implementation:

  1. The User clicks the Login button.
  2. The Mobile app creates a link for authorization on the Auth service and opens it in the browser.
  3. The User sees a screen with login/password fields.
  4. The User enters the login and the password and grants access to the data.
  5. The Auth service returns the authorization code to the Mobile app using a redirect. With the code, you won’t be able to get access to the required resources from the App service yet. In order for the redirect to be intercepted only by the application, custom schemes are usually used, not http(s). Otherwise, the code can also be intercepted by the browser. In this case, a disambiguation dialog appears.
  6. The Mobile app retrieves the code from the redirect URL and exchanges the code for a token. Additionally, client_id and client_secret can be passed.
  7. The Auth service returns access_token, refresh_token.
  8. The Mobile app uses the received token to communicate with the App service.

When using Authorization Code Flow with PKCE, the scheme changes slightly. Differences are highlighted.

  1. The User clicks the login button.
  2. Code_verifier and code_challenge are generated and saved in the app. The generation process is described in RFC-7636.
    code_challenge is derived from code_verifier, reverse transformation is not possible.
  3. The Mobile app creates an authorization link based on the generated code_challenge. The link is opened in the browser. At this point, the Auth service saves the code_challenge for the session. code_verifier remains only in the Mobile app memory and is not transmitted over the network.
  4. The User sees a screen with login/password fields.
  5. The User enters the login and the password and grants access to the data.
  6. The Auth service returns the authorization code to the Mobile app using a redirect. Note that code_challenge is not returned from the server with the code. Only the Auth service and the Mobile app know about it.
  7. The Mobile app exchanges the code for a token. When exchanging, the Mobile application sends the code_verifier that was saved in step 2.
  8. The Auth service accepts code_verifier from the Mobile app. It derives the code_challenge from code_verifier and compares it with the code_challenge saved in step 3. If they match, the token is returned.
  9. The Auth service returns access_token, refresh_token.
  10. The Mobile app uses the received token to communicate with the App service.

What would happen if code_verifier and code_challenge were not used?

📱Intercepting auth by malicious app

One of the OAuth implementations is using an external browser.

In this case, the code from Auth service is returned to the Mobile app using the system function: when a redirect to the URL inside the browser occurs, your Mobile app is opened if the app can handle the URL.

At the moment when the system is looking for an application to process the redirect URL, it is possible to intercept the redirect by a malicious application. An attacker can create an app that intercepts redirects like your app. All redirect data is leaked.

Intercepting redirects by malicious app

That’s why you need to return an intermediate code in the redirect, not a token. Otherwise, the token will be available to malicious app.

When using the basic Authorization Code Flow, the malicious app can potentially get the code and exchange it for a token, similar to how it is done by your app (Real app). But using code_verifier and code_challenge makes malicious interception meaningless. Malicious app doesn’t know the code_verifier and code_challenge that were generated inside your app, and they aren’t returned in the redirect.

Without this data, the malicious application will not be able to exchange the code for a token.

Note that such an attack will not work if you use universal links (on ios) and applink (on android). To open a redirect link in the app, you need to put a json file with your app’s signature to the server.

But often we can’t add a json file to the server if we are using an external service. That’s why it can help not always.

📱 Implementation details 🔍

How to open the login page?

The OAuth login page is a web page. There are the following ways to open it:

  • WebView inside your application.
  • An external browser.
  • ChromeCustomTabs, SafariVC.

When choosing a method, keep in mind that the main task of OAuth is to provide access without entering credentials inside the application process.

1️⃣ WebView 🏜

👍 Advantages:

  • You can customize the ui of the screen completely as you need.
  • The screen with WebView may be opened faster than the page in the browser: webview works inside your application process, without interprocess interaction. But in Android O webview rendering works in separate process.

👎 Disadvantages:

  • WebView implementation is not secure in general, and some social networks, like Google, do not allow this way of implementing OAuth. In practice, it is possible to hack this by replacing the user agent. But that doesn’t correspond to Google policy, and you can’t do that.
  • The general problem is that WebView works within the application. The creator of a malicious application can inject between the user and the service in which the user logs in and intercept the password and the login. One of the goals of the OAuth protocol is to counter this.
  • WebView executes JS in the process of your application, which is not safe for the application itself. If you are using WebView inside your app, I recommend that you read the setup tips for added security.
  • WebView decreases UX. The user may have already been authorized in the browser, but WebView will not know about this, since WebView and the browser have splitted cookie storages.

Due to the disadvantages, WebView is not acceptable option for implementing OAuth in a mobile application.

2️⃣ Browser 🌐

The second option is to open the page in an external browser installed on the device.

👍 Advantages:

  • Opening a page in the browser is very easy.
  • Your app has no control over your browser or opened webpage. This provides additional security for the user.
  • The browser saves the user’s cookies. This means that if the user was already logged in to the service inside the browser, he doesn’t have to re-enter credentials on OAuth.

👎 Disadvantages:

  • Opening the browser is a heavy operation because we need to start an external process.
  • You cannot configure the browser UI, it opens in an external window.
  • When you open the browser, you leave the navigation stack of the app.

Browser is an acceptable option for implementing OAuth in a mobile application but not the best.

3️⃣ ChromeCustomTabs, SafariVC 📊

ChromeCustomTabs (CCT) and SafariViewController (SafariVC), like the browser, make it easy to open web pages in your app.

👍 It eliminates drawbacks of WebView:

  • The attacker will not be able to intercept the data entered on the login page.
  • Data is available to the browser and CCT/SafariVC. Because cookie storage is same.
  • Note: starting with ios 11, data between browsers and different SafariVC sessions is no longer automatically shared. To implement this, you need to use ASWebAuthenticationSession.
    Example: GitHub Gist.
  • JS is executed in an external process, this will secure your application.

👍 The browser’s drawbacks are partially eliminated:

  • CCT allows you to warm up the background, which allows you to quickly load the page when it is opening.
  • An opened CCT does not reduce the priority of your application’s process because it may lead to process kill by the OS.

There are limiter options for customizing the appearance: CCT, SafariVC.

CCT was originally made only for Chrome. Now it is supported in different browsers. In addition to it, there is also TrustedWebActivity in Android. You can read more about them on the official page.

This is the best approach for opening an OAuth page. It eliminates almost all the drawbacks of the previous two approaches.

🤷‍♂️ Redirect doesn’t work in Chrome

As mentioned above, it is better to use a URI with custom scheme to redirect back to the app, so that the redirect is not intercepted by browsers.

While testing the implementation of OAuth in Android, we encountered that CCT with Chrome browser after successful authorization, did not redirect user into the app on some devices. There’s a bug in the tracker for this.

The reason is simple. An update was made in Chrome browser that prevents you from following URL with custom scheme without user intent. This behavior blocks the user from getting into a malicious application.

To bypass this restriction, we made the web page that the browser redirects to after successful authorization. The webpage automatically tries to make a redirect inside the app. If this doesn’t happen, and Chrome has blocked the redirect, the user can click the enter button and go explicitly. Then Chrome does not block redirect because clicking is user intent. That approach works.

🥬 Token refreshing

With OAuth you need to remember about token refreshing.

This is usually similar to how to change a code to a access_token. You are requesting API service to get a token and specifying grant_type=refresh_token and refresh_token, which you received initially when logging in.

We are going to discuss implementation details in the example below.

⭕️ Browser is missing

Android, unlike iOS, may not have an installed browser. But if we are using CCT, we will need to make sure that the user has installed the browser with CCT protocol implementation.

In addition to Chrome, this feature is supported in SBrowser, Firefox, and all other modern browsers. But even if the user doesn’t have one, a regular browser opens.

Developing page shows how to check browsers with CCT support.

🚪 Logout

In application cases without OAuth, you need to clear tokens / cache files / databases when a user logouts.

If you use CCT/SafatiVC for OAuth, then the browser saves cookies of the authorized person. When you log in again, you will be automatically logged in to your first account again. It is not possible to clear cookies from the app directly, because the browser works inside a separate process with its own cookie storage. And access to it is prohibited from other apps.

🔅 OAuth implementation options 🔆

We checked OAuth flow for mobile apps and implementation details. Next step — select implementation option.

There are several options:

  • Service SDK
  • Manual implementation
  • OAuth libraries

🛎 Service SDK

Implementing OAuth logic with SDK dependency. E. g. you need FB OAuth and use Facebook SDK

👍 Pros:

  • simple implementation;
  • authorization via native apps is possible if they are installed. E.g. login through FB application.

👎 Cons:

  • increasing external dependencies count, especially with a large number of external OAuth services;
  • there is no implementation control, if you will want to change something — you can’t.

We are not going to consider using SDK in the current article, because this requires the SDK documentation research.

✍️ Manual implementation

Implementing OAuth logic manually within your own application using WebView or other implementations (CCT/SafariVC).

👍 Pros:

  • you get full implementation control

👎 Cons:

  • you have to write your own code, maintain it and take into account manually the nuances discussed above.

We are not going to consider manual implementation, because it is individual for each application and service. It option may be justified in complex mobile applications with large codebase and custom architecture.

📚OAuth libraries

There are many open source libraries for mobile OAuth.

Libraries should support the OAuth and OpenId protocols and allow communication with any services.

Examples:

  • AppAuth IOS
  • AppAuth Android
  • Auth0 Android
  • When using this approach, you need to make sure that the authentication server is functioning according to the OAuth protocol, and you don’t have to hack the library to link it.
  • If you understand the library and know how it works, the OAuth implementation is quite simple. But it takes time.
  • The authorization implementation will be universal for different services, you do not have to connect additional dependencies and write a lot of code for each external service.
  • Note that the implementation of the library may not be completely convenient for using in your application. The approaches used to communicate with the library may differ from those adopted in your team, and you will need to write wrappers and bridges. Example: AppAuth library in Android uses AsyncTask, but in your app you use coroutines. But usually it is not problem.

In the following part, we are going to discuss the OAuth implementation using the AppAuth library. There are several reasons for this:

it has both Android and iOS implementations.

In the next chapter of article we will correctly implement OAuth in Android & iOS. Stay tuned!

--

--