iOS App Logout via Universal Link Callback

Created: Modified: Knowledge Base

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

Introduction

Imprivata has created this standard 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, without prompts interrupting the automation.

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 briefly foreground, allowing an app’s native logout code to run.
  • Apps may clear login tokens, and also signal their back-end systems to close sessions, set user status to “offline,” etc.
  • Since all activity happens within the device, no credentials (e.g. API keys) need to be shared with Imprivata.
  • No dialog appears for the end-user.
  • This approach is independent of sign-on technology, and can be paired with simple username & password login, ASWebAuthentication, or other login mechanisms.

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 this 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 Imprivata GroundControl Locker wants to tell YourApp to logout, then have YourApp return control to Locker.

  1. First, Imprivata Locker will send a Universal Link to YourApp with a form like this:
              https://yourapp.yourcompany.com/logout
                        ?ulc-success=https://locker.groundctl.com/success
                        &ulc-error=https://locker.groundctl.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 YourApp to the foreground, without a user prompt.

  2. YourApp will parse the received link, and identify the “URL path” of /logout. Identifying this, YourApp 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.
  3. On successful completion, YourApp will call the Universal Link in the ulc-success query string: https://locker.groundctl.com/success. YourApp 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, YourApp will call the Universal Link in the ulc-error query string: https://locker.groundctl.com/error.With either message, iOS will bring Locker to the foreground, without a user prompt.
App Requirements

Inbound Universal Links: Your app will need to support inbound Universal Links. Please refer to Apple’s developer documentation for technical details. Requirements include:

Unlike common Universal Link usage in Apple’s examples, there is no requirement to host content on a web server. Also, there’s no need for a login from a web app.

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.groundctl.com/, for example https://locker.groundctl.com/lock, https://locker.groundctl.com/logout, etc..

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

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

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.

Outbound Universal Links: After handling logout, your app will need to call a Universal Link. This will return foreground to another app, and background your apps. The Universal Link you call will be the value of the &ulc-success parameter sent in the inbound link.

This function is documented in Apple’s documentation for open(_:options:completionHandler:). Targets responding to ULCs must use the option universalLinksOnly as this option allows ULCs to work even when Safari is hidden by MDM.

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: NOTE: This is a “gotcha” for many apps. Imprivata GroundControl will force-quit all apps just before sending a Universal Link. This is unfortunately a requirement in how GroundControl functions. To log out of your back-end systems you will need session information, but many apps retain session information in memory only. Force-quitting will lose the session info, preventing you from later logging out of your back-end when you receive the Universal Link Callback.

We recommend storing the session info in a place such as UserDefaults in order to survive the Force-quit.

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:

{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 that 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.groundctl.com/ulc-tester.