Search code examples
androidiosmobileoauth

Implement OAuth 2.0 authorization against a 3rd party service for a mobile app


I need to integrate a 3rd-party web service into a mobile app. The web service supports OAuth 2.0.

The other answers on the site suggest using the Authorization Code Flow with PKCE or the Implicit Flow. Neither would work in my case, because 1) the Implicit Flow does not support refresh tokens, and 2) the 3rd-party web service does not support PKCE.

My current approach involves having the app open a parameterless URL on my server in a browser (e.g. https://server.me/3rdparty/authorize), which invokes a standard Authorization Code Flow against the 3rd party service. When the redirect arrives from the 3rd party service to my server, I invoke the token endpoint of the 3rd party service in the background and send the token back to the app by redirecting the browser to an app link (e.g. myapp://oauth/response?access_token=ABCDE&refresh_token=12345).

The only security problem that comes to my mind with this implementation is that the app could be impersonated by another app that registers the myapp:// prefix. Two possible solutions to this problem:

  • Use a domain-bound and verified Deep Link / Universal Link
  • Have the app generate a "state" parameter and pass it through the entire flow, and at the end, require the app to decrypt the token with the "state" parameter as a key.

Do you see any security problems with this approach?


Solution

  • PKCE is an optional extension to the authorisation code flow. It is not mandatory. It guards against Man-in-the-middle attacks, but this may be a low risk depending on your use case.

    You should use ASWebAuthenticationSession to open a secure browser in your app to complete the authentication flow. You provide an https callback url to the session and iOS ensures that only your app receives the response, even if other apps have registered the same callback url. It does not use insecure app url schemes.

    If the 3rd party service provides a web interface for user authentication, then you could open that interface directly in your app and receive the code response in your app, however your app would then need to hold the required secret to exchange the code for a token.

    The approach you have outlined, using your own server, is a more secure approach:

    • Open your server url (https://server.me/3rdparty/authorize) in an ASWebAuthenticationSession, providing some callback url, say https://server.me/mobile/authComplete
    • Your server redirects the the 3rd party auth web site, providing a call back url that points to your web server (say https://server.me/3rdparty/callback) and some random state.
    • When the response is received at https://server.me/3rdparty/callback you can verify the state and exchange the authorisation code for token(s) using secrets that it holds.
    • Your server then issues a redirect to https://server.me/mobile/authComplete with the token(s) in the query string.
    • Because the redirect url matches the url you provided to ASWebAuthenticationSession, the web session will be closed and the url will be provided to your completionHandler where you can extract the token(s)

    The advantage of this approach is that your mobile app doesn't need to know any secrets that could be accessed by an attacker.

    Addendum

    I noticed that you tagged Android as well. There will be a similar solution for Android, but I don't know what it is off the top of my head.