How to federate identities in mobile apps

Enabling social logins in mobile apps makes it easier for users to sign in, share their profile information and preferences. When done well this can greatly improve the conversion rate of your application.

All sign-in paths must lead to a single token

The integration of user identities from external providers, such as Google or Facebook, is called federation. Regardless of which path your users choose to sign in, via a local account / credentials, or via an external IdP, the aim at the end is to arrive at one or more tokens that are issued by your own Connect2id server and which all apps and services in your domain can understand.

  • ID token -- A standard OpenID token which conveys the identity of the logged in user, and provides a singular identifier for the user, regardless of where they came from. This is called identity correlation. The ID token can also include other information, such as the strength of the authentication level, the original IdP (Google, Facebook, etc) and selected user attributes (called claims).

  • Access token -- An OAuth 2.0 token to let the application access user profile information (which may have been sourced from an external IdP) as well as other protected resources (web APIs) in your domain.

  • Refresh token -- A special OAuth 2.0 token used to obtain a new access token when the current has expired (optional).

Login with local credentials

Before we delve into external IdP integration, let's see how simple sign-in with local credentials is handled. That's done with the standard OAuth 2.0 password grant, where the user enters their name and password into the mobile app, and then the app submits the credentials to the Connect2id server to obtain an access / ID / refresh token.

Example password grant request:

POST /token HTTP/1.1
Host: server.c2id.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=alice&password=secret

Example response with an access and refresh token only:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token"  : "2YotnFZFEjr1zCsicMWpAA",
  "token_type"    : "Bearer",
  "expires_in"    : 3600,
  "refresh_token" : "tGzv3JOkF0XG5Qx2TlKWIA",
  "scope"         : "read write"
}

The Connect2id server comes with several available handlers for the password grant, and allows precise control of which token types to return to the client, as well as their parameters.

The basics of sign-in with an external IdP for mobile apps

Authenticating users with an external IdP is facilitated by sending the user to a web page or app of the IdP, where the user can submit their credentials in a secure manner. Upon success the user is directed back to the requesting client with a protocol specific object (code, access token, OpenID token) which the client can use to obtain the actual user identity.

The popular social login providers provide ready SDKs for that, and employing them can be as simple as creating a login button for the IdP with the appropriate link, and then defining in-app callbacks for success and error.

Links to some of those SDKs:

The login flow can involve the IdP's app, or the browser:

  • Sign-in via the IdP's own app is typically perceived as the most fluent user experience, since the user is, as a rule, always logged in with the app.

  • If the IdP's own app is not installed on the device, the SDK will fall back to opening the IdP's sign-in page in the system browser. If the browser doesn't have an active session (cookie) with the IdP, the user will be prompted to enter their credentials. That, and the relative performance of web apps on a poor internet connection, typically makes the UX of signing in via the browser less desirable.

You have a mobile app with a backend. How to integrate an external IdP securely?

Validating the tokens securely

With apps that utilise a backend, the protocol specific object (e.g. token) that is used to obtain or assert the user's identity must be processed by the backend. If that isn't observed, the backend cannot be sure that the signed-in user is who they claim to be, and may become vulnerable to rogue mobile clients aiming to impersonate arbitrary users. Don't do that!

So how should you proceed?

Create a simple (micro)service on your backend which job is to validate the tokens issued by the external IdP. Remember, this validation must not take place in the mobile client!

  • OpenID Connect -- For an IdP that speaks OpenID Connect that token will be an ID token, which encodes the user's identity in a JSON object that is digital signed. Let your backend service validate the digital signature of the ID token.

  • OAuth access token -- For an "old-style" IdP that only issues an access token to obtain the user's identity and profile information from some endpoint, simply make the required HTTPS call with the supplied access token. Then record the reported user ID (and other profile information).

Obtaining universal tokens for your domain

Once you know the user's identity, and have correlated that to a local identifier for the user, make a call to the protected direct authorisation endpoint of the Connect2id server to obtain the required tokens that the apps and web services in your own domain understand.

Example request to obtain an access token for the domain managed by the Connect2id server, with scopes myapp:read and myapp:write (intended for some web API):

POST direct-authz/rest/v2 HTTP/1.1
Host: server.c2id.com
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6
Content-Type: application/json

{
  "sub"       : "alice",
  "client_id" : "8cc2043",
  "scope"     : [ "myapp:read", "myapp:write" ]
}

The direct authZ endpoint can also issue an ID and / or refresh token if requested, and supports a number of optional parameters.

Example response with the access token, which the backend service can then relay back to the mobile app:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "access_token"  : "b15b843981cf",
  "token_type"    : "Bearer",
  "expires_in"    : 3600,
  "scope"         : "myapp:read myapp:write"
}

Intercepting the tokens from the mobile app SDK

How do you intercept the returned tokens from the IdP in your mobile app?

All vendor SDKs normally provide a callback or method for that.

Facebook's SDK for instance allows that via its AccessTokenTracker.