Native app guide

When creating a native app that should use OAuth for authorization, unique security considerations unlike those found in server-side clients are present.

By definition, native apps are not secure secret containers. Therefore, secrets stored in app source code or attached resource bundles, must be considered public domain if an attacker can get a hold of the binary, which is usually a straightforward process. This page details a few mitigation strategies that Telenor Digital strongly encourages in order to ensure clients are sufficiently secure to handle tokens with access to sensitive resources.

Most secure: Server-side (confidential client)

The safest approach for all apps is to create a server-side client which stores access tokens, refresh tokens, the client ID and the client secret. This way, the app is considered to be a "dumb" terminal. The only thing the app needs to store, is a user-specific session ID that it should use to indicate its identity.

Confidential client sign-in flow

Step-by-step authorization sequence

  1. The app creates and persists a state string, for instance using the UUID functionality provided in all major programming languages.
  2. The app opens up an external browser pointed at the /authorize endpoint, including its state string.
  3. The user is prompted to authenticate and authorize the client to access their resources.
  4. On completion of the authentication/authorization dialogs (success or failure), the authorization server responds to the browser request with a redirect directly to the app using a process called "deep linking", including the authorization code and state in the deep link URI if the authentication/authorization succeeded.
  5. The app extracts the "state" query parameter in the redirect URI and compares it with the state entry previously persisted.
  6. The app extracts the authorization code from the "code" query parameter in the redirect URI.
  7. The app sends the authorization code to the server-side client through for instance a REST call.
  8. The server-side client generates a unique session ID for the app.
  9. The server-side client trades the authorization code for an access token/refresh token pair using the /token endpoint in the authorization server.
  10. The server-side client stores the access token/refresh token pair along with the session ID in a secure database.
  11. The server-side client responds to the REST call with the session ID it stored.
  12. The app stores its session ID in the device's secure storage and uses it for all further client requests. The client can then look up the tokens belonging to this session ID and use the access token to retrieve resource server information.

Security

  • A session ID might be hijacked. Appropriate measures should be taken to protect it.
  • The app should contain some state indicating that it has started an authentication/authorization session, which should be deleted after the authorization code is received. If this is not done, an attacker can trick a user into clicking a link with a compromised authorization code afterwards, which results in a Session ID belonging to the attacker being used.
  • Use TLS/SSL (HTTPS) for all requests, including redirect URIs to ensure all secrets are transmitted in a confidential fashion.

Advantages

  • Potential phishing apps will have to communicate with the server-side client, which reduces the feasibility of such an attack if the server-side client API only exposes functionality present in the official app.
  • As the server-side client authenticates itself towards the authorization server and is able to keep the access/refresh tokens safe, the client is permitted to request high-risk scope values.
  • If the access tokens are used towards resource servers with sensitive data, the resource servers can trust that requests with tokens originate from a well-behaved server-side client.

Disadvantages

  • The service provider must implement and maintain a server-side client or a cluster of such clients, which needs to be scalable with number of installations of the app.

Simplest: Pure native app (public client)

The simplest approach (and the cheapest, from the perspective of an app developer) is to embed all the authorization logic within the app.

Public client sign-in flow

Step-by-step authorization sequence

  1. The app creates and persists a state string, for instance using the UUID functionality provided in all major programming languages.
  2. The app opens up an external browser pointed at the /authorize endpoint, including its state string.
  3. The user is prompted to authenticate and authorize the client to access their resources.
  4. On completion of the authentication/authorization dialogs (success or failure), the authorization server responds to the browser request with a redirect directly to the app using a process called "deep linking", including the authorization code and state in the deep link URI if the authentication/authorization succeeded.
  5. The app extracts the "state" query parameter in the redirect URI and compares it with the state entry previously persisted.
  6. The app extracts the authorization code from the "code" query parameter in the redirect URI.
  7. The app trades the authorization code for an access token/refresh token pair using the token endpoint in the authorization server.
  8. The app stores its tokens in the device's secure storage and uses it for all further resource server requests.

Advantages

  • No server-side client to maintain and scale.
  • Overall simpler to implement.

Disadvantages

  • Risk of phishing apps appearing using the client ID of the public client.
  • Because the client is public, it cannot ask for high-risk scope values such as changing or adding phone numbers and email addresses. This is a security measure to avoid issuance of powerful tokens to malicious software which is necessary since public clients cannot be authenticated reliably.
  • Authorization logic in app - More in-app complexity means higher risk of bugs - It takes a long time to ensure app is updated on all user devices.

Android and iOS SDKs

For Android and iOS there are SDKs available which handle the most common tasks for the developer. This includes signing in the user, and keeping track of the tokens. Code and documentation is shared on Github. Using an SDK will significantly speed up development time and reduce complexity.

Features

  • User authentication and authorization through a secure web flow
  • Obtaining access and refresh tokens
  • Implicitly or explicitly refreshing tokens
  • Revoking tokens
  • Permanent secure storage

https://github.com/telenordigital/connect-android-sdk

https://github.com/telenordigital/connect-ios-sdk

Deep linking

The process of deep linking is supported on all major mobile platforms and is a technique where a web browser redirect or a link can point to a local app directly.

It works by having the app register a custom URI with the device OS on app install. After this is done, all URIs pointing to this URI will open the app instead of starting a browser.

NOTE: If other apps have registered a similar URI, the user will be prompted by the OS on which one to open. Therefore, it is recommended to choose a URI that is unique to the app. For instance: Common browser apps subscribe to all requests to URIs beginning with http:, https:, ftp:, and so on.

Android: Enabling Deep Links for App Content

Apple: Inter-App Communication