iOS App Logout via Universal Link Callback

This page is intended for iOS software developers and is a companion to About Password AutoFill.

Introduction

Imprivata proposes building x-callback-url on top of Apple’s standard Universal Links. Implemented properly, this will enable a standard and centralized logout functionality for shared devices.

About Universal Links: You can connect to content deep inside your app with universal links. Users open your app in a specified context, allowing them to accomplish their goals efficiently. When users tap or click a universal link, the system redirects the link directly to your app without routing through Safari or your website. — developer.apple.com.

About x-callback-url: The goal of the x-callback-url specification was to provide a standardized means for iOS developers to expose and document the methods they make available to other apps. Using x-callback-url’s source apps can launch other apps passing data and context information, and also provide parameters instructing the target app to return data and control back to the source app after executing an action. Specific supported actions were dependent on the individual apps and were not discussed in the specification. — x-callback-url.com.

Benefits of Universal Link Callbacks

  • Apps will foreground during the process, allowing your own native logout code to run.

  • This approach enables more than “forgetting the user.” Apps may signal their back-end systems to disable push notifications, set a user to “offline”, etc.

  • No credentials need to be shared.

  • No data is shared between the apps in the transaction.

  • No dialog appears for the end-user.

  • This approach works with any single sign-on technology, as well as without any SSO.

Universal Links are not Interapp URLs, also known as Custom URI Schemes.

  • Universal Links always begin with https://. Interapp URLs begin with a unique URI scheme such as myappname://.

  • Interapp URLs will prompt users: “AppA wants to open AppB.” Universal Links show no prompt, so they do not interrupt automated workflows.

  • Universal Links are secured with an Apple App Site Association file. Interapp URLs are not secure and are subject to spoofing attacks.

We have focused discussion of Universal Link Callbacks on a process to log out of apps. But the ULC pattern could be extended for other uses as well. Such extended use is beyond the scope of this document.

The ULC Process

A Universal Link Callback (ULC) is used if AppA wants to tell AppB to logout, then have AppB return control to AppA.

  1. First, AppA will send a Universal Link to AppB with a form like this:

    Copy
    https://appb.companyb.com/logout
                        ?ulc-success=https://appa.com/success
                        &ulc-error=https://appa.com/error
    NOTE:

    The parameters ulc-success and ulc-error are URL Encoded in practice, but shown here unencoded for legibility.

    iOS will then bring AppB to the foreground, without a user prompt.

  2. AppB will parse the received link, and identify the “URL path” of /logout. Identifying this, AppB will execute whatever code it needs to log out: purging any cached data, messaging its back-end server to close a session, and/or clearing a local UserDefaults cache of the logged in user.

    On successful completion, AppB will call the Universal Link in the ulc-success query string: https://appa.com/success. AppB will assume this is a universal link, in order to be sure to call an app, and not open a web page.If there is an error, AppB will call the Universal Link in the ulc-error query string: https://appa.com/error.With either message, iOS will bring AppA to the foreground, without a user prompt.

  3. AppA will parse the received link, and know whether the operation was a success or failure.

App Requirements

Inbound Universal Links: Your app will need to support inbound Universal Links. See Apple’s developer documentation for technical details. Associated requirements include an Associated Domains Entitlement within each app, and an Apple App Site Association file on a company-controlled web server. If your company publishes multiple apps, one Apple App Site Association files can may be used to serve all apps.

Unlike common Universal Link usage, there is no requirement to host content on a web server. We recognize that much of the data served by apps is proprietary and often regulated. Instead, we’ll understand the URLs to be commands from one app to the other.

Here is an example AASA file, from our own Locker app. The file tells iOS that the Locker app will handle every request prefixed with https://locker.imprivata.com/, for example https://locker.imprivata.com/lock, https://locker.imprivata.com/logout, etc.

https://locker.imprivata.com/.well-known/apple-app-site-association

Copy
{
  "applinks": {
      "details": [
           {
             "appID": "Y3692ZXX5N.com.imprivata.b2b.locker",
             "components": [
               {
                  "/": "*"
               }
             ]
           }
       ]
   }
}

Outbound Universal Links: Your app will also need to call a Universal Link. This function is documented in Apple’s documentation for open(_:options:completionHandler:). Targets responding to ULCs should NOT use the option universalLinksOnly, because the source app may be a web app.

Full Logout: The definition of “Log out” is up to each app. This could mean purging any cached data, messaging your back-end server to close a session, and/or clearing a local UserDefaults cache of the logged in user. ULCs provide your app the opportunity to use all resources available to fully log out of your systems.

No Interactivity: Your app likely already has a UI element to log out. Logging out through Universal Link Callbacks additionally requires there is no user interaction during its process. You may use an “Are you sure?” prompt during interactive logout, but interactive prompts are prohibited during the ULC flow.

Force-Quit: Due to the nature of iOS’s App Lock, some logout mechanisms may force-quit your app before the Universal Link is called. Your app must be able to process the ULC even if it was immediately force-quit before receiving the message. You may want to delay processing of Universal Links until after you app’s normal startup routine. Be careful if clearing authentication credentials if force-quit. You may need those credentials in a logout routine.

Short Timing: Your app’s logout process should take no longer than 20 seconds. If it takes longer, the initiating logout system may decide your app stalled. If this happens, the initiating logout system may send the ULC again, or may perform more drastic measures including erasing the phone.

Specification

We will define a Universal Link Callback as follows:

Copy
{appLogoutAction}?ulc-success={successUrl}&ulc-error={errorURL}

The presence of the query string parameter ulc-success= in a Universal Link identifies the link as a Universal Link Callback.

{appLogoutAction} is an Apple Universal Link. As such, it must begin with https://.

Every app may define its own form for {appLogoutAction}. Possible values include:

  • https://appb.company.com/logout

  • https://appb.company.com/signout

  • https://appb.company.com/actions/logout

  • https://appb.company.com/actions/logout?force=1

NOTE:

The hostname portion of this value (“appb.company.com”) must be embedded in the app as the Associated Domains Entitlement. The hostname must also match to an Apple App Site Association File. If multiple apps share the same AASA, then you may use paths (“/actions”) to differentiate apps.

You will share this {appLogoutAction} with Imprivata to enable ULCs.

The {appLogoutAction} should be identical for every user and every device. Individualized URL parameters are not supported. Per-organization configurations may be supported; contact Imprivata to discuss.

{successUrl} and {errorURL} are URL-encoded Universal Links. For example:

  • https%3A%2F%2Fappa.com%2Fsuccess

These are provided by the app initiating the logout. Your app will not know these URLs in advance, and should make no assumptions about them, other than assuming they are proper Universal Links. The URLs may change from time to time, or with every use. Your app’s job is to open the provided success or error Universal Link after you complete your own logout actions.

Use {successUrl} if you were able to log out the user. Also use {successUrl} if no user was logged in, and your app took no action.

Use {errorURL} if your logout encountered an unrecoverable error, but use it sparingly. If a retry may result in a successful logout, your app should attempt the retry before calling {errorURL}. If your app calls {errorURL}, any of the following may happen:

  • The error may be logged

  • The calling app may attempt the ULC again

  • The device may be removed from service until checked by IT

  • The device may be automatically erased and set up again

Validation

Imprivata is has developed a validation tool at https://apps.imprivata.com/ulc-tester.