Table of Contents

Approov Reference Guide

Getting Started With Approov

This documentation provides a detailed reference manual for using Approov. If you are new to Approov then you will find it much easier to start with the Quickstart Integrations for the frontend and backend. You can then return to this manual as needed for detailed usage guidance.

Once you have installed the Approov CLI Tool there are a few more steps to get your Approov integrated app running:

  1. Familiarize yourself with the Approov Architecture
  2. Understand Account Access Roles in the Approov CLI
  3. Add the API domain(s) to be protected by Approov
  4. Build your app and register it with the Approov cloud service
  5. If you are using API Protection then modify your API backend to verify that valid API tokens are present. If you are using Runtime Secrets Protection then setup secure strings to migrate your existing secrets to be managed with Approov.

If you have technical support enquiries then please use support@approov.io. Note that if you have a paid plan then you can use the Approov CLI command approov support to get emergency contact information. This will allow you to contact our 24 hour support for critical production issues.

You can reach your subscription portal at https://approov.chargebeeportal.com. You will have received login details when you converted to a paid plan. The portal allows you to change your subscription plan, update your payment details, terminate your subscription, etc. For further sales-related enquiries please contact sales@approov.io

Note that when your account was first created the initial rejection policy will have been selected. This policy relaxes some aspects of the Approov protection. We suggest you review the available rejection policies to determine if there is one better suited to your needs. At minimum you should consider changing your rejection policy to default rather than initial.

Exploring Other Approov Features

Some other Approov features you might want to try are:

  • Update your Security Policy to change the conditions under which an app will be given a valid Approov token.
  • Learn how to Manage Devices to apply custom policies to specific devices (useful for enabling debug on your development devices).
  • Consider the use of Approov Runtime Secrets protection using Secure Strings to provide protection at rest, as well as in transit, for any remaining app secrets.
  • Learn how to Manage Key Sets to managing additional keys for signing or encrypting Approov tokens, and to allow access to a wide range of JWT algorithms beyond the default HS256 signing method.
  • Understand User Management so you can add and remove access for others to your Approov account.
  • Employ Automated Approov CLI Usage to enable integration of Approov with Continuous Integration (CI) systems.
  • Use the Metrics Graphs to see live and accumulated metrics of devices using your account and any reasons for devices being rejected and not being provided with valid Approov tokens. You can also see your billing usage which is based on the total number of unique devices using your account each month.
  • Use Service Monitoring emails to receive monthly (or daily) summaries of your Approov usage. You can also manage the API domains to be continuously monitored to ensure they are accessible and that the pins match those added to your account.
  • Investigate advanced features, such as Token Binding, Apple DeviceCheck Integration, Apple AppAttest Integration, Google SafetyNet Integration, Device Filters, Message Signing, Custom JWTs and Android Automated Launch Detection.
  • Add support for calling Approov protected APIs using Web Protection Integration, using one of the supported 3rd party services FingerprintJS, Google reCAPTCHA or hCaptcha.

Account Access Roles

When you initialize access to your Approov account through the CLI a number of different access roles may have been installed. Typically these will have been dev and admin. The dev role is automatically made active on installation.

Most operations can be carried out using the dev role, but certain more security sensitive operations are reserved so that they can only be executed when you have assumed an admin role. To assume the admin role you can type:

$ eval `approov role admin`

When you issue the next approov CLI command you may be invited to provide the password. You should only assume the admin role for the period that you need it and then you should assume the dev role again. Note that on Windows you must use the form set APPROOV_ROLE=admin:your-account where your-account is the name of your Approov account.

To see a list of all the roles available use:

$ approov role
available role selection commands for account your-account:
  eval `approov role admin`
  eval `approov role dev`
  approov role .

This lists all of the user roles you have installed on your machine, and the command required to assume that role. The command you actually need to issue is eval which evaluates the return from the approov role command itself. This is a string for exporting the APPROOV_ROLE environment variable, which selects the active role. This ensures that each individual shell, which can have a different APPROOV_ROLE values, may have a different role selected. This prevents any unwanted interaction between terminal shells when you select a different role as the selection is only for the current shell. Any newly created shell will default to using the dev role, if that is available.

Note that on the Windows platform the role commands look slightly different, such as the following:

$ approov role
available role selection commands for account your-account:
  set APPROOV_ROLE=admin:your-account
  set APPROOV_ROLE=dev:your-account
  approov role .

Thus you must issue these set commands directly to change the current role.

User role sessions are controlled by the Approov cloud. This means that if you have initialized the same access on multiple machines, operations that end a session on one machine will impact all other machines using the same user roles.

If you explicitly select a role again, after you have provided a password, then this ensures that the session is refreshed to be a full hour long. You can use this if you wish to perform some scripted operations using the Approov CLI and you do not want the session to time out during this time. You can use the form approov role . to extend the session for the currently active role without have to explicitly select it.

It is possible to see which role is selected at any time as follows:

$ approov whoami
admin: https://admin-something.approovr.io
configuration: /home/you/.approov
account: your-account
role: dev
ID: dev-1016
name: your name
email: you@your.domain
expiry: 2020-12-04 14:00:30

The shows both the role and account, as well as other relevant information.

Note also that it is also possible to initialize access to multiple different Approov accounts, e.g.:

$ approov role
available role selection commands:
  eval `approov role admin your-account`
  eval `approov role dev your-account`
  eval `approov role dev your-other-account`
  approov role .

In this case an additional parameter is always required to specify the account as well as the role required.

If the access provided expires or is revoked then the role will remain on your machine but you will no longer be able to use it. If you execute an approov init with revised access then that will replace any expired or revoked user role. You can remove all current roles using the approov init remove-all command, but then you will need to reinitialize access via the access recovery flow.

Passwords

Password protection improves your security posture and dramatically reduces the risk of your account being compromised. Approov access information is held in the .approov configuration in your home directory and this will only have access permissions for your user identity. However, if your machine account is compromised then so could access to your Approov account. This could allow an attacker to generate valid Approov tokens or prevent your apps from doing so. Password protection of Approov user roles prevents this. Sessions time out after a maximum of one hour and after this time the password is required again for access. The password itself is never stored by the Approov CLI on your machine.

Communication between the Approov CLI and the Approov cloud service is always conducted using TLS, but its security is subject to the certificate trust store installed on your local machine. Ordinarily if this were to be compromised then it would be possible for a Man-in-the-Middle (MITM) attacker to intercept, modify and then spoof requests to the Approov cloud service. The password mechanism also provides protection from such compromises, as it provides an additional level of message integrity over and above TLS. It employs asymmetrically encrypted integrity tokens with a proof of password possession protocol to transmit this information, ensuring that an attacker cannot spoof these integrity tokens without knowledge of the password.

If a CLI command is issued that uses a password protected role, then the user will be invited to provide the password before they can continue. Once the password is correctly entered this initiates an active session that lasts for one hour. During that time it is not necessary to enter the password again in order to issue CLI commands. The current session information is stored in a .approov file in your home directory.

Different users should not share user roles, you should add new user roles as required, allowing each user to set their own passwords.

If you wish to reset the password for a user role then first select the role. Then use the following command:

approov password -sendCode
password reset code for dev role in account your-account sent to you@your.domain
use the command "approov password -setWithCode <emailed-code>" to set the password

This sends the reset information to the email associated with the user role. The email provides a long base64url encoded reset code string that is valid for at least 30 minutes. This long code is actually used to encrypt the new password information sent to the Approov cloud. This ensures that no MITM can possibly intercept the password information, or set their own passwords, without access to the code in the email.

You can then set the password as follows (use the code received in your email, not the one listed below):

$ approov password -setWithCode Gbf4erRmu3lrWAGAIW60kMXlkSYK1jJmtqRicMFAZCg
setting password for dev role in account your-account
enter password:
confirm password:
new password set for dev role in account your-account

You will be asked to enter a password (of at least six characters) and then re-enter for confirmation. It is not echoed to the terminal.

After a password has been set, you will be asked to enter it the next time you assume the role, or when the session has timed out with the role active and you issue another command.

Note it is also possible, although not recommended, to remove the need to use a password for a paricular user role. Go through the procedure of obtaining a reset code and then:

$ approov password -clearWithCode Gbf4erRmu3lrWAGAIW60kMXlkSYK1jJmtqRicMFAZCg
WARNING: we recommend that you protect your access using passwords
ATTENTION: If you wish to continue then please type YES and return: YES
password cleared for dev role in account your-account

It may take up to 30 seconds for the new password state to be fully updated.

Installing on Another Machine

If your onboarding email code has not expired then you can easily initialize the Approov CLI on another machine using the normal flow.

If the onboarding email has expired then you can obtain a new one by resending an onboarding email, assuming you have admin role permissions. If you don’t have these permissions then you will to ask somebody in the team who has those permissions to do this for you.

Account Access Recovery

If all admin level access to your Approov account is somehow lost, then you will need to use the recovery flow. This will send a new onboarding email to your email address with a refreshed onboarding code allowing you to run approov init again.

If somebody else in your team still has admin role access to the Approov account then they can simply resend an onboarding email to enable you to initialize the Approov CLI.

For security reasons, you must have a record of the recovery PIN that was provided during the original initialization. This is to prevent an attacker gaining access to your Approov account if they are able to gain access to your email account. If you do not have this PIN number then you will need to contact Approov support. Note that if you upgraded your access from an earlier version of Approov with a management token then you won’t have been issued with a PIN, but in that case you can just import the management token again.

The recovery command is similar to the original onboarding command in your original onboarding email, but with an email address used instead of an onboarding code. The command will be similar to the following:

$ approov init your-account you@your.domain
you must provide the recovery PIN that you were given when you first initialized Approov access for this account
enter PIN and return: 123456
onboarding email for account your-account to you@your.domain will be sent if this combination is valid (wait 5 minutes before retrying)

You must specify the account name and the email address to which the access was issued. You will also be asked for the recovery PIN. If all this information is correct then you will receive an Approov Onboarding email. This email will only ever be sent to the address to which the role was assigned. Thus you can’t use this to recover access if your email address has changed.

For security reasons, no indication is given if the provided information is incorrect. The command will just silently fail. Note that, if you think some of the information is incorrect on one attempt, you must wait 5 minutes before retrying due to the protections in place agaist the brute forcing of the PIN value.

Migrating to Account Access Roles

If you signed up to use an earlier version of Approov then you will have been issued with management tokens, rather than an onboarding code. This will have been set in an APPROOV_MANAGEMENT_TOKEN environment variable. It is possible to import your existing management tokens to use the new role based approach as follows:

$ approov init your-dev.tok
imported management token dev-6805 for account your-account
available role selection commands for account your-account:
  eval `approov role dev`

This imports the management token saved in the file your-dev.tok. You should now remove the environment variable APPROOV_MANAGEMENT_TOKEN.

You will probably also want to import your your-admin.tok management token as well.

Importing existing management tokens doesn’t add a password for them. However, you can do this with the approov password -sendCode command when the appropriate role is selected. See Passwords.

Approov Architecture

This describes the overall architecture of Approov and familiarizes you with the key concepts required to understand the steps in the Approov integration.

Key Components

The key components of Approov are detailed in the following diagram:

Overall Architecture

The steps required to obtain an Approov token are as follows:

  1. You will be able to administer the properties of your account using the approov command line tool and Approov account access you were issued upon sign up. A key aspect of this administration is the registration of new apps that are to be released to the app store. The approov tool analyzes the app (in either .apk, .aab or .ipa format) and adds its signature to a database in the Approov cloud service for your account. The particular build of the app then becomes recognized as being official, allowing valid Approov tokens to be generated for calls from that app.
  2. The integrity check process requires the SDK and the Approov cloud service to work together. The process is initiated when you make an API call that requires an Approov token to be added. The SDK analyzes the runtime environment of the app and the authenticity of the app that is being measured. These checks are implemented in hardened code and communications are protected both by TLS and also by a secondary level of request integrity signing. The Approov cloud service performs analysis on the data provided by the SDK and makes a decision based on this and the security policy criteria you set for your account. If the criteria are met then the Approov cloud provides a short lived token signed with a symmetric secret allocated randomly during your account sign up. If the criteria are not met then a token is still issued, but it is not signed with the correct secret. Options are also available to use other secrets or other signing algorithms, including those with asymmetric keys.
  3. The obtained Approov token should be transmitted with a backend API request. This is typically done automatically using on of our Quickstart Frontend Integrations. Typically the token is added as the additional header Approov-Token, but the approach can be customized. It is important that all communications made by these APIs are pinned so that no Man-in-the-Middle (MitM) interception is possible that could make a copy of the short lived token. Pinning TLS connections is good security hygiene anyway, as it prevents customer data being intercepted in the same way. Our quickstarts automatically perform this pinning. Note that once an Approov token has been obtained it is cached by the SDK for up to 5 minutes so that subsequent API calls do not require additional communication with the Approov cloud service.
  4. Your backend API is able to check the validity of the Approov token by checking it has been correctly signed with the symmetric secret. If it is, then you know that the API request is really coming from an official registered version of your app; it is not being spoofed by some other entity. Moreover, a valid Approov token also indicates that the checks on the runtime environment have passed, as controlled by the security policy you have set in your account. Since the shared symmetric key is never put inside the app, an attacker cannot reverse engineer it in order to create their own signed Approov tokens without going through the integrity measurement process.

Detection Capabilities

Approov is able determine various properties of the app and the environment in which it is running. The individual detections are mapped to individual property flags that are determined each time an Approov token is fetched. It is possible to set security policies that determine, at a fine grain level, whether a given detection should result in a valid Approov token being issued or not. The summary below may change at any time as new threats are recognized, but we will endeavor to keep this table as up to date as we can.

Type Description
AppAttest Approov provides an optional integration with Apple's AppAttest capability. This provides an additional security layer for iOS devices that support this to prove that requests are from the authentic version of your app.
Authenticity Analysis of the app to ensure it is one that has been officially registered. Failure may indicate that a fake or tampered app is being used, or one where its registration has been revoked.
Automation Detections of the app being automated in some way. For a production app this is a strong indicator of automation that may be associated with some nefarious use of the app. Basic detection is in place for Appium iOS and monkeyrunner on Android.
Banning Mechanisms are provided to ban particular devices so that they no longer receive valid Approov tokens.
Cloning Android app cloning is detected, which allows an app to be effectively installed inside another app, typically to allow multiple accounts on the same device. Permitting apps to run this way may have significant implications for the users security and privacy. Approov detects a multitude of these cloning apps, a popular example being Parallel Space.
Debugging Various levels of detection are used to determine if the app is running in a debug environment.
DeviceCheck Approov provides an optional integration with Apple's DeviceCheck capability. Various propeties can be extracted from the results of this and used to determine device rejection. This may also be used to provide permanent banning of specific devices.
Emulation Detection that the app is running on an Android emulator or iOS simulator. For Android, if the SDK is running on x86, then it is more likely to be an emulator, so only an internal list of known real 32-bit x86 devices are allowed through. Currently all 64-bit Android x86 devices are categorized as emulators.
Frameworks Detections for various framework and modding environments. For iOS specifically Cycript and Cydia are detected. Android specifically detects the Xposed framework. The Frida framework is detected on both Android and iOS, with protections to prevent attachment to the app while it is running.
Filtering Capabilities are provided for filtering devices based on various characteristics. This may be for information only or it may be used to reject or permanently ban certain devices.
Jailbreaking Detection that the iOS device the app is running on has been jailbroken.
Modding Apps Detection of apps associatd with hacking or modding, such as GameGuardian on Android.
Rooting Detection that the Android device the app is running on has been rooted. This includes detection of the Magisk root manager, even when it is being actively cloaked.
SafetyNet Approov provides an optional integration with Google's SafetyNet. Various propeties can be extracted from the results of this and used to determine device rejection.
Spoofing Approov provides integrity guarantees for the data transfer between the protected core of the SDK and the Approov cloud service. Any tampering is detected and causes failing Approov tokens to be issued.
Tampering Various checks are performed to ensure the runtime integrity of the app. The overall app memory layout is also monitored looking for suspicious changes or configurations indicating that the app is being monitored or attacked.
Unpinning Detection that pinned connections between the app and the backend API are being compromised. Approov can perform continuous pinning testing and there is detection of certain frameworks designed to compromise the integrity of pinning.

Dynamic Pinning

This section describes how certificate public key pins can be dynamically managed by the Approov SDK.

What is Pinning

Pinning is necessitated by the fact that an attacker may be able to control both the device and also the channel over which it communicates. In the absence of pinning, attackers are able to install additional certificates on the device as being trusted, and then use a proxy to decrypt any traffic from the mobile app to the API endpoints. This method can then be used to steal valid Approov tokens from the communication channel in order to make spoofed requests, as though they were coming from the app.

Pinning represents good security hygiene. It prevents real users from having their traffic intercepted if an attacker is able to trick them into installing an additional certificate on their device that then becomes trusted for TLS communication. Pinning ensures that the app avoids completely delegating its trust to the device.

There are various existing mechanisms to implement pinning in an app. Although conceptually identical, there are significant implementation differences between Android and iOS:

  • Android: There is a good overview on TLS more generally here. This article provides specific information on how pinning can be implemented for various different HTTP stacks that might be used in an app. Android have also added a network security configuration feature that allows pins to be specified at the manifest level for an app. Pinning with the OkHttp stack is straightforward using the CertificatePinner class.
  • iOS: There are fewer resources targeting iOS, but this is a good place to start. TrustKit is a popular library used to implement pinning, and there is also a version for Android. iOS has also introduced an Identity Pinning configuration capability.

These standard methods can be used to pin an app’s connections with the backend API server. However, they implement static pinning which require the app itself to be updated to change the pins.

Note that the Approov SDK uses its own methods to pin the connections it makes with the Approov cloud service, so you can be sure that this channel is defended without any further work.

Static Pinning Issues

Under normal circumstances public key pins do not have to be changed very often. Approov uses public key pinning rather than certificate pinning. This means that the pin is actually to the public key of the certificate rather than a hash of the whole certificate contents. The advantage of this is that, if certificates are changed simply because they are expiring and need to be renewed, then the same public/private key pair may be used to generate the new certificate without invalidating the pins.

The difficulty arises when a certificate has to be revoked and replaced if there is a concern that the private key has been compromised (or lost). This could allow an attacker to generate fake certificates and spoof the endpoint, intercepting traffic from the app if they are able to insert themselves as a Man-in-the-Middle (MitM) in the network.

Such an event necessitates a change in the public key pin for the certificate, as a new private key needs to be generated. If this is simply changed immediately then it would prevent apps with the public key pin from connecting to the API. The app would no longer work. It is recommended practice to also include a backup pin inside in the app that could be used in such an emergency. But this requires careful management and also relies on the backup’s private key not being compromised at the same time.

Thus the disadvantage of the static pinning methods described in the previous section is that they fix the set of valid pins into the app itself as part of its configuration. This means that for an app to get a new set of pins a new version of the app must be released and be installed on a user’s device. In reality this can take many days, or even weeks, for most of the apps to update and there may always be a stubborn cohort whose apps are never updated. These would be denied access once the pins are changed, and may end up as either permanently lost users or ones which increase user support load.

Static pinning causes problems both with the speed of incident response and user retention. Ideally what is required is a means to transmit the updated pins over-the-air immediately to invocations of the app without any need for an app update. Moreover, this needs to be done in a secure manner to prevent an attacker using this as a back door to inject their own pins to undermine the pinning protection. Approov offers a dynamic pinning solution that fulfils these requirements.

How Dynamic Pinning Works

When the Approov SDK connects to the Approov cloud the set of public key pins for API domains being protected are downloaded automatically. These will then be stored in the dynamic configuration and thus be available immediately the next time the app starts up. This is convenient for apps developed using frameworks that require any public key pins to be presented very early during the initialisation of the app.

The overall architecture is as follows:

Pinning Architecture

The SDK configuration is signed using Elliptic Curve Cryptography (ECC), with the public key held in the initial SDK configuration and the private key held securely in Approov’s servers. This allows over-the-air dynamic updates to the configuration to be sent to running apps that can be verified as being untampered and authentically issued by the Approov servers. This is guaranteed even if the update is transmitted over a channel already compromised by a MitM attack. An attacker cannot know the private key to tamper with an update. They could block an update of course, but only while they have control of all communication, so any other use of the app will cause an update to be received.

If any change is made to the API domains and their pins using the approov CLI then an updated dynamic configuration will be transmitted to all any app that requests a new Approov token. The dynamic configuration is signed with the ECC private key, preventing any possibility of tampering and proving that the update has been issued by the Approov servers. This updated dynamic configuration will be written to the local storage of the app, and will either have an impact next time the app is started or immediately, depending upon the implementation of the pinning in the app.

This dynamic pinning is primarily designed to protect the channels over which Approov tokens or secure strings are being transmitted. However, it can also be used to protect other domains. The only restriction for any domain is that there must be a process in place to provide notification of an upcoming change that may impact the public key, otherwise this will cause pinning to fail until updated pins are configured in Approov. For cases where this is not possible, perhaps when the API domain is not under the control of the same organization as the frontend app, a Managed Trust Roots capability is provided.

The dynamic configuration update can also be used to perform over-the-air updates of the networking access rules (in terms of domain names and timeouts) that are used by the Approov SDK to access the Approov cloud servers.

Security Rules Updates

The Approov SDK is able to execute security analysis rules that are supplied dynamically by the Approov cloud service as illustrated below:

You may set your security policy and Approov researchers are continually updating the set of rules and security signatures that are being detected to indicate malicious intent inside the app’s runtime environment. When the first Approov fetch is made in the app, the latest set of security rules are transmitted from the Approov cloud to the SDK. These rules specify the data to be gathered by the SDK and the checks to perform to identify particular threat signatures. The security rules are automatically updated for running apps whenever they are changed on the server.

When an Approov fetch is performed, a predetermined subset of the gathered data and the results of signature analysis are transmitted securely to the Approov cloud. Data analysis is then performed before determining if the particular app instance should be issued with a valid or an invalid Approov token.

This mechanism is also used by Approov researchers to gather intelligence on specific devices that are associated with malicious behavior. It enables a highly reactive security stance without the requirement for SDKs within apps to be updated.

Cloud Server Redundancy

To enable a highly reliable Approov service, the backend is implemented in two different cloud service providers, as illustrated below:

When an Approov fetch is requested, the initial transmission is sent to a primary service hosted in the AWS cloud. The primary service has multiple frontend servers deployed across the availability zones of a region and is setup to automatically scale with the service load. The particular geographic data center utilized is allocated upon sign up. Some accounts may also have support in multiple different geographic data centers to lower latencies in different parts of the world and to offer further enhanced redundancy.

If communication cannot be established with the primary service (or errors are continually returned) then the SDK attempts to make contact with the secondary (aka failover) system. This is available on a different domain name using a different TLD (Top Level Domain) to further enhance redundancy. The secondary failover system is implemented in Google Cloud to provide complete isolation from large scale failures that may occur in AWS. The failover system only provides a subset of the full analysis capability of the primary system, but it will ensure your apps should continue to receive valid Approov tokens in the event of a catastrophic primary system failure.

The failover system only provides service if it is enabled. It continually checks the primary system on a minute-by-minute basis and automatically enables itself if a primary failure is detected, with no need for any manual intervention in the switch over process.

Frontend App Integration

This section details additional information associated with the frontend integration of Approov into your app. You should follow one of our Quickstart Frontend Integrations to do this. If your particular frontend is not supported then you can integrate the Approov SDK directly following the instructions in Direct SDK Integration.

Android Specific

This section provides specific additional information related to Android app integration.

Targeting Android 11 and Above

This section is relevant if your app uses a targetSDKVersion of 30 (Android 11) or above.

This relates to the detection mechanisms used to detect rooting. If you are using a 2.9.0 or later SDK then an additional isolated process is provided that uses a different method to determine if the device is rooted. It is suggested that you always employ this method in addition to ensuring your app has QUERY_ALL_PACKAGES permissions. This is because apps likes Magisk are always subject to change and this could mean that one of the detection methods could be rendered obsolete until a new Approov SDK update is available. Using two different detection methods reduces the risk that your app will not be able to detect root at all for a period.

Some aspects of the Approov SDK root checking analysis rely on PackageManager visibility. This analysis is only used for the purposes of scanning for rooting apps on the device, and is never used for any fingerprinting or tracking of the devices themselves. Approov does not retain any information regarding the packages installed on particular devices and, under normal circumstances, all processing of the package information is performed on the device itself.

Package visibility is restricted if your app targets Android 11 (API level 30) or above and some of the root checking capabilities will not be available. Thus devices might not be marked as rooted or root-risk when they otherwise would be. Other analysis, including that associated with the detection of instrumentation frameworks, is unaffected.

If you wish to retain the full root analysis capability while targeting API level 30 or above then you can use the special QUERY_ALL_PACKAGES permission in your manifest:

<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />

However, from 1st July 2022 Google will consider this to be a sensitive permission and you will be required to declare this in a declaration form in the Play Console. You must justify this on the basis of the security importance of detecting rooting for your application, and that the feature will not be used for any form of user fingerprinting. Google already suggests that exceptions will be forthcoming for “Apps that have a verifiable core purpose involving financial transaction functionality (e.g. dedicated banking, dedicated digital wallet) may obtain broad visibility into installed apps solely for security-based purposes.”

If you are using a 2.9.0 or later SDK on Android then you will obtain the device property flag no-package-query if your app is unable to perform a full query of app packages. This does not cause a failure, but is simply a reminder that Approov does not have full visibility of packages so some checks cannot be performed.

Isolated Process Capability

An additional optional method is provided by the Approov SDK to detect certain rooting tools such as Magisk. If your app is able to query all packages (see Targeting Android 11 and Above) then this is unnecessary, but does provide an additional layer of protection. The method works by allowing the Approov SDK to create a lightweight Service in an isolated mode, which allows it greater system visibility. The Approov SDK starts this service on the first Approov token fetch and then communicates with it in order to provide enhanced detection capability.

The following needs to be added to the app’s manifest (AndroidManifest.xml) to use this facility, inside the application tag:

<service
    android:name="com.criticalblue.approovsdk.isoproc.IsolatedService"
    android:enabled="true"
    android:isolatedProcess="true" />

Note that if you use this option then any custom onCreate() method declared in the Application class will be called when the service is created. Since an isolated process has a vastly reduced set of permissions this can, in some circumstances, cause exceptions on startup. We suggest you look at your logcat output around the first Approov fetch to ensure that this is not happening.

If there is a problem then you may need to add conditional code in your onCreate method to avoid calling code requiring file access, and some other extended, permissions. This can be done using the isIsolated method defined on Process. You can implement something like the following:

public class YourApp extends Application {
    @Override
    public void onCreate() {
      super.onCreate();
      if (!android.os.Process.isIsolated()) {
          // permission requiring code that should not be called when creating an isolated process
      }
    }
}

Note that although isIsolated was only officially added at API level 28, it has actually been available since API level 16. For a discussion of this topic, and some alternative methods to detect if your app is running an isolated process, see How can I tell if I am running in android:isolatedProcess?

Note that if you are initializing the Approov SDK or ApproovService in your Applicaton’s onCreate method then you should avoid calling it when running in an isolated process.

This feature is only available in 2.9.0 and later SDKs.

Android Obfuscation

Note that since the Approov SDK is already obfuscated with Proguard so you should not attempt to obfuscate it again (with Proguard or R8) as this will cause it to stop working. Add the following exemption to your proguard-rules.pro:

-keep class com.criticalblue.approovsdk.** {*;}

Use on Emulator

We recommend using a physical device for testing your apps. However, you can use an Android Virtual Device (AVD) in Android Studio. Normally the Approov service will not generate a valid Approov token when running in the emulator and will indicate a rejection wih the emulator property. The only way to obtain a valid Approov token on an emulator is to force an always-pass policy for it. This requires extracting the device ID. We suggest that the approov device -add latest is the easiest method when first trying Approov.

iOS Specific

This section provides specific additional information related to iOS app integration.

Use on Simulator

We recommend using a physical device for testing your apps, however, the simulator architectures are provided for you to use when this is not possible. Normally, the Approov service will not generate a valid Approov token for a simulator device. The Approov service will indicate a rejection wih the ios-simulator property. The only way to obtain a valid Approov token on a simulator is to set an always-pass policy for it. This requires extracting the device ID. We suggest that the approov device -add latest is the easiest method when first trying Approov. Please note, using the command line to install or remove applications on the simulator may produce a different device ID. This is also the case when the simulator is reset which erases all settings and applications.

Please note, if targeting a simulator device and using xcframework SDK, Approov does not provide support for the i386 architecture. Since Xcode might try building all the simulator architectures by default this will produce an error. You can disable any unavailable architecture in your target build options, Architectures section as follows:

Xcode: Disable architectures

Please also note, that in some cases you might experience an error when running on the simulator if the Approov framework contains a previusly used signature within it. You can simply remove this signature as follows from the Approov.xcframework using the MacOS codesign command:

codesign --remove-signature Approov.xcframework/ios-arm64_x86_64-simulator/Approov.framework/Approov

Bitcode Mode Management

If you are compiling your app from bitcode then it is important that the SDK you are using is marked as being in bitcode mode. This happens automatically when you download the SDK directly with the -bitcode option. If the SDK was not directly downloaded using the Approov CLI then it is also possible to use the -bitcode option when registering the app.

If you are using one of our Quickstart Integrations for the app integration then you should use the -bitcode option when registering the app. Note though, you must be using a bitcode version of the SDK itself. Follow the instructions in the relevant quickstrat which will detail how this is achieved.

Commands are also provided to see the list of SDKs for your account that have bitcode mode enabled:

$ approov sdk -bitcodeList
6015: 2.6.0, iOS-universal
6243: 2.6.1, iOS-universal

It is possible to manually add a specific SDK ID as being in bitcode mode, although normally you will not need to do this as use of the -bitcode option on direct SDK download or registration will be sufficient. If you do need to do this then use the following command, in this case for the SDK ID 5777:

$ approov sdk -bitcodeAdd 5777
bitcode mode enabled for SDK 5777

Individual SDK IDs can then be removed from bitcode mode as follows:

$ approov sdk -bitcodeRemove 5777
WARNING: removing bitcode mode will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
bitcode mode disabled for SDK 5777

Getting the Initial SDK Configuration

In order to initialize the SDK a configuration string must be obtained using the approov CLI as follows:

$ approov sdk -getConfigString
#your-account#+kv3bSO3x11jB25QN7/IdP3INz7WTpg+ScXG3vyLOJU=

The provided string is the config parameter to initialize Approov as described in the Quickstart Frontend Integrations. The information consists of the account identifier and public key string that uniquely identifies your account.

Initialization using this method is only supported in version 2.7.0 and later SDKs. For earlier SDKs use the extended configuration.

Getting the Extended SDK Configuration

In some special circumstances Approov support configure your account so that a special configuration string needs to be used. For instance, this might be required if the configuration requires communication with Approov servers to be proxied using a different DNS address, rather than using the addresses embedded in the SDK itself. To facilitate this, an extended form of the SDK configuration must be used. This is a much longer configuration string that is actually a base64 encoded JSON Web Token (JWT).

An extended SDK configuration can be obtained using the approov CLI as follows:

$ approov sdk -getConfig extended.config
initial SDK configuration written to extended.config

In this case the configuration is written to the file extended.config. Copy the contents of this file and use it for the Approov initialization.

Handling Multiple Accounts

You may have access to multiple Approov accounts. Each account will have a different user roles in your Approov CLI. Furthermore, each account will have a different initial configuration for the SDK. This configuration will embed a different account name and also a different public key, since each account is allocated a different public/private keypair. This prevents a configuration for one Approov account being valid for another.

These different initial configurations will need to be carefully managed in your app development and build environments. Note that, the account name that is read from the configuration is always logged as part of the Approov SDK initialization, e.g. an example from Android logcat:

2019-05-23 16:41:43.139 32592-32592/com.criticalblue.demo I/Approov: test-account, com.criticalblue.demo, 2.0.4(1033), h4gubfCFzJu81j/U2BJsdg==

Approov Fetch Status

When some operation are performed that interact with Approov a fetch status is returned that may be output in the logging. The possible status results are enumerated in the table below. Note that all iOS errors are prefixed by ApproovTokenFetchStatus..

Status (Android / iOS) Description
SUCCESS / success Indicates that a fetch call to the SDK was successfully completed. If you are fetching an Approov token then if it was successfully fetched it still might not be valid if the app does not pass its rejection policy. Common reasons for unexpected invalid tokens include forgetting to register new app builds, see registering an app, or because a debugger is attached to the device when a token is requested. Note that you can set a device specific custom always pass security policy to get valid tokens in both the previous scenarios but, if you do, you must take extra care to test your app on a variety devices without a custom policy before release.
UNPROTECTED_URL / unprotectedURL Indicates that the provided URL is valid but is not one for an API domain that needs to be provided with an Approov token. The request should continue without adding an Approov token. You get this on API domains that have been added with the -noApproovToken option.
UNKNOWN_URL / unknownURL Indicates that the provided URL is valid but is is not an API domain configured for use, and wildcard mode has not been enabled. You should add the API domain if necessary. The request should continue without adding an Approov token.
NO_APPROOV_SERVICE / noApproovService Indicates that a fetch operation could not be completed due to the unlikely event that Approov cloud services are completely down (including the failover service) or, more likely, that the account has been cancelled. The error might also occur in some cases of poor network connectivity. In the case of an Approov token fetch we suggest you continue without adding any Approov token to the API call, so that requests can still reach your backend. This is to guard against some catastrophic failure or cancellation of your Approov service. In the case of secure string or custom JWT fetches it is not possible to continue, and you must retry.
NO_NETWORK / noNetwork Indicates that a fetch operation could not be completed because there is no network connectivity. The SDK checks for network connectivity before making a fetch attempt. This allows a rapid return from the fetch if there is no connectivity. If this error is received then there is no point in proceeding with any following API call which will also require network access. A timed, or user initiated, retry is required.
POOR_NETWORK / poorNetwork Indicates that a fetch could not be completed due to poor network connectivity. If this error is received then there is no point in proceeding with any following API call which will also require network access. A timed, or user initiated, retry is required.
MITM_DETECTED / mitmDetected Indicates that there is a Man-In-The-Middle (MITM) in the communication with the Approov cloud service. This may be malicious or may simply indicate that the end user is using a network with a firewall that intercepts all traffic for inspection. If this error is received then there is no point in proceeding with any following API call which will also require network access. A timed, or user initiated, retry is required.
REJECTED / rejected Indicates that for a secure strings or custom JWT usage the app does not pass the selected rejection policy, so the operation cannot be completed. A suitable message must be presented to the user about why it is not possible to proceed. Common reasons for this include forgetting to register new app builds, see registering an app, or because a debugger is attached to the device when the fetch request is made. Note that you can set a device specific custom always pass security policy but you must take extra care to test your app on a variety devices without a custom policy before release.
BAD_URL / badURL Indicates that the provided URL is not in the correct format. The URL should just be provided as a domain, although a full URL path may be specified from which the domain is extracted. This error can occur if such a URL is provided with a http:// rather than the https:// scheme.
DISABLED / disabled Indicates that for a secure strings or custom JWT usage that the appropriate feature is not enabled in the account settings.
UNKNOWN_KEY / unknownKey Indicates that for a secure strings usage that there is no secure string with the given key value.
NA / badKey For iOS, indicates that for a secure strings usage the key value provided is invalid, either being empty or longer than the 64 character maximum allowed.
NA / badPayload For iOS, indicates that for a custom JWT fetch that the payload provided is invalid. It is either too large or is not a valid JSON object.
NO_NETWORK_PERMISSION / NA For Android, indicates that the app does not have ACCESS_NETWORK_STATE or INTERNET permission.
MISSING_LIB_DEPENDENCY / NA For Android, indicates that the Approov SDK dependency on the OkHttp library has not been satisfied.
INTERNAL_ERROR / internalError Indicates there has been an internal error within the SDK. Please contact Approov support if this ever happens.
NA / notInitialized For iOS, indicates that an attempt is being made to use an SDK method before it has been initialized. Note that the Android SDK generates an exception in this case.

Fetch Latency

The integrity check operation provided by Approov requires the SDK to perform a CPU computation and possibly one or more network requests. A Cached Fetch, as its name implies, returns an already available Approov token and or secure string and does not require much additional computation or any network connection. Note that a custom JWT fetch always requires a network fetch. The table below provides an average of values obtained by measuring the performance of fetch operation on a range of devices for both Android and iOS with good network conditions. Moreover, the devices were located in Europe or the US West Coast, geographically close to our AWS points of presence for the Approov cloud. The type of fetch mechanism (synchronous or asynchronous) does not impact the latency.

Platform Network Fetch Cached Fetch
Android 950 ms 50 ms
iOS 750 ms 35 ms

The iOS Approov SDK can optionally perform additional DeviceCheck using the Apple DeviceCheck or AppAttest capabilities. If either of these options are used then the Approov SDK must make a call to Apple servers to identify the device. This needs to be done on the first Approov fetch after installing the app. Performing this operation requires additional network connection(s) and CPU processing time, over which the Approov SDK has no control. This can substantially delay the fetch operation on the iOS platform by adding up to 2500ms of additional latency (or even longer if both options are used). If you are using either of these options then consider asynchronously prefetching an Approov token as early as possible to help hide this latency.

The Android Approov SDK can optionally perform SafetyNet attestation. If this option is used then the Approov SDK must make an attestation call. This needs to be done on the first Approov fetch after installing the app. Performing this operation requires additional network connection(s) and CPU processing time, over which the Approov SDK has no control. This can substantially delay the fetch operation on the Android platform by adding up to 3500 ms of additional latency. If you are using this option then consider asynchronously prefetching an Approov token as early as possible to help hide this latency.

If you are using Android and you have added app signing certificates, this will cause an increase to the latency of the first Approov fetch after launching the app by an amount determined by the size of the APK and the performance of the device on which the app is running. This can add up to 1300ms for a 30MB APK on an entry-level device, but is 500ms or less for mid and high performance devices.

Note that the Approov fetch process itself may make various retries of the communication with the Approov server. Within the SDK, the absolute worst case timeout before the method returns is typically configured to be 30 seconds.

Attestation Response Code

An Attestation Response Code (ARC) is a short alphanumeric code that is assigned to all Approov fetch events. The ARC encodes a subset of the device property flags of the device making the request. It also encodes whether a fetch resulted in attestation pass or not. The encoding ensures it is not possible to determine the actual properties without Approov backend access. When fetching Approov tokens, the ARC also embedded inside the received Approov tokens themselves in the arc claim.

ARC provides a way of finding out why an attestation may have failed, and the overall properties of a device, without leaking this information to the end user or, indeed, any attacker. This is because the ARC cannot be decoded without access to the Approov cloud service. It may also be useful for internal debug purposes or internal support.

The ARC can be provided in error information presented to the user or submitted by the app in an API call, for cases where the user is having trouble using their app. The base32 encoding and short length means that it is possible to read out or submit this information reliably for support purposes. The encoding also includes internal checking that detects most transcription errors. This facility might be needed if the app is not usable because invalid Approov tokens are being issued. When the ARC is decoded it is then possible to ascertain why Approov fetches are failing and for remedial action to be taken.

Approov also provides a more direct way of determining why a particular attestation was rejected using Rejection Reasons. This provides the causes in the SDK so that the app can directly inform the user. This feature is off by default.

Unless you onboarded before version 2.5 of Approov, ARC will be enabled by default. If necessary you can enable it as follows:

$ approov policy -setARC on
WARNING: updating the arc policy will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
arc policy was set successfully

Changing the ARC policy requires an admin role and confirmation. Although you are able to set the arc policy to off we do not recommend this.

The current status of the ARC policy can be obtained as follows:

$ approov policy -getARC
ARC policy is on
flags that can be ARC encoded:
  app-not-registered
  bad-hmac
  ...

If the policy is on then a list of the device property flags that can be encoded in the ARC are provided. This means that if any of those properties were set for a fetch then you will be able to determine that by decoding the ARC.

The codes are encoded using a cryptographic secret so that it is not possible to determine their meaning without access to the Approov account backend. Moreover, the encoding for each Approov account is unique so codes generated by one account cannot be decoded by another.

Decoding an Attestation Response Code

The Attestation Response Code is embedded in the arc claim of all issued tokens. However, if you wish to obtain the code directly then certain Quickstart Frontend Integration errors provide it directly. See the quickstart documentation for more details.

An API endpoint is provided that takes an ARC and returns the decoded information for it. This is designed for use in backend customer support systems. Information about how to access the API endpoint is provided as follows:

$ approov token -showArcInfoCurl
curl -H "Authorization: Bearer xxx..." -H "Arc: <arc>" https://<account-domain>/arc-info/

The API key in the Authorization is account specific and should not change unless a specific support request is made to request its rotation. The API key only allows the decoding of tokens and obtaining additional token information and does not enable any other actions on the account. However, as with any account credential, steps should be taken to keep it secured and to prevent accidental disclosure or inclusion in source code repositories.

An example API request is made as follows, with the ARC XJEUXVAKZY:

$ curl -H "Authorization: Bearer xxx..." -H "Arc: XJEUXVAKZY" https://<account-domain>/arc-info/
{
  "status": "failed",
  "deviceProperties": [
    "app-not-registered",
    "rooted",
    "root-risk",
    "xposed"
  ]
}

The status indicates if the attestation was passed or failed. If the provided ARC is invalid in some way (perhaps issued to a different Approov account or entered incorrectly) then the status will be arc invalid.

The deviceProperties lists device property flags that have been determined from the device. If the status is failed then this will almost certainly pinpoint the reason(s).

Note that, although the output is a curl command, you can of course use an alternative tool or command to perform the GET request.

This API is for the use of your backend systems only. Never build calls to this API, and especially not the Authorization key required, directly into your mobile app. Moreover, this endpoint should only be used for informational purposes, as it may be subject to rate limiting and does not have the Cloud Server Redundancy features of the Approov token issuance process.

Rejection Reasons

This feature allows an app to directly determine if an Approov operation has failed because the device does not meet the rejection criteria for the current security policy. See the Quickstart Frontend Integration documetation to see how it can be obtained for your integration. It is provided as a comma separated list of the device properties that are asserted and are in rejection set for the current rejection policy.

This feature is not enabled by default. If you enable it then the app will be able to determine programmatically whether a particular fetch request has passed or failed, and the reasons for failure. By default, and if the feature is again disabled,an app is unable to determine if a token is valid. This is by design, as it reduces the information available to attackers. Only use this feature if you wish to directly inform the user about failures and their causes.

You can enable this feature as follows:

$ approov policy -setRejectionReasons on
WARNING: updating the rejection reasons policy will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
rejection reasons visibility policy was set successfully

Changing the rejection reasons policy requires an admin role and confirmation. Use off to disable it again.

The current status of the rejection reasons policy can be obtained as follows:

$ approov policy -getRejectionReasons
rejection reasons visibility policy is on

The rejection reasons information may be presented to the user as an explanation of why they are unable to proceed in the app. You can rely on the device property names not changing, so you may wish to split the string and check against individual commonly occurring properties (e.g. rooted or jailbroken) and provide a more detailed explanation to the user.

This rejection reasons capability is only available in version 3.0.0 and later SDKs.

Managing API Domains

This provides an overview of the management of API domains in the account. These correspond to the domains for which Approov protection can be applied.

Overview

Each Approov account has a set of API domains for which an app can fetch Approov tokens. These will typically correspond to the domains serving the APIs that are to be protected with Approov. An account may have a maximum of 25 different domains. API domains may be added and removed from the account as required.

Approov is passed the API domain for which a token is being fetched. There are a couple of motivations for specifying Approov token fetches with particular domains:

  • APIs that are protected with Approov tokens need to be pinned to prevent a Man-in-the-Middle (MitM) attack from stealing valid, albeit short lived, Approov tokens. Pinning needs to be based on the domain for the API since this determines the certificate that will be presented by the server.
  • It is possible that Approov tokens fetched for different domains are in a different format, or are signed using different secret keys. For instance, a particular domain may be setup to use encrypted (JWE) rather than symmetrically signed (JWS) tokens.

Domains are restricted to lower and upper case letters, digits, a dash and a period. This means that the API domain should not (and cannot) contain the full URI path to a particular resource.

There is no special handling of sub-domains so, for instance, your.domain and sub.your.domain are considered to be entirely distinct.

Adding API Domains

A new API domain can be added to the account as follows:

$ approov api -add your.domain
WARNING: adding the API will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
added API domain your.domain with type:account, alg:HS256, pin:JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU=
enabled continuous monitoring for https://your.domain:443 (remove using `approov monitoring -removeAPI`)

Confirmation is required whenever a new domain is added. This is because it has an immediate impact in production, with tokens being served for the new domain. As soon as a domain is added, tokens for the API domain can be obtained.

New domains have a public key pin added derived from the public key of the leaf certificate presented on the domain. This pin can be used to protect the communication channel between the app and API domain to prevent any Man-in-the-Middle (MITM) attack between the app and the API backend. This is explained in detail in Public Key Pinning and is not covered further here. In some cases using a leaf pin might not be appropriate, so you should consult the team responsible for maintaining the certificates for the backend API. If the API domain that you wish to connect to is not on the standard port 443, you can use the -port option to select a different port from which to obtain the pinning information. Do not try and add the port to the API domain itself as this is not valid.

By default, newly added domains are included for continuous API monitoring. This means that you will receive an email notification if the API domain becomes inaccessible or the certificates it presents no longer match the pins in the account. Note that you must setup the alert email or general email recipients to receive these notifications.

By default, newly added domains will support attestations from mobile apps. Add the -allowWeb flag if you also need to provide access to the API from web apps using one or more of the Web Protection Integration.

By default, Approov tokens for a particular API will be issued as signed JWS tokens using the account secret key. Approov also provides an option to issue encrypted JWE tokens for a domain. This is enabled by using the -jweoption when adding the new API domain. The Approov token format is covered in more detail here.

Once you have added an API domain you can edit its attributes by adding it again with the new set of attribute options specified. However, editing an API domain requires the admin role.

As explained, adding a domain in this way will set a pin based on the leaf certificate presented from the domain. This may then be used by your app to pin the connections that it makes to that domain. Pinning connections in this way significantly increases security, however, there is a danger that you app will stop communicating with the API if the certificates on the domain change and the public key of the certificate is not preserved. To avoid this, you should try to manage your backend APIs so that the same public key is used when certificates are rotated. However, if this is not possible, Approov does give you the flexibility of dynamically updating pins if required and, by default, you will receive an email from the API monitoring that will warn you of a pin mismatch.

Keyset Key API Addition

If you have added one or more keyset keys then you can add an API domain that uses one of those keys as follows:

$ approov api -add your.domain -keySetKID your-key
WARNING: adding the API will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
added API domain twitter.com with type:keyset, alg:RS256, kid:your-key, pin:kJ8+U7wNPfc5vxwnQYvlffbaZA6wwCvd/eC8YMpB+sU=
enabled continuous monitoring for https://your.domain:443 (remove using `approov monitoring -removeAPI`)

This adds the domain using the keyset key your-key. This means that all Approov tokens issued for the domain will be signed or encrypted with the specified key. The key identifier will appear in the kid claim in the header. The particular algorithm to be used is also defined by the key, allowing a wide range of choices including asymmetric options which can ensure that the Approov cloud service is the only entity capable of generating valid tokens signed with the private key, which the tokens can be verified by your backend using the public key.

Adding No Approov Token Domains

An option is provided to add an API domain which does not need Approov tokens to be sent. Do this as follows:

$ approov api -add your.other.domain -noApproovToken
WARNING: adding the API will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
added API domain your.other.domain with type:none, pin:kJ8+U7wNPfc5vxwnQYvlffbaZA6wwCvd/eC8YMpB+sU=
enabled continuous monitoring for https://your.other.domain:443 (remove using `approov monitoring -removeAPI`)

The purpose of this is to allow access to the pinning or managed trust root features of Approov without the need to send Approov tokens. This option should therefore only be used on endpoints where it is not necessary or possible to add Approov token checking on the backend.

Any attempt to get a token for the domain results in an UNPROTECTED_URL / unprotectedURL status from the Approov token fetch call. The Quickstart Frontend Integrations continue with the request in this case without adding an Approov token.

Listing API Domains

A list of all the domains that are configured for the account can be obtained with:

$ approov api -list
2 API domains:
 your.domain           type:account, alg:HS256
 shapes.approov.io  type:restricted, alg:HS256

This provides information about all of the domains that have been added and their attributes. The type attribute may be:

  • account: This is the default, indicating that the account secret key is used.
  • restricted: Indicates that the keys and pins for the domain are centrally managed by Approov.
  • keyset: Indicates that the key used for the domain is one from the keyset.
  • none: Indicates that the domain has been added without the need to send Approov tokens.

The alg attribute shows the type of algorithm used for signing or encrypting the Approov tokens. By default, for account type tokens, the HS256 signing algorithm is used. However, if the -jwe option was used then the A256GCMKW JWE encryption algorithm is used instead. For a keyset type a wider range of algorithms are avaialble.

The kid attribute, and the associated value, is shown if the domain has been configured to use a JWT KeySet entry. The specified key ID will be included in the header of all subsequent tokens issued for the domain.

The monitorPort property is included if contiuous monitoring has been enabled for the domain (the default). This displays the port being used to probe the domain, normally 443. (See API Monitoring)

Approov tokens are only served, for an account, for those APIs listed by this command. Any attempt to get a token for another domain results in an UNKNOWN_URL / unknownURL error from the Approov token fetch call (unless wildcard mode is enabled).

Removing API Domains

An API domain that has been previously added can be removed with the following command:

$ approov api -remove your.domain
WARNING: removing the API will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
removed API domain your.domain

Note that removal of an API domain requires an admin role and further confirmation is required before the domain is removed. Note that this means that Approov tokens will no longer be served for that domain. You must not remove a domain that is being used by production apps as this will lead to a production outage.

Setting Wildcard Mode

A facility is provided to enable wildcard Approov tokens. Normally if a token fetch is made for a domain for which an API domain has not been added, then an UNKNOWN_URL / unknownURL error is returned. In typical Approov SDK usage this will cause the API request to continue without adding an Approov token. If wildcard tokens are enabled then an Approov token will be returned always. However, if the URL is not for an explicitly added API domain then the provided Approov token will always be a failing one. This is because these domains will not be pinned and so valid Approov tokens should not be transmitted on them.

The purpose of this mode is to enable quick discovery of which particular API calls are getting Approov tokens added and to manually check if Approov tokens are being received at the backend, prior to implementing full backend Approov token checking. This initial discovery also avoids the need to setup any pinning. A gradual transition to full Approov protection can then be made, by adding API domains and turning off wildcard mode without any need to make code changes to the app.

Wildcard token mode can be enabled as follows:

$ approov api -setWildcardMode on
wildcard mode was set successfully

It may be subsequently disabled using an off parameter value.

The current wildcard status can be seen with:

$ approov api -getWildcardMode
wildcard mode is on

Adding Demonstration Shapes API

A special shapes domain (managed by the Approov team) can be added to your account:

$ approov api -add shapes.approov.io
WARNING: adding the API will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
added API domain shapes.approov.io with type:restricted, alg:HS256

This domain serves a very simple API that provides random shapes and it is used by the Approov demo app. Any account can add this domain to generate Approov tokens for the API. The type is shown as restricted meaning that it has the special property that the associated Approov tokens with a secret key expected by that API rather than the standard one for the account. Moreover, you are not able to modify the pins associated with that domain.

Managing Registrations

App registration management determines the set of apps that the Approov service will consider valid for the account.

Android App Signing Certificates

This section is only relevant if you are using Android and are registering an app that is going to be released using Google Play Signing. This means that the app package delivered to your users will be signed by the certificate held in the Google cloud. Releases made via an Android Application Bundle are always signed in this way, but it is also possible to release APKs that are Google Play Signed, as explained in this guide.

In order to use Google Play signing with Approov you need to inform Approov about the app signing certificates that you use. These are remembered in your Approov account so it is only if you add a new certificate or revoke an old one that you will need to complete this step again. An app signing certificate proves that a particular installed app package has been issued by Google via your account. The public key of the certificate allows an encrypted digest of your full app content to be verified. Recreating a valid signature for a modified app requires access to the private key associated with the certificate, which is inaccessible except to Google. Approov supports the signature algorithms in the list of signature algorithm IDs on the Android Open Source Project’s web-site.

The app signing certificate is available in your Google Play console. Log in and navigate to the release management section for your app. You will see a screen similar to the following:

Google Play App Signing

The section App signing certificate shows the signing certificate that is currently active, and its hash in various forms. Download the .der certificate file by clicking on the DOWNLOAD CERTIFICATE button. Save it as app-signing-cert.der, or some other convenient name. Note that there is no risk of key compromise by doing this since it is a public certificate and the private key is not included.

You can add the signing certificate to Approov with the following command:

$ approov appsigncert -add app-signing-cert.der
successfully added C0:F3:15:9B:A5:6C:A8:E1 | Subject: CN=ANOther,O=CriticalBlue,L=Edinburgh,C=UK | Expiry: 21 May 2041

This adds the certificate to those that are known by Approov. The first 8 bytes of the SHA256 hash of the certificate are shown in hex. This matches the value SHA-256 certificate fingerprint shown in the Google Play Console. Other certificate metadata and the expiry date are also output.

Approov will now be able to recognize apps that have been signed with this certificate. The Approov SDK does an analysis of the app signature as part of its analysis to ensure that only your app is able to obtain a valid Approov token. Note that in addition to providing the correct signing certificate, you also need to register the specific app version.

You may add up to 10 different app signing certificates to the Approov account. This allows apps with different signing certificates. These may be from different Google Play accounts, allowing them to be supported in a single Approov account. Moreover, if you upgrade or change your app signing certificate in the Google Play console you should keep the old one in the Approov account as there will be installed versions of your app still using it.

You can list the current app signing certificates as follows:

$ approov appsigncert -list
1 app signing certificate:
 C0:F3:15:9B:A5:6C:A8:E1 | Subject: CN=ANOther,O=CriticalBlue,L=Edinburgh,C=UK | Expiry: 21 May 2041

An app signing certificate can be removed with:

$ approov appsigncert -remove C0:F3:15:9B:A5:6C:A8:E1 
WARNING: removing an app signing certificate will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
successfully removed app signing certificate with fingerprint C0:F3:15:9B:A5:6C:A8:E1

Use the shortened fingerprint hash to select the appropriate certificate. Note that removal requires an admin or delegate role and user confirmation.

Adding or removing an app signing certificate does not have an immediate impact on the validity of registration. The impact is only for apps which are started 30 seconds or more after the change. Contrast this with the app registrations themselves which are actioned within 30 seconds for the next time an app fetches an Approov token (typically a maximum of 5 minutes), with no need to restart the app.

App signing certificates are also employed if you utilize the SafetyNet Integration option to check the certificate hash provided in the SafetyNet token.

Using app signing certificates will cause an increase to the latency of the first Approov fetch after launching the app. For details please see Fetch Latency.

Huawei AppGallery App Signing Certificates

Registering an app that is released to the Huawei AppGallery using an APK or an Android Application Bundle (AAB) is very similar to the process for Android apps described in the previous section.

This section is only relevant if you are registering an app that is being released to the Huawei AppGallery using an Android Application Bundle (AAB). This means that it is using Huawei AppGallery App Signing where the app package delivered to your users will be signed by a certificate held in the Huawei AppGallery.

In order to use Huawei AppGallery App Signing with Approov you need to inform Approov about the app signing certificates that you use. These are remembered in your Approov account so it is only if you add a new certificate or revoke an old one that you will need to complete this step again. An app signing certificate proves that a particular installed app package has been issued by Huawei via your account. The public key of the certificate allows an encrypted digest of your full app content to be verified. Recreating a valid signature for a modified app requires access to the private key associated with the certificate, which is inaccessible except to Huawei.

The app signing certificate is available in Huawei AppGallery Connect. Log in and navigate to the App Signing section for your app. You will see a screen similar to the following:

Huawei AppGallery Connect App Signing

The section App signing certificate shows the signing certificate for the app and its SHA-256 hash. Download the certificate file by clicking on Download certificate. It will be saved as certificate.pem. Note that there is no risk of key compromise by doing this since it is a public certificate and the private key is not included.

The certificate.pem file downloaded from AppGallery Connect is in a non-standard PEM format - some of the file’s lines are longer than the permitted 64 characters. You can use a text editor or, alternatively, the fold utility in a shell to insert the missing line breaks:

$ fold -w 64 certificate.pem > certificate_fixed.pem

The Approov command line tool requires the app signing certificate to be presented in DER format. To convert the certificate use openssl in a shell:

$ openssl x509 -outform der -in certificate_fixed.pem -out certificate_fixed.der

You can then add the fixed and converted app signing certificate to Approov with the following command:

$ approov appsigncert -add certificate_fixed.der
successfully added C0:F3:15:9B:A5:6C:A8:E1 | Subject: CN=ANOther,O=CriticalBlue,L=Edinburgh,C=UK | Expiry: 21 May 2041

This adds the certificate to those that are known by Approov. The first 8 bytes of the SHA256 hash of the certificate are shown in hex. This matches the value SHA-256 certificate fingerprint shown in AppGallery Connect. Other certificate metadata and the expiry date are also output.

Approov will now be able to recognize apps that have been signed with this certificate. The Approov SDK does an analysis of the app signature as part of its analysis to ensure that only your app is able to obtain a valid Approov token. Note that in addition to providing the correct signing certificate, you also need to register the specific app version.

For further information on how to manage signing certificates, for example how to list or remove them, please refer to section Android App Signing Certificates.

iOS IPA Extraction

In order to obtain an .ipa file for iOS select the Archive option in Xcodes Product menu (if the Archive option is greyed out, you need to modify your target by setting the destination to be Any iOS device since targeting a simulator device disables archiving). Once the archive operation finishes, you will see the Organizer window similar to the one below:

Xcode:Archive Organizer

Xcode has archived the source files and linked the libraries by producing an xcarchive file which is a collection of files, binaries, debug symbols and other files from which an actual ipa file can be obtained. From there you should click Distribute App and select one of the options, App Store Connect to submit to the app store or one of the others. Irrespective of the selection, you can always recall the Organizer by selecting the menu Windows and then Organizer and if you select the same archive you can generate another ipa file or make another submission to the App Store.

Registering an App

The Approov service is designed to only send a valid Approov token to apps that have been registered. Registration indicates that Approov has captured the fingerprint of a good instance of your app and should, subject to various other checks and conditions, deliver valid Approov tokens to any identical app instance. Any other app cannot receive valid Approov tokens and will therefore be unable to access the backend API services that you have protected with Approov.

When you release a new version of your app to the app store, you will need to register the final version that will be published. Multiple different versions of the app registration may be live simultaneously to support end users who are running different versions of the app. In general it may take some time for users’ apps to be updated to the latest version. You may also wish to register various versions of the app during the development and test process.

In order to register an app you need the app package that is to be run. This is either an .apk or .aab file (Android) or an .ipa file (iOS). An app being registered must have the Approov SDK integrated within it or else the registration will fail.


$ approov registration -add your-app.apk
registering app
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=your.app.com-2.0[3]-1042  SDK:Android(2.5.0)
registration successful

$ approov registration -add your-app.ipa
registering app
 DRJNqt37tsdHwb9FKFT80dPqXlOHqZnZy68zAiVSsvM=your.app.com-2.0[3]-1041  TeamID:953D8M53YN  SDK:iOS(2.5.0)
registration successful

The message indicates that an overall signature of the app, its name and its version have been extracted and are available for viewing in the list of all registrations for the account. The overall signature consists of a signature hash of aspects of the application, the application package name, application version information, and the ID of the Approov SDK that is integrated within it. Finally, information about the type and version number of the Approov SDK used is also provided.

Once an app is registered, it should be possible to get valid Approov tokens for it, assuming there are no other issues with the device or its runtime environment (for instance, a debugger being active) that prevent it from receiving a valid token. By default, an app registration is permanent and will remain in the Approov cloud database until it is explicitly removed. Permanent app registrations should be used to identify apps that are being published to production.

It is only possible to have a maximum of 250 registrations at any one time.

Android Registration Considerations

If you are registering an Android APK that will be released using Google Play App signing then you must use the -playSigned option, and add your app signing certificates. If the app is in the form of a .aab then this option is set implicitly.

If you are registering an Android App Bundle (.aab file) then the approov tool needs access to bundletool. The bundletool is a command line tool written in Java and distributed as a .jar. To use it you will need Java installed, although it is likely you have it installed already if you are developing Android apps. It can be installed from here. Once you have Java installed you can download the latest version of the bundletool from here. If you have saved the bundletool-all-<version>.jar to the current directory then try a command such as:

$ java -jar bundletool-all-1.7.0.jar version
1.7.0

Substitute the filename to the version you have. This confirms that it is running correctly.

When you make a registration of a .aab Android app the approov tool needs to be able to invoke the bundletool and therefore needs to know its location. This can be done by specifying the -bundletool option providing its path for all registrations of app bundle .aab files. Alternatively the path of the bundletool jar file can be set in the environment variable APPROOV_BUNDLETOOL.

If you are registering an Android app that you intend to publish to the Play Store, you must ensure that it is signed with a V2 signature (or later) or else the registration will not match the Play Store version and it will not receive valid Approov tokens.

If your Android app bundle includes other native libraries that include architectures that are no longer supported, then you may wish to remove them from your build and only include the relevant architectures using ABI Filters. For instance, you can use abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' to restrict to Approov supported architectures only. We have had reports that without this an incorrect package of native libraries can be delivered to certain devices and cause the Approov libapproov.so to be missing and thus the Approov SDK cannot be initialized.

iOS Registration Considerations

If you are registering an iOS IPA then you may also use the -bitcode option if your app is using a bitcode build and will be submitted to the Apple App store with bitcode. This is only necessary if the SDK being used has not already been marked as being in bitcode mode. This normally happens when you first download the SDK using the -bitcode to obtain the version including bitcode. However, this option may be used to ensure that this mode has definitely been selected for the SDK used.

The signature extracted for an iOS registration only includes the version number and not the build number. Thus all builds of the same version will share the same registration. You should thus be careful not to remove the registration for a previous build of the same version, as this will also remove the registration for all builds of that version. Instead you should employ Temporary Registrations and then make any released build registration permanent. This will upgrade any pre-existing temporary registration to be permanent, and any others will expire naturally.

Temporary Registrations

By default an app registration is permanent. This also means that an admin role is required to remove it. Removal needs to be restricted since an accidental removal will stop apps in production from receiving valid tokens, which may effectively bring an app service down. Note that in such a circumstance the Approov failover system will not be enabled, since this is not an Approov cloud system failure but explicit user action.

A temporary registration is performed just like a permanent registration, but with the addition of the -expireAfter option.

$ approov registration -add your-app.ipa -expireAfter 3d
registering app YourCoolApp
 P6nTmI3fhftxUr740ZnUMGKuAyTYjxP5dxKzJGd9yOk=my.app.com-2.0[3]-2974  TeamID:953D8M53YN  SDK:iOS(2.5.0)
registration successful, expires 2019-06-01 16:27:01

This creates a registration that is active for 3 days. The expiry time is given in local time in the output. Note though, if the registration already exists and is permanent or has a longer lived temporary expiration time, then that later time is retained.

The -expireAfter parameter takes a duration which may be specified in y (years), d (days), h (hours), m (minutes) or s (seconds). Multiple time units may be used as long as they are specified in this order, e.g. 3d12h to register for three and a half days.

Updating Registration Expiry

If you have made a Temporary Registration you may subsequently want to make that registration permanent, or at least to extend the time of the registration expiry. You can do this as follows, using the registration signature provided from the registration -listoption:

$ approov registration -updateExpiry P6nTmI3fhftxUr740ZnUMGKuAyTYjxP5dxKzJGd9yOk=my.app.com-2.0[3]-2974
registration update successful

This method does not require you to have access to the original app package. Note that the -expireAfter option can also be used to extend an existing temporary registration.

Unversioned Registrations

By default an app registration is for a specific version of the app. This means that a new app registration is required each time a new app is released. This gives the flexibility of fine grain control of your registrations, allowing you to remove individual registrations associated with specific versions (perhaps if you no longer wish to issue valid Approov tokens to an older version of your app).

However, it is possible to create an app registration that is not specific to a version. This will match any app issued with the same signing authority and with the same package name. If you use this style, then only one registration is required and any updated app release will also match. Remember that you lose the flexibiliuty of revoking individual versions in the future.

An unversioned registration is performed with the addition of the -unversioned option. Note that this is not supported for Android .apk packages, only for .aab.

$ approov registration -add your-app.ipa -unversioned
registering app YourCoolApp
 guwtV9sOk0AaEqE08mWKu32X6x8HuyBqMalrN2UcD64=my.app.com-*-5647  TeamID:953D8M53YN  SDK:iOS(2.6.0)
registration successful

This creates an unversioned registration, denoted by the * in place of the version number.

Unversioned registration is only supported in version 2.6.0 and later SDKs.

Listing Registrations

All of the registrations that are active for the account can be listed as follows:

$ approov registration -list
3 app registrations:
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974                   SDK:Android(2.5.0)  registered:2019-05-15 18:03:17
 P6nTmI3fhftxUr740ZnUMGKuAyTYjxP5dxKzJGd9yOk=approov.io.client.swift.shapes-client-1.0[1]-4803   SDK:iOS(2.5.0)  registered:2019-05-15 18:03:31
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974                   SDK:Android(2.5.0)  registered:2019-05-29 14:49:36 expiry:2019-06-01 14:49:36

Each registration entry provides its overall signature as a single text block at the start of each line. This is the signature that must be copied in order to remove a registration (see next section). It contains a signature hash of aspects of the application, the application package name, application version information, and the ID of the Approov SDK that is integrated within it.

More information is also provided about the type and version number of the Approov SDK used. The registration time of the app is also provided (in local time). This is updated if a new registration of an app is made that happens to have the same signature. Finally, the expiry time of the registration is shown if it was registered with -expireAfter. Once a registration expires it is automatically removed from the list.

Note that if you are looking for a particular registration you are able to find it by simply piping the output through grep, for instance on Linux/MacOS:

$ approov registration -list | grep iOS
 P6nTmI3fhftxUr740ZnUMGKuAyTYjxP5dxKzJGd9yOk=approov.io.client.swift.shapes-client-1.0[1]-4803  SDK:iOS(2.5.0)  registered:2019-05-15 18:03:31

Using this method it is possible to find registrations for specific platforms, SDK versions, app names and versions.

Removing Registrations

Any individual registration can be removed using its overall signature provided from the registration -listoption. For instance, to delete a temporary app registration:

$ approov registration -remove Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974
app registration Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974 has been removed

If you are using the zsh shell you will need to enclose the -remove parameter with single quotes ('). This is because zsh interprets square brackets as a globbing specifier.

You will be asked for confirmation if the app has a permanent registration, but not for a temporary registration. Note the removal process assigns an expiry time for the registration two minutes into the future, at which point it is actually removed. When removed no further valid Approov tokens will be issued for the app. Note that running apps may already hold a cached Approov token so it may take up to 5 further minutes before all valid token usage by those apps stops.

Permanent app registrations are removed in the same way but users are also asked to provide confirmation before the deletion occurs. An admin role can be used to remove any registration. Registrations that were added with an admin role can only be removed with an admin role (it doesn’t need to be the same user). A user’s dev role can be used to remove registrations that they added using a dev role. In other words, a developer can remove their own permanent registrations or any temporary registration and an administrator can remove any registration.

$ approov registration -remove P6nTmI3fhftxUr740ZnUMGKuAyTYjxP5dxKzJGd9yOk=approov.io.client.swift.shapes-client-1.0[1]-4803
WARNING: removing app registration will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
app registration P6nTmI3fhftxUr740ZnUMGKuAyTYjxP5dxKzJGd9yOk=approov.io.client.swift.shapes-client-1.0[1]-4803 has been removed

You can provide just the first part of a signature if it is unique amongst all of the registrations. If you are using the zsh shell then this also means you don’t need to use single quotes if you don’t include the part of the signature with square brackets.

Removing Multiple Registrations

A facility is provided to remove multiple registrations using a single command. This is useful for maintaining the hygiene of your app registrations. You should actively remove registrations that are no longer in use, either because they are registrations for old testing apps (that have been accidentally permanently registered), or for previously released production apps that no end users are still using. The command is invoked as follows:

$ approov registration -removeMatching com.criticalblue.demo,30d
2 matched registrations to be removed:
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974  registered:2019-05-05 16:01:46
 A4rcdXpfEOg0wse4snbAURnjRZidPvY63EULzUrZeFE=com.criticalblue.demo-3.0[4]-2974  registered:2019-05-15 18:02:08
WARNING: removing app registrations will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
removing Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-2.0[3]-2974
removing A4rcdXpfEOg0wse4snbAURnjRZidPvY63EULzUrZeFE=com.criticalblue.demo-3.0[4]-2974

This needs an administration role as this is a risky operation that could cause current production app registrations to be removed if care is not taken. The parameters provide the exact package name of apps to be matched and the minimum age of last registration of the app. In this case it is 30 days i.e. in this case, the command will only remove apps whose last registration is older than 30 days ago. A list of matching registrations is provided. You should review this carefully before allowing the operation to complete.

Testing Android App Bundles

It is not necessary to go through the Play Store console to test using an app bundle with Approov. You can use Android Studio ‘Build → Build Bundle(s)/APK(s) → Build Bundle(s)’ to build an app bundle which will be automatically signed with the debug key from your debug keystore (debug.keystore) or you can use ‘Build → Generate Signed Bundle / APK…’ to build an app bundle and sign it with a key from another key store.

Locate the signed app bundle you have just built and follow the bundletool instructions on Generate a set of APKs from your app bundle and Deploy APKs to a connected device to deploy the app bundle to a test device. The installation section describes how bundletool can be obtained.

For Approov to recognize app bundles built and deployed in this way, you need to add the app signing certificate to Approov, for the key that you used to sign the app bundle. The app signing certificate can be extracted from the key store using the Java keytool, which comes as part of your Java installation (Java can be installed from here). Issue a command such as this, substituting the key alias and filenames to match the key store you are using.

$ keytool -exportcert -keystore debug.keystore -alias androiddebugkey -file androiddebugkey-app-signing-cert.der
Enter keystore password:  
Certificate stored in file <androiddebugkey-app-signing-cert.der>

Then, using the approov tool, add the exported app signing certificate as described above. Keep in mind that the number of app signing certificates in Approov is limited to 10. Sharing of debug or development keystores among a development group is advised.

Annotating a Registration

A facility is provided to add an arbitrary string instead of the version name for a particular registration. This allows a particular registration to be annotated to show that it is for some specific purpose (perhaps a special testing version, for instance) and this allows it to be easily located in the list of all app registrations. We advise you not to use this facility on apps which are to be retained for production purposes, so that the real version number of app registration is available.

The annotation is added as follows:

$ approov registration -add your-app.apk -versionName "special"
registering app
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=my.app.com-special-5647  SDK:Android(2.6.0)
registration successful

This particular registration can then be easily found again:

$ approov registration -list | grep special
Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=com.criticalblue.demo-special-5647  SDK:Android(2.6.0)  registered:2021-05-29 17:07:22

Special Library Registration

By default, the SDK library ID for an app is determined by the approov tool that analyses the app to be registered. In some cases though an Approov SDK may itself be embedded inside another SDK within the app. In this case the tool cannot automatically locate the SDK and, in any case, it is possible for there to be more than one Approov SDK in the app.

In such a case you must use the specific ID of the Approov SDK that you want to register with. This can be specified with an additional command line option as follows:

$ approov registration -add your-app.apk -libraryID 1056
registering app
 Ac15BRFWqxn79dGsjOdVJXVqBQQ64ZWTAuKdrzRC9hc=my.app.com-2.0[3]-5647  SDK:Android(2.6.0)
registration successful

Registration From Device

This feature allows a registration to be made when access is not available to the original IPA or APK. This might be necessary if an app registration has been accidentally deleted and the original IPA or APK file is no longer available, for instance. It leverages the getting specific device informaion capability. Please follow those instructions in order to be able to get the detailed information for a running device, including its app registration information.

You can then add the registration as follows:

$ approov registration -addFromDevice qZka0yfv+ExvOq3PRh6pGw==
using app information captured at 2021-04-07 18:30:10 BST
registering tL8CNNpf4XlekWkwuyJaCRtcntJyjZ1ujYJ7CZMO+Fk==com.criticalblue.demo-3.0[3]-4000
registration successful

This adds the registration associated with the app that is running on the device. Note that is is also possible to use the -expireAfter option to create a temporary registration using this method.

It is is possible to use the -playSigned option to provide a registration that is compatible with an Android app that uses Google Play signing. An app released as an App Bundle will always use Google Play signing. Note that in this case you must also add your app signing certificates.

Registration Cloning

A registration cloning option is provided to support a use case employed by certain Approov customers. In this use case the developer and publisher of the app using the Approov SDK (developer) is distinct from the publisher of the API that is protected by Approov (controller). Both the developer and the controller must have Approov accounts. The developer is responsible for managing app registrations. The controller is responsible for Adding API Domains and also Managing Pins. Only the controller is able to view and manage the secret keys associated with their APIs.

To use this flow, an admin role holder of the controller account should create a delegate user role for use by the developer. The developer can then use this role to:

  • Download the controller’s Initial SDK Configuration for use in their apps
  • Add and remove registrations of their apps to and from the controller’s account. (They do this by cloning app registrations from their account into the controller’s account. Apps that were previously registered but have since been deleted by the developer are removed from the controller’s account at that same time that the new ones are added. The developer cannot modify any app registration that they did not add to the controller’s account. The controller can always remove any app registration from their own account.)

The developer uses the configuration obtained from the controller’s account to initialize the SDK in the app. Since the account that the app uses depends on the SDK configuration with which it is initialized, this flow means that the Approov SDK will use the controller’s account when it is obtaining tokens to include on its API requests. Typically, the app will provide a way to dynamically select which initial configuration is used, allowing the app to either use the developer’s or the controller’s account. In general, there might be several possible controller accounts for a single app.

While in app development, the developer can use Approov in the normal way using their own Approov account. When they do a release for use with the controller’s APIs, either for testing or production, then they will need to copy the active app registrations from their account into the controller’s account. In the case where a single app is to be used by various controllers, the app developer will need a delegate role provided by each one of those controller accounts. If the app has the ability to dynamically switch which controller account is to be used, then the SDK must be reinitialized dynamically to select the appropriate one.

If the developer has initialized the delegate role(s) into their Approov CLI then the registrations can be cloned as follows:

$ approov registration -cloneToAllDelegateAccounts
registrations will be cloned to the following accounts:
  accountA
  accountB
WARNING: this will have an immediate impact on production of the target accounts
ATTENTION: If you wish to continue then please type YES and return: YES
cloning 3 permanent registrations into account accountA
cloning 3 permanent registrations into account accountB

If the delegate roles are password protected then you may be asked for each of the passwords during the cloning operation. If you are unable to provide the correct password then the cloning for that particular account is skipped.

In the example, three registrations are cloned to two different accounts. Note that only permanent registrations are cloned. Note also, due to the complete cloning of all active app registrations, if a new API controller account is introduced, with a new delegate role, then all registrations (including historic ones) are easily cloned with this single command. If a registration was previously cloned, but then subsequently removed, then the next clone operation will also remove it from the target delegate account.

When the registrations are listed in the delegate account they are associated with the name of the app developer account from which they were cloned. This allows the API controller to easily identify the apps that were contributed by different delegate roles.

If you only want to clone to a subset of all your delegate role accounts, then you can do this as follows:

approov registration -cloneToAccounts accountA
registrations will be cloned to the following accounts:
  accountA
WARNING: this will have an immediate impact on production of the target accounts
ATTENTION: If you wish to continue then please type YES and return: YES
cloning 3 permanent registrations into account accountA

This option takes a comma seperated list of the accounts into which you wish to clone your registrations.

The maximum number of registrations that may be cloned in this way is 50. A warning is provided if the maximum number of registrations in the target account is exceeded.

This command only clones the app registrations. If you are using Google Play signing then you will also need to set the app signing certificate in the target account. The delegate role provides rights to do this. Note also that if you are relying on DeviceCheck, AppAttest or SafetyNet this information can also be set using a delegate role.

Approov Tokens

The result of performing a token fetch request with the Approov SDK is an Approov token held by the app. The app then adds the token to the requests made to the backend API to be used in the authorization flow. This section describes the format and content of the tokens.

Token Format

The Approov service uses JSON Web Tokens (JWTs) to represent the authenticity of client apps. This in an open and standard mechanism for representing claims in a tamper proof form and your web service will need to decode and verify these tokens as part of the Approov flow. An Approov token is typically a JWS (a type of JWT) which consists of three parts; the header, payload and signature where each part is base64url encoded and the parts are separated by periods. For a more in depth explanation off JWT tokens, please read this introduction.

JWT libraries take responsibility for generating the header and the signature. We just need to specify the signing algorithm we want to use, the secret key for the algorithm, and the un-encoded payload part. For JWTs, the payload is always a JSON object with the entries referred to as claims.

JWS Token Signing

This section describes the approach used to create signed JWTs (called JWS to differentiate them from JWE tokens which are encrypted). If an app has passed the attestation process acoording to the selected rejection policy, then a correctly signed token is issued. If the rejection policy causes the app to fail attestation then a token is still issued, but it will not be correctly signed. An observer that does not know the signing secret key will not be able to differentiate between these two cases.

There are a number of different options for token signing depending on the type notified for the API domain when it is added:

  • account: This is the default, and this selects a token signed with the HS256 algorithm. This peforms HMAC signing using the account secret key. The 512-bit symmetric secret may be exported using the approov CLI. If there are multiple API domains using the account type then they are all signed using this key.
  • keyset: If keyset keys have been added then an API domain may be assigned to use one of them for token signing. Each key in the keyset is associated with a particular signing algorithm, providing support for asymmetric key pairs such as RSA and ECDSA.
  • restricted: Some specific domains are considered to be restricted and are managed directly by Approov (such as the demonstration Shapes domain). If these API domains are added to the account then they are automatically allocated the restricted type. Approov tokens for them are signed or encrypted using a different key that is not accessible.

Be aware of the performance impact when you are selecting your algorithm. Token signing is performed by the Approov cloud service and it impacts the time required to get a token. Token verification is performed by the backend that handles API requests. The precise performance for different algorithms will be specific to the implementation you use and the hardware on which it is running, however, you can use the table below as a rough guide for Approov tokens (using an HS256 base-case with a signing time of x):

Algorithm Signing Verifying
HS256 x 2x
ES256 5x 15x
RS256/PS256 250x 10x

JWE Token Encryption

Note that Approov can also support another type of JWT, encrypted JWE tokens. One use case for these is if you wish to provide extended information within the anno and do not want to reveal the contents to any party that is able to read the tokens. JWE tokens use compact serialization which has 5 parts separated by ., where the first part is unencrypted and holds the encoded information about the algorithms used to encrypt the Content Encryption Key (CEK) and the payload. The Approov service uses A256GCMKW (alg claim) for encrypting the CEK and A256GCM (enc claim) for content encryption.

An API domain will use JWEs if the -jwe option is used when adding the domain. A JWE will also be used if a keyset key is used that is associated with the A256GCMKW algorithm.

Token Lifespan

The normal lifetime for an Approov token is 5 minutes, plus a grace period, from the point of issue by the Approov cloud service. The grace period of a few seconds is added to allow a valid token to be propagated and checked within a backend API system. If a particular device is identified as being risky in some way (such as it being rooted or jailbroken), then, independently of the overall security rejection policy that is set, it will receive a shorter lived 2 minute token instead of a 5 minute one. This forces the device to make more frequent checks as it receives tokens.

The app itself should never cache Approov tokens that it gets from the Approov as the underlying SDK does this in a secure way. Each Approov call does some basic app environment checking and, if issues are discovered, performs a complete attestation check to fetch a new token. Thus an Approov token lifetime should be considered to be up to 5 minutes, since any cached token may be discarded at any point.

Token Claims

Depending on the source of an Approov token (the main Approov service or the Failover) the claims it contains may vary. However, the expiry (exp) claim is always present. The details of the claims are provided in the table below:

Key Name Type Description
exp Expiry Number The only mandatory claim for Approov tokens. It specifies the expiry time for the token as a Unix timestamp.
did Device ID String This claim identifies the device for which the token was issued. This is a base64 encoded string representing a 128-bit device identifier. Note that this is not, strictly speaking, a device identifier as it is also influenced by the app identifier and may change if the same app is uninstalled and then reinstalled on the same device.
arc Attestation Response Code String This is an optional claim that encodes information about a subset of the device property flags and also whether the attestation was a pass or fail. The claim is encoded in base32 and is typically 10 characters long (although it may be longer in some circumstances). See Attestation Response Code. This claim is not included by tokens from the failover.
ip IP Address String This holds the IP address of the device as seen by the Approov cloud service. It is provided in a human readable IP address format (in either IPv4 or IPv6 format). In practice this value can often change between the time a token is issued and the time it is sent to your backend, so you should never block if it differs, but you may include it as a signal that tokens have somehow been stolen and are being replayed. This claim is not included by tokens from the failover or if the IP Tracking Policy for the account has been set to none.
iss Issuer String An optional claim that is added if the issuer inclusion option is enabled. This provides the Approov account ID that was used to issue the token (suffixed with approov.io). It can be used as an additional layer of backend verification if signing keys are shared between multiple accounts. It indicates that tokens were issued from the expected Approov account. This claim may also be set to an explicit value for long lived Approov tokens. This flexibility is designed for use with server-to-server communication (which may only be signed with the account specific secret keys).
anno Annotation Embedded JSON This is an embedded JSON array of strings showing the list of flags that are set and are in the annotation set for the security policy that is selected. This allows additional information to be collected about the state of a particular device without necessarily causing an attestation failure. Note that if there are no possible annotations then this claim is not present at all. This claim is not included by tokens from the failover.
pay Payload Hash String An optional claim that is added if the protected app passes a token binding argument to the setDataHashInToken method. The claim value is set to the base64 encoded SHA256 hash of the provided payload string. This is typically used to bind an Approov token to some other data used by your app to enhance security (like a user auth token).
aud Audience String An optional claim that is added if the audience inclusion option is enabled. This provides the domain for which the token was issued. It can be used as an additional layer of backend verification to ensure that tokens intended for one domain cannot be used on to access a different one.
mskid Message Siging Key ID String This is an optional claim that encodes the ID of a key being used for Message Signing. This is only present in Approov tokens for which message signing is active. This claim is not included by tokens from the failover.
mpk Measurement Proof Key String An optional claim to provide the measurement proof key if a measurement has been requested by the SDK on the domain for which the token is issued. This is a base64 encoded 128-bit proof key value. Note that if measurement is being used, then JWE tokens will be used to keep this claim secret.
imh Integrity Measurement Hash String An optional claim to provide the integrity measurement hash if a measurement has been requested by the SDK on the domain for which the token is issued. This is a base64 encoded 256-bit SHA256 measurement value. Note that if measurement is being used, then JWE tokens will be used to keep this claim secret.
dmh Device Measurement Hash String An optional claim to provide the device measurement hash if a measurement has been requested by the SDK on the domain for which the token is issued. This is a base64 encoded 256-bit SHA256 measurement value. Note that if measurement is being used, then JWE tokens will be used to keep this claim secret.

Obtaining Additional Token Information

An API is provided that allows additional information to be obtained for a previously issued Approov token. Note that for additional information to be available the Attestation Response Code feature must be enabled.

Information about how to access the API endpoint is provided as follows:

$ approov token -showTokenInfoCurl
curl -X PUT -H "Authorization: Bearer xxx..." -H "Approov-Token: <token>" https://<account-domain>/token-info/
  add `-H "Report-Message: <message>" to report a particular token

The API key in the Authorization is account specific and should not change unless a specific support request is made to request its rotation. The API key only allows the decoding of tokens and obtaining additional token information and does not enable any other actions on the account. However, as with any account credential, steps should be taken to keep it secured and to prevent accidental disclosure or inclusion in source code repositories.

You should provide an issued Approov token to the API endpoint, for example:

$ curl -X PUT -H "Authorization: Bearer xxx..." -H "Approov-Token: eyJh..." https://<account-domain>/token-info/
{
  "did": "qZka0yfv+ExvOq3PRh6pGw==",
  "status": "failed",
  "claims": {
    "arc": "B3Y5SLMO2K",
    "did": "qZka0yfv+ExvOq3PRh6pGw==",
    "exp": 1607528162,
    "ip": "1.2.3.4"
  },
  "expiryTime": "2020-12-09 15:36:02 UTC"
  "deviceProperties": [
    "app-not-registered",
    "rooted",
    "root-risk",
    "xposed"
  ]
}

The status indicates if the attestation was passed or failed. If the provided token was issued to a different account then the status is likely to be arc invalid (and if it does happen to be valid it will not report the correct decoding). The did property provides the Device ID. The full set of token claims are provided, even if the Approov token is an encrypted JWE. The expiryTime provides a readable form of the expiry time of the Approov token. Note that, the tokens you provide may have expired and this will not impact their status or the ability to decode them.

The deviceProperties lists the device property flags that have been determined from the device. If the status is failed then this will almost certainly pinpoint the reason(s).

Note that although the syntax is provided for curl for your convenience, any standard tool or mechanism can be used to perform the PUT request to the endpoint.

This API is for the use of your backend systems only. Never build calls to this API into your mobile app and, especially, never expose the Authorization key.

You should never use this endpoint to check the validity of the token. Always check validity by verifying the signature of the Approov token directly. This endpoint should only be used for informational purposes on a subset of received tokens; it may be subject to rate limiting and does not have the Cloud Server Redundancy features of the Approov token issuance service.

Reporting Token Misuse

The Token Information endpoint provides an optional facility to report the misuse of particular tokens. This endpoint can be used in conjunction with Approov support to allow automatic reporting of tokens that appear to be being misused in some way. This may be because you have reason to believe that a valid Approov token is being issued when it should not have been. Alternatively, if you believe that the Approov token has been somehow extracted from a running app and is being used to make API calls outside of the official app then these should be reported.

You should include a short message (256 characters or less) describing the issue in the Report-Message header for the request, for example:

$ curl -X PUT -H "Authorization: Bearer xxx..." -H "Approov-Token: eyJh..." -H "Report-Message: Expected a token fail on this device, contact ops@your.domain" https://<account-domain>/token-info/
{
  "did": "qZka0yfv+ExvOq3PRh6pGw==",
  "status": "failed",
  "claims": {
    "arc": "B3Y5SLMO2K",
    "did": "qZka0yfv+ExvOq3PRh6pGw==",
    "exp": 1598608042,
    "ip": "1.2.3.4"
  },
  "deviceProperties": [
    "app-not-registered",
    "rooted",
    "root-risk",
    "xposed"
  ]
}

Token reports are automatically forwarded to Approov support and they will be notified at the end of day in which the report is made. Unless you are already in dialogue with Approov support about this issue, we suggest you include email contact information in your report message. Approov support will analyze the information provided, and may gather more information from the specific device reported, and will respond with some additional diagnosis of the issue.

Token reports are rate limited, typically restricted to one per minute. If you exceed the rate limit then the API will return Ok but the report will not be forwarded to Approov support. Note also that subsequent token reports are ignored if they are issued on the same day and about the same device ID.

Checking Token Validity

A checking option is provided that allows any Approov token to be checked. This is useful for debug purposes during your integration with Approov. Simply use:

$ approov token -check eyJhbGciOiJIUzI1Ni…
failed: expired alg:HS256 {"anno":["app-not-registered"],"did":"h4gubfCFzJu81j/U2BJsdg==","exp":1558626228,"ip":"1.2.3.4","pay":"6ZIvH1YelZyc2hx1iRRqD3dWNcFgjVtCon+7921XDjg="}

The Approov token content is decoded, and information is provided about whether the token is passed or failed. For a JWS it also shows if the token has expired or not. Remember that expiry and signature validity are independent. The validity of a token (i.e. whether it is signed with the account secret key) depends on whether the request came from a valid app instance and also the security policy in place in the account. The expiry is purely related to how long ago the token was issued. Tokens normally only have a 5 minute lifetime.

The signing algorithm of the token (alg) is also shown, as well as any key ID (kid) in the token.

The content of the decoded token will depend on other Approov features that are being used. This particular token is issued from an account with a non-default annotation policy, that provides some reasons why a token may be invalid, in the anno claim. It also has a pay claim as a result of using setDataHashInToken.

Note that if Attestation Response Codes are enabled for the account then this command will also provide a list of the device property flags associated with the device to which the Approov token was issued.

Note that the token check is also able to process encrypted JWE tokens. It shows if they are valid and can decode their content, even if they are invalid.

Loggable Tokens

It is generally not recommended to log Approov tokens within an app. This is because it might be possible for an attacker to turn logging on in a production app and use this as a mechanism to steal valid Approov tokens that have been received. Furthermore, the raw Approov tokens are also very opaque since they are just base64url encoded JWT strings and therefore not very useful for debugging.

Loggable tokens are output in the logging generated by the Quickstart Frontend Integrations. They provide a decoded string form of the Approov token, and is therefore much more useful for debug purposes. The returned string holds a JSON object containing the payload contents with an additional sip claim, as demonstrated by the following example:

{
  "anno": [
    "app-not-registered"
  ],
  "did": "h4gubfCFzJu81j/U2BJsdg==",
  "exp": 1558626228,
  "ip": "1.2.3.4",
  "pay": "6ZIvH1YelZyc2hx1iRRqD3dWNcFgjVtCon+7921XDjg=",
  "sip": "HggK-u"
}

Note that if no valid token was returned from the Approov token fetch request, or the returned token was a JWE, then a marshaled JSON string giving the error is provided, e.g.:


{
  "error": "POOR_NETWORK"
}

{
  "error": "JWE"
}

As mentioned, a loggable token includes a special sip claim. This contains the first few characters of the signature of the token. Six characters are provided in base64, giving 36 bits out of the 256 bits provided in the complete signature. Thus it is not sufficient to create a validly signed token, but, if the signing key is known, it is sufficient to check, with a very high degree of accuracy, whether an Approov token is valid. Note that app itself never knows the symmetric secret used for signing tokens. Its possible to check a loggable token in the same way as a JWT as follows:

$ approov token -check '{"anno":["app-not-registered"...'
failed: loggable

Note that the loggable token must be enclosed in single quotes so that it is treated properly as a single command line parameter.

A statement is provided about whether the token was valid or not. It does this by reproducing the complete Approov token on the cloud service with the correct signature and then checking this against the prefix part of the signature that it knows from the sip.

The sip claim cannot be used to determined token validity if the token was signed with a the probabilistic signature scheme. Probabilistic schemes include keyset key that use one of the following algorithms: PS256, PS384, PS512, ES256, ES384 or ES512. For these algorithms the loggable token will always be interpreted as a fail.

If you are using a version of the SDK prior to 2.2.0 and have enabled Key IDs, attempting to get a loggable token will result in a BAD_JWT_HEADER error.

Long Lived Approov Tokens

It is possible to generate Approov tokens that have a long expiry time. Approov tokens issued via the Approov SDK only have an expiry time of 5 minutes or less. This facility allows tokens for an arbitrary duration to be created. It requires an admin role. To create one use:

$ approov token -genLongLived server-token,90d
token will expire at 2019-06-03 13:24:38
WARNING: Long lived token should never be integrated into public clients and their security must be carefully managed
eyJhbGciOiJIUzI…

This generates an Approov token that is valid for 90 days. The server-token parameter is included in the iss claim of the token. Change this to whatever name you would like. It can be used to identify particular long lived tokens, or even to revoke certain ones by backend API checking. In effect this claim could be used as a type of API key within the overall signed Approov token. The expiry time should be specified in days and cannot be less than 1 day.

The generated Approov token can be checked and decoded as follows:

$ approov token -check eyJhbGciOiJIUzI…
passed: alg:HS256 {"exp":1567078473,"iss":"server-token"}

Long lived tokens can be used to authorize communication to the protected backend API for server-to-server communication and test environments (such as Postman). This allows a particular API to be accessible both from mobile apps and also via other servers without having to create a different authorization mechanism. Generating a long lived token has no impact on the expiry time of tokens issued normally through the Approov SDK.

Long lived tokens must never be included in public clients, such as web pages or mobile apps. They should only be used in circumstances where the token can be protected in a server environment.

Long lived tokens cannot be generated for restricted domains, such as shapes.approov.io demo endpoint. Moreover, it is only possible to generate long lived JWS tokens signed with the account secret key. It is not possible to create tokens signed with a keyset key.

IP Tracking Policy

The IP tracking policy determines how Internet Protocol addresses are dealt with in your Approov account. When your account is setup the policy will be token. This means that the IP address of the device requesting an Approov token will be included in the token itself in the ip claim. However, in accordance with Approov’s privacy notice, no record will be kept of the IP address in Approov’s internal logs or records. This is because IP addresses can be considered to be Personally Identifiable Information (PII) and the Approov service does not collect this by default for an account holder’s end customers. IP addresses are only stored by Approov services after transformation through a one-way hash function from which the original IP address cannot be recovered.

If desired the IP tracking policy can be changed to none so that the IP address claim is not even included in the issued Approov token.

$ approov policy -setIPTracking none
WARNING: updating the IP tracking policy will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
IP tracking policy was set successfully

An admin role and confirmation is required to make an IP tracking policy change.

A policy of full is also available whereby permission is given for Approov services to record unhashed IP addresses. This allows more sophisticated correlation analysis between IP addresses and device characteristics, carried out in conjunction with Approov support. Note, however, that if this option is used then the Approov service is collecting PII on your behalf and this may have GDPR implications.

The current IP tracking policy can always be retrieved as follows:

$ approov policy -getIPTracking
IP tracking policy is none

Audience Inclusion

The audience inclusion feature allows the aud claim to be populated in all Approov tokens issued for the account. This will be set to the domain name for which the Approov token was issued. This can be useful to ensure that tokens issued for one domain cannot be used to gain access to a different domain that shares the same signing secret key. This needs to be checked by the backend API integration.

The audience inclusion feature can be enabled as follows:

$ approov policy -setAudience on
WARNING: updating the audience policy will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES

An admin role and confirmation is required to make an audience policy change.

The current audience policy can always be retrieved as follows:

$ approov policy -getAudience
audience policy is on

Note that wildcard tokens are issued with an aud claim of *.

Issuer Inclusion

The issuer inclusion feature allows the iss claim to be populated in all Approov tokens issued for the account. This will be set to the name of the account suffixed with approov.io. This is useful as an additional verification if signing keys are being shared between multiple accounts. The backend API integration is able to verify that the token was issued for the expected account.

The issuer inclusion feature can be enabled as follows:

$ approov policy -setIssuer on
WARNING: updating the issuer policy will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
issuer policy was set successfully

An admin role and confirmation is required to make an issuer policy change.

The current issuer policy can always be retrieved as follows:

$ approov policy -getIssuer
issuer policy is on

Backend Integration

This section describes the changes that are needed in the backend API to check that an Approov token is valid.

This section provides a detailed reference for backend integrations. If you able to use one of our Quickstart Backend Integrations then you may find this simpler.

Requirements

To protect a backend API with Approov it is necessary to check that incoming requests have a valid Approov token. This might be required on all endpoints or just on some that demand additional security. Typically, token checking will be performed in some middleware layer of the backend rather than be implemented in the business logic.

Approov token checking is often performed in addition to user authorization, as an orthogonal activity. User authentication and authorization ensure that a known user is invoking the software making the request. Approov checking ensures that the software making the request is actually what it claims to be.

Approov uses standard JWTs as discussed in the previous section. This makes the backend API checking straightforward since almost all backend languages and technologies support JWT checking. To check an Approov JWS, the account secret key must be made available to the backend code. The token will be signed with the HS256 profile, and the shared symmetric account secret key is needed to perform the check. Libraries for working with JWTs are available in most common languages, with many listed on the JWT homepage.

There are essentially three cases which should cause a request to be rejected:

  • Invalid Token: If the Approov token is simply missing or is not a correctly formatted JWT then this indicates some spoofed request and should be rejected.
  • Incorrectly Signed Token: If the token is not correctly signed then it must be rejected. Obviously an attacker can synthesize an incorrectly signed token. An app is also provided with an incorrectly signed token if the attestation has been rejected. Note it is important to ensure that the signing method of the JWT is HS256.
  • Expired Token: Any token that has expired must be rejected, as under normal operation this should never happen. The app should never cache the Approov token, and the Approov SDK never provides a token that has expired. A small grace period is built into the token lifetime to allow for transmission and propagation delays in the backend systems. It is important to make sure that the server checking the tokens is correctly time synchronized.

Note that the actual behavior for an invalid token does not have to be rejection, although this is the typical approach. An invalid token event could simply be used for logging or as a signal to require some additional authentication and security checks on a particular user.

We recommend that the backend integration has a dynamic facility to enable or disable the Approov token check. This allows traffic to be passed through without the check in case of some emergency situation. Moreover, you may wish to collect logging for events where invalid Approov tokens are being provided.

Account Secret Key Export

The account secret key can be obtained with the following command:

$ approov secret -get base64
note: secret is base64 encoded and must be decoded to its binary form to verify Approov tokens
dEitzKUYJLQ…

An admin role required to gain access to the account secret key.

This example displays the secret as a base64 encoded string, representing a 512-bit value that is randomly assigned to the account during signup. The value of the secret must be protected with extreme care. The number of individuals with exposure to the value of the secret should be minimized and it should never be checked into a source control system. Ideally, it should only be made available to the runtime environment of the backend servers. Note that if base64url is used as a parameter to the command then the secret can be obtained in base64url encoded format, which may be needed by some backend integrations.

Note that it is also possible to obtain the secret in raw form, as discussed here.

If you wish to output the secret value, with no additional text, you may use the -plain option. This allows the output to be easily piped into other command line tools, so that generic scripts can be easily developed that extract and operate on the account secret key. Of course, you should never include your administration token in such a script directly.

If you wish to export the secret key that is used for JWE tokens (of the account type and using the A256GCMKW algorithm) then the -jwe option can be used as follows:

$ approov secret -jwe -get base64
note: secret is base64 encoded and must be decoded to its binary form to verify Approov tokens
1bgyVw6/9X6...

Account Secret Key JWK Export

The account secret key may also be exported in JSON Web Key (JWK) format as follows:

$ approov secret -getJWK secret.jwk
JWK written to file secret.jwk

This writes the JWK to the file secret.jwk as follows:

$ less secret.jwk
{
    "kty": "oct",
    "use": "sig",
    "k": "dEitzKUYJLQ…",
    "alg": "HS256"
}

The JWK format is useful for certain backend systems that accept this format directly. Usage with JWKs is also often associated with the requirement for a Key ID property in tokens. This needs to be set prior to getting the JWK so that the kid property is listed.

It is also possible to export it in the JSON Web Key Set format, for systems that require that format. In this case the single account secret key is included in the keys map.

If the -jwe option is used then the secret key used for JWEs is provided, rather than the one for JWSs.

Generating Example Tokens

It is possible to generate example Approov tokens that have the same format as those generated for a mobile app. For example:

$ approov token -genExample my.api.io
eyJhbGciOiJIUzI1N…

The API domain, for which the token is being generated, must be provided. The result is a valid token that lasts for one hour. The extended expiry time of these tokens provides for longer debug sessions using a single token. For example, the token can be used in synthetic queries made to a backend API to check that it is working correctly. There is no need to know the actual account secret key to use this facility as the token is automatically signed with the correct secret.

If an API domain is provided that has not been added for the account then no token can be generated. If the API domain is associated with encrypted JWE tokens then one is generated, to allow verification of the JWE decryption logic in the backend.

The example tokens contain a fake IP address and device ID that are in the correct format. A -setDataHashInToken option is also provided for testing the Token Binding feature. You can decode the example Approov token to see what it contains:

$ approov token -check eyJhbGciOiJIUzI1N…
passed: alg:HS256 {"did":"ExampleApproovTokenDID==","exp":1558980988,"ip":"1.2.3.4"}

By default a valid Approov token is generated. But it is also possible to generate an invalid token to test the backend API handling with such tokens. For instance:

$ approov token -genExample my.api.io -type invalid
eyJhbGciOiJIUzI1N…
$ approov token -check eyJhbGciOiJIUzI1N…
failed: alg:HS256 {"did":"ExampleApproovTokenDID==","exp":1558981918,"ip":"1.2.3.4"}

Changing the Account Secret Key

The account secret key can be changed with the following command:

$ approov secret -change
WARNING: updating the account secret key will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES

This requires an admin role and a confirmation of the operation. If confirmed then the new account secret key value is output as follows:

new base64 encoded account secret key is VcXl2IgVUgz…

If the account secret key is changed then this has an impact in production within 30 seconds for newly issued tokens. This means that for a period of up to 5 minutes the backend API may see a combination of tokens signed with the old secret (if they have been cached and reused by the app SDKs) and new ones signed with the new secret (for freshly obtained tokens).

In general it is hard for a backend integration to deal with two different secret values, so we recommend the following procedure if rotating the account secret key:

  1. Disable Approov token checking on the backend API. This will let any traffic through for a short period of time,
  2. Execute the command to update the account secret key and copy the new value.
  3. Integrate the new account secret key into the backend API.
  4. Re-enable Approov token checking. Assuming this process takes more than 5 minutes, all tokens in use will be using the new account secret key.

Raw Account Secret Key

There are certain specific backend JWT checking libraries that require the secret to be specified as a raw string (they have no facility to provide it in an encoded form such as base64). To support this, a feature is provided to get the secret in its raw format. However, the initial secret generated for your account will almost certainly contain some bytes that are not printable and therefore cannot easily be added to a string. Thus, if you need the secret in its raw form, you must first change it and include the special -forcePrintable option as follows:

approov secret change -forcePrintable

It is then possible to obtain the raw secret value as follows:

approov secret -get raw

Use of this option reduces the entropy of the secret and so you should only use this facility if there is no option but to use a JWT library that requires the secret in this format. Typically you should specify the secret in an encoded format rather than a raw string.

Public Key Pinning Configuration

It is essential that all of the channels over which Approov tokens, or secure strings protected with Approov, may be transmitted use pinned connections. This means that the app should only be willing to establish a TLS connection where the presented certificates are both valid and where at least one public key of a certificate in the chain is specifically pinned, by the app itself, as being valid. This will happen automatically if you have used one of our Quickstart Frontend Integrations.

Managing Pins

Any API domain can have a list of pins expressed as subject public key info hashes in base64. A pin is considered to have passed if any part of the certificate chain includes one of the pins provided. Thus intermediate public key pins are supported. Backup pin(s) can also be included if desired. As discussed in Dynamic Pinning, these updated pins are pushed out automatically to running apps.

Facilities are provided for extracting the public keys of certificates directly from files, or live from existing endpoints. Extracting pins from certificate files allows backup pins to be added to APIs before the associated certificate goes into production, thus allowing certificate update flows with no down time.

If the app is able to receive a new configuration update and immediately change the pins being used, then the update need only occur early enough that any prior Approov fetch will have received the configuration revision. This only needs to be 5 minutes. In other cases, where the app cannot immediately update its pins on receipt of a new configuration, then a longer time period is required. This will depend on the circumstances in the app but it is generally advisable to push out a new configuration some days ahead of the actual change.

Note, once a change has been completed, any redundant pins can be removed causing another new configuration to be issued. The timing on this second update is less important as the new pin is already deployed and in active use, however, if pins were rotated due to a breach then you will need to make this change as soon as the new certificate is deployed to prevent the old pin from being trusted.

Managed Trust Roots

In addition to explicit pinning, Approov also has a managed trust roots facility that can be used instead of explicit pins. This is primarily for cases where the backend API is outside the control of the frontend app developer. In this case the public key pin of the presented certificate could be changed at any point. Moroever, the issuing certificate authority and therefore the root certificate could also be changed at the time of renewal or indeed at any time.

To deal with this situation, Approov provides a set of trusted roots with the same set of certificate authorities typically trusted by the iOS and Android system trust stores. The set of trusted roots is managed by Approov and can be dynamically updated in the same manner as individual dynamic pins. If any individual root certificate is revoked then Approov removes it from the trusted set and the update will be picked up by all apps on their next attestation. Approov monitors the iOS and Android system trust stores for changes and updates the Approov managed trust roots appropriately.

In the app, the trusted roots set is enforced in addition to the trust store on the device itself. A root certificate has to be present in both sets for a connection to be established. This is a valuable feature, as the typical approach to allow use of a Man-in-the-Middle (MitM) proxy is to install a self signed certificate into the system trust store of the device (either on an emulator or a rooted/jailbroken device). Such an installation allows MitM to take place since the device is entirely reliant on the contents of its trust store. Conversely, with managed trust roots enabled, this style of attack is prevented because the self signed root certificate cannot be added to the Approov managed trust roots and therefore any connection attempts with the MitM proxy certificate will be rejected. Any connection to a certificate in a chain to a legitimate root authority will still be accepted.

Managed trust roots are not enabled by default. To enable them use:

$ approov pin -setManagedTrustRoots on
WARNING: updating the managed trust roots policy will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
managed trust roots policy was set successfully

An admin role and confirmation is required. Managed trust roots can be disabled using off.

It is possible to get the status of managed trust roots at any point using:

$ approov pin -getManagedTrustRoots
managed trust roots policy is on

Managed trust roots require some changes to the pinning management logic for Approov quickstarts. You must only enable this if using a quickstart designed for a 3.0.0 SDK or later.

When managed trust roots are enabled, additional pins are provided to the app in the dynamic configuration under the * domain name. This allows the trusted root set to be provided only once, even if they are to be used for multiple API domains. This additional set is used by the pinning implementation in the app in the following way:

  1. The pinning implementation checks for pins associated with the specific domain; if they are defined then they are used as the only accepted set of pins.
  2. If there are no pins defined for a domain, then the implementation uses the set associated with the * domain. If there is a match for the pins in the * domain then it indicates that the presented certificate chain leads to a trusted root certificate.

This approach allows a mixture of API domains that use specific pins and domains using the managed trust roots.

Enabling managed trust roots changes the default behavior when adding new API domains. While disabled, the default for adding a new API is to perform a domain lookup to calculate the pin for the active certificate and then use that pin as the sole entry for the domain. If managed trust roots are enabled, then no lookup is performed and instead the new API is added with no pins, meaning that the pinning implementation in the app defers to the managed trust roots associated with the * entry.

After an API is added, you can always modify the set of associated acceptable pins. If you add a pin to an API that has none, then it will switch from using the managed trust roots to only accepting the specified pin. If you remove the last pin associated with an API then it will switch from requiring a specific pin to using the managed trust roots.

Disabling managed trust roots while some domains have no specific pin configuration will leave those domains relying solely on the system trust store and therefore potentially exposed to MitM attacks.

Pinning For New API Domains

You can add a new API to your set of APIs with your default configuration with the following command:

$ approov api -add your.domain
WARNING: adding the API will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
added API domain your.domain with type:account, alg:HS256, pin:JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU=
enabled continuous monitoring for https://your.domain:443 (remove using `approov monitoring -removeAPI`)

The above listing shows the output in the default case when managed trust roots is disabled. In this case, a pin for accessing that domain is automatically added. The pin is extracted from the leaf certificate presented by the domain’s server. You can modify the pins associated with the domain using the commands presented later in the section.

If managed trust roots is enabled, then no pin is added to the domain: the command behaves as if the -pinType none flag was provided as shown below. In this case, channel security is provided by ensuring that the connection certificate root is both in the system trust store and the Approov managed trust roots set. We recommend using explicit pins where possible, see the managed trust roots section for more details.

We strongly advise you to implement pinning (or managed trust roots) for the API domains you access in your app. This means that any communication with this particular domain will be pinned to the permitted certificates. In some cases it might not be appropriate to pin to the leaf certificate value, perhaps because different certificates may be presented by different servers on the endpoint. You must verify the stability of the provided pin with the backend API implementation team before going into production. If the pin changes, then your app will no longer work until a new set of pins can be pushed out using the dynamic configuration update mechanism.

It is possible to change the pin type so that no pin is added at all with the new API domain (this is the default behavior when using managed trust roots):

$ approov api -add your.domain -pinType none
WARNING: adding the API will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
added API domain your.domain with type:account, alg:HS256, unpinned

Unless managed trust roots is enabled, a domain with no pin relies on the integrity of the system trust store to ensure connections are secure. This can leave your app vulnerable to MitM attacks.

When a leaf pin is being collected, it is obtained from both a local network request and via a network request from the Approov cloud servers. The pin obtained must match, or else an error is generated, for example:

$ approov api -add your.domain
domain your.domain local pin 1O0wDRM/roe6UTctDVQ5aN/ASNYsGQFVzXYhO34t5GE= differs from remote pin OfxtkIyzmWFXb028KrIr3VqP0XHW41mbunxtNnS3eb4= (may be due to local firewall)

This means that the observations differ. This might indicate that the leaf certificate obtained is not deterministic, or may depend on the geographic location from where the request is made. Alternatively, it might just mean that the local network is subject to interception via a firewall (this can be checked with the approov pin -api <domain> -getCertChainPins command which obtains the full certificate chain obtained from a local request).

If you are confident that either the localor remote public key pin is the one required then the appropriate one can be selected using the -pinType option, e.g.

$ approov api -add your.domain -pinType remote
added API domain your.domain with type:account, alg:HS256, pin:OfxtkIyzmWFXb028KrIr3VqP0XHW41mbunxtNnS3eb4=
enabled continuous monitoring for https://your.domain:443 (remove using `approov monitoring -removeAPI`)

This selects the remote public key pin. Note that of course this means that the mobile app will not be able to run on the local network.

When you add new APIs, or change the pins on existing APIs, a new pinning configuration is automatically sent to your running apps when they connect to the Approov servers.

Managing Domain Pins

Once a particular domain has been added it is then possible to add or remove pins on that domain. An individual domain may have up to 10 different pins specified for it. A connection attempt for domain is considered to be successful if any of the specified pins is present at any level in the certificate chain obtained from the API domain server. Thus leaf and intermediate certificate pins may be specified, along with backup pins which may not yet be in service. Note that if no pins are specified for a domain then this means it is unpinned and any certificate (presuming it meets the normal criteria) is deemed acceptable.

You can add a pin to a domain with the following command. The pin value itself may have been extracted using one of the methods discussed in the following sections. For example:

$ approov pin -api your.domain -add Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk=
WARNING: updating the pins will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
pin Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk= added to API domain your.domain

Note that you need an admin role to modify the pins. You can see the pins set for any domain as follows:

$ approov pin -api your.domain -list
Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk=

Finally, specific pins can be removed as follows:

$ approov pin -api your.domain -remove Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk=
WARNING: updating the pins will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
removed pin Q62DnTGJsy1h+ude8HB5ZjKy0Vhg2pvTzjplWSD3hkk= from API domain your.domain

Any attempt to change the pins for the demo endpoint shapes.approov.io result in an error.

Leaf Public Key Pin Extraction

The public key pin for a leaf certificate presented on a particular domain may be obtained as follows:

$ approov pin -api shapes.approov.io -getLeafPin matching
matching leaf pin for domain shapes.approov.io:443 is JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU=

This obtains the same pin that would be obtained by the -addoption described above. The possible values for the parameter are as follows:

  • matching: Ensure that there is a matching pin between the local network access and remote observation by the Approov servers.
  • local: Obtain the pin value as observed on the local network.
  • remote: Obtain the pin value as observed remotely by the Approov servers.

Note that if the endpoint being accessed is not on the standard port of 443, the -port option can be used. Here is an example that gets the leaf pin as observed by the local machine on port 8000:

$ approov pin -api your.domain -getLeafPin local -port 8000
local leaf pin for domain your.domain:8000 is 0vNoWx4vRXJCQggeFuEx6/5yyhXVl/VScIN18PmL7co=

Only a single set of pins can be associated with a particular API domain, independently of the port that is being used. If the application uses multiple different ports on the same API domain, associated with different pins, then the overall domain only needs to be added once and the set of pins for it should be the union of all those required on the different ports.

Intermediate Public Key Pin Extraction

In some cases you might not want to pin against a leaf certificate but, instead, choose to pin against an intermediate certificate within the whole chain presented on a domain. A command is provided to extract this information:

$ approov pin -api shapes.approov.io -getCertChainPins
pin JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU=, expiry 2020-05-22, CN=shapes.approov.io
pin JSMzqOOrtyOT1kmau6zKhgT676hGgczD5VMdRMyJZFA=, expiry 2025-10-19, CN=Amazon,OU=Server CA 1B,O=Amazon,C=US
pin ++MBgDH5WGvL9Bcn5Be30cRcL0f5O+NyoXuWtQdX1aI=, expiry 2037-12-31, CN=Amazon Root CA 1,O=Amazon,C=US
pin KwccWaCgrnaw6tsrrSO61FgLacNgG2MMLq8GE6+oP5I=, expiry 2034-06-28, CN=Starfield Services Root Certificate Authority - G2,O=Starfield Technologies\, Inc.,L=Scottsdale,ST=Arizona,C=US

This shows the full chain of certificates. In this example we use our demo endpoint shapes.approov.io that is hosted with AWS and uses an AWS issued certificate. You can see the chain right up to Amazon’s root certificate. Notice that certificates higher in the chain tend to have longer expiry times. Depending upon your particular backend setup it may be better to pin to one of these certificates rather than the leaf, which is more subject to change. Of course you need to ensure that any certificate you pin to cannot itself be used to sign certificates that an attacker might use. So, in general, try and pin as low in the overall chain as is practicable.

Note that if the endpoint being accessed is not on the standard port of 443, the -port option can be used to obtain the certificate chain on the specified port.

Note that the certificate chain is determined by making a local request. If the local network has a firewall that intercepts TLS traffic, then the resulting chain will not be the same as one observed by a device outside that network. Also be aware that, depending upon the backend API architecture, the observed chain may be influenced by the specific server that responds to the request. For example, different geographical regions may supply different certificates.

Certificate File Pin Extraction

As well as getting the public key pin from a live endpoint, it is also possible to get a pin from a certificate file. This is useful when you want to add a pin to a certificate that is not yet in service. Use the following to get the pin:

$ approov pin -getCertPin your-cert.crt
pin jZetC3373f9dmwxg5YE9TCZzl4MYvp0eYTiEsbcTU34=, expiry 2022-05-10, CN=your.domain

This provides the public key pin along with the expiry time and subject of the certificate. Note that, to use this option it is necessary to have a PEM encoded certificate file. This is normally associated with a .cer, .crt or .pem file extension.

Certificate Pins From a Device

It is possible to obtain the set of pins seen by the SDK in a particular device using the Managing Devices capabilities.

Firstly you need to set the device ID from which you wish to capture the certificate information. To obtain the ID see Extracting the Device ID. A probe URL is specified that must include https and may optionally include a port number as shown:

$ approov device -add qZka0yfv+ExvOq3PRh6pGw== -probeURL https://shapes.approov.io:443
successfully set device qZka0yfv+ExvOq3PRh6pGw==

The next time the device fetches an Approov token it will also probe the specified URL and obtain the information about the certificate chain. Remember that the device must obtain a new Approov token to do this, so if it has already obtained one then it can be up to 5 minutes before it expires.

The device information can then be obtained as follows, and this should include the probe result information (other information has been elided here):

$ approov device -getInfo qZka0yfv+ExvOq3PRh6pGw==
captured: 2020-07-23 09:54:46 BST
... 
probe-result:
  probe result for https://shapes.approov.io:443:
   dqP5GOntRqZST5GfBj8NGpr1GMUTeKZG5g6+Q5mZFYM=: CN=shapes.demo.approov.io
   YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=: CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US
   Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=: CN=DST Root CA X3,O=Digital Signature Trust Co.

This is the full set of certificate pins in the chain and the subject information of the certificate. The individual pins can be added via Managing Domain Pins.

This option of extracting the pins live from a running device is useful for pin debugging purposes, or network topologies where it is not practical to run the approov command line tool on the same network as the device and the network is not accessible via remote pin probing from the Approov cloud services. This might be the case if you are deploying Approov in a private network environment.

Checking API Configuration

An option is provided that checks that all of the specified API domains are accessible and that, if pins are provided, then they do actually match a certificate being presented for the domain. This can be used as a quick check that the API configuration that is currently set is valid. It is invoked as follows:

$ approov api -check
your.domain:
  no pins defined
shapes.approov.io:
  certificate chain:
    dqP5GOntRqZST5GfBj8NGpr1GMUTeKZG5g6+Q5mZFYM= CN=shapes.demo.approov.io
    jQJTbIh0grw0/1TkHSumWb+Fs0Ggogr621gT3PvPKG0= CN=R3,O=Let's Encrypt,C=US
  pins:
    dqP5GOntRqZST5GfBj8NGpr1GMUTeKZG5g6+Q5mZFYM=
  matched pin dqP5GOntRqZST5GfBj8NGpr1GMUTeKZG5g6+Q5mZFYM=

The current API configuration is obtained from the Approov cloud service, and then each of the domains is checked from your local machine. If monitoring is enabled for the API domain then any port specified for that is used for the access. If the API domain is not accessible then that is considered an error.

If pins are defined for a particular API domain then the certificate chain observed is shown, along with the list of pins that are defined for the domain. If there is a matching pin then that is also listed.

The command has a return code of 0 if it succeeded or 1 if it failed. Note that if the user role is invalid, or the Approov cloud service cannot be contacted, then this is not considered a failure since the explicit purpose of the command is to check the API endpoints themselves.

Testing the Pinning Implementation

It is important that any pinning implementation is tested, by forcing the app into situations where the pins are incorrect with respect to the certificates being presented on the API endpoints. It is necessary to show that this is handled correctly and, importantly, that dynamic configuration updates issued from the Approov cloud update the app’s pins correctly.

In production it would be undesirable to change the certificates on the real API endpoints to do the testing as this would impact all app users. To avoid the need to do this, Approov provides facilities to modify the set of pins provided to a particular device being tested. These facilities are discussed in detail in the Managing Devices section. The idea is that for a particular device the pins can be set to a known bad value that will trigger the pinning exception so that it can be tested, i.e. Approov changes what the app is pinning against rather than what is being presented by the API endpoint. This is an equivalently good test.

The following is a recipe of commands to perform a test on your pinning implementation. Firstly you will need to get the ID of your device, see Extracting the Device ID. You should then check that the app is operating normally and that you have pins defined for the endpoints you are trying to protect with pinning. You can check what pins are set using Getting Pin Configuration.

Next, you can block all of the communication by forcing bad pins to be downloaded as a dynamic configuration for your app. For example:

approov device -add h4gubfCFzJu81j/U2BJsdg== -pinMode block

Note that nothing will happen until the next Approov fetch is made. An existing token may have a lifetime of up to 5 minutes. A new dynamic configuration should then be received. You may be able to see this in the app’s logging. How quickly your app can respond to this update will depend upon the app’s architecture. Once the update has been actioned, you should see an appropriate error from your app when it attempts to make API calls. We suggest you go through this whole process without exiting the app.

You can then simulate what would happen to your running app if a new set of valid pins are transmitted to your app via a dynamic configuration update:

approov device -add h4gubfCFzJu81j/U2BJsdg== -pinMode pin

This sets the pins back to the default for the account. Once any currently fetched Approov token has expired (up to 5 minutes) a dynamic configuration update is transmitted to the app. Depending on the pinning implementation, this might have an immediate impact or after some time if the pins can only be rebuilt then. If your app’s pinning implementation cannot rebuild the pins until the app is restarted then it should provide a user message to that effect.

It is vitally important that you test that your app is able to recover from having incorrect pins to correct ones via a dynamic configuration update. This is the process that your app must successfully follow should there be a need to supply new pins to your app over-the-air.

It is also possible to block all app communication, including that between the Approov SDK and the Approov cloud as follows:

approov device -add h4gubfCFzJu81j/U2BJsdg== -pinMode blockAll

In this case you will receive a MITM_DETECTED error from fetch attempts. This will allow you to check the handling of this in your app.

Continuous Pinning Testing

Pinning relies on the underlying http stack implementation, that is part of the device OS, to implement it. If this underlying implementation is compromised then it is possible that the pinning is not actually restricting TLS connections in the way intended, and potentially allowing an attacker to MITM connections. Approov incorporates various detections of modifications to the runtime environment that may allow such a compromise to occur. In such cases the device will typically not be issued with valid Approov tokens. However, if a particularly lax rejection policy has been selected then there is a danger that such underlying tampering could be occurring whilst valid Approov tokens are issued.

Thus an additional pinning verification mechanism is provided. This allows an arbitrary URL to be specified. The SDK attempts to connect to this the very first time a new app installation tries to fetch an Approov token. The fetch uses the underlying pinning mechanisms of the device OS and specifies a pin that will not be present. Thus the connection attempt should fail. If it succeeds then it indicates that the pinning mechanism has been compromised in some way. If this happens then the app installation will never be issued valid Approov tokens.

Set the URL to be used as follows:

$ approov pin -setPinningTestURL https://your.domain:443
WARNING: updating the pinning test URL will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
pinning test URL was updated successfully

The URL should be specified as a full URL with https and may optionally include a port number. This URL should be something that it is possible to perform a successfully http GET operation upon and obtain a 200 OK response. The URL should also not result in a redirect. If the URL is not valid then approov tool will issue a warning. The idea is that if SDK is able to perform this GET, despite the pinning restriction, then this is the trigger to mark the app as being compromised.

We recommend that the URL is one of the key API backend domains that your app uses and is protected using Approov.

You will be able to see devices that have compromised using the pinning-tampered device property flag.

You can see any URL that has been set as follows:

$ approov pin -getPinningTestURL
https://your.domain:443

Finally you can remove the URL at any point using:

$ approov pin -removePinningTestURL
WARNING: updating the pinning test URL will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
pinning test URL was updated successfully

This feature is only supported with SDKs that are version 2.4.0 or later. Earlier version SDKs will not perform the check.

Getting All API Configuration

The complete set of API domains and the pins that have been added to the account can be extracted into a JSON format file as follows:

$ approov api -getAll apis.json
API domains and pins written to JSON file apis.json

This command gets all of the API attribute and pin information and writes it to the apis.json file. In this example the content is as follows:

$ less apis.json
{
  "your.domain": {
    "secretType": "account",
    "algorithm": "HS256",
    "pins": [],
    "monitorPort": 443
  },
  "shapes.approov.io": {
    "secretType": "restricted",
    "algorithm": "HS256",
    "pins": [
      "JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU="
    ]
  }
}

This shows that Approov tokens can be issued either for your.domain or shapes.approov.io.

The attributes for each domain in the format are as follows:

  • secretType: The type of the API domain, primarily defining where the signing or encrypting secret key is obtained. Options are account, keyset, restricted or none.
  • allowWeb: This is an optional boolean flag that is only shown if true. It indicates that the API domain may have web protection Approov tokens fetched for it.
  • algorithm: Provides the type of signing or encryption algorithm for the API domain (or empty for none).
  • kid: This is optional and provides any key ID for tokens issued for the domain. This is always present for the keyset type.
  • pins: The list of valid pins for the domain. Empty indicates that no pinning is applied.
  • monitorPort: If contiuous monitoring is enabled for the domain then this specifies the port being used (normally 443).

Setting All API Configuration

API configuration may be set in the same format as that obtained with the API -getAll option. New domains may be added, removed or edited. For instance, we may edit the JSON received in the previous section with a different domain and two different potential pins.

$ less apis.json
{
  "another.domain.com": {
    "secretType": "account",
    "algorithm": "HS256",
    "pins": [
      "/ABoW73P1I3gWumpugB6zzHtqjl0+yFKRBEvJW8I3sQ=",
      "Wp/PdTn4cw7/jwsS9+DnheEm5AbtTEsmVPAGOGY3tHk="
    ]
  },
  "shapes.approov.io": {
    "secretType": "restricted",
    "algorithm": "HS256",
    "pins": [
      "JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU="
    ]
  }
}

We can then update the Approov server configuration as follows:

$ approov api -setAll apis.json
another.domain.com: matched pin Wp/PdTn4cw7/jwsS9+DnheEm5AbtTEsmVPAGOGY3tHk=
shapes.approov.io: matched pin JG29gD8vWiEanTCVPjYLQ5yiYMKQqR05OH38yFf0kBU=
WARNING: updating the APIs will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
APIs set successfully

An error is generated if the input is not well formed JSON. Each of the domains provided are checked to see if they are reachable and if any one of the pins provided match. This ensures that the configuration is valid prior to updating it in the Approov cloud and distributing it to apps. If there is a problem then the follow message is seen:

WARNING: problem detected with APIs, we do not recommend you proceed (unless caused by known local firewall issue)

You can still choose to proceed if the issue may be caused by your local connectivity, since the check is made via the local network, but you should be convinced that this is the only issue or else it would be unwise to proceed.

We do not generally recommend that you use this option. It is better to perform finer grain management using the -add and -remove options for individual APIs and pins.

An admin role is required and further confirmation is expected. This is because these changes will have an impact on production within 30 seconds and as such are dangerous if domains have been accidentally removed or if pins are incorrect.

Any attempt to change the pins for the demo endpoint shapes.approov.io cause an error.

Security Policies

A security policy is set at the account level and determines which apps may be issued with a valid Approov token.

What is a Security Policy

Approov provides fundamental checks regarding the integrity of the app itself, so that valid Approov tokens are only issued to valid app instances. Additionally, various other runtime integrity checks are also performed and the results transmitted to the Approov cloud server in a secure manner. Whether these checks should result in an invalid Approov token or not is determined by the security policies that are selected. This gives you the flexibility to permit accesses or block them according to your risk assessments and the characteristics of your user base. For instance, if you develop a banking app, you may take the view that no rooted device should receive a valid Approov token. However, other consumer apps, deployed to certain markets or demographics, may require rooted devices to be accepted. Thus the security stance must be informed by the characteristics of the app’s user base and the particular threats that Approov is being used to defend against.

A security policy is shown and specified as three comma separated individual selections as follows:

  • Security Rules: The security rules that should be used. Currently the only valid value is default.
  • Rejection Policy: Policy to be used to determine if a particular request should be rejected and an invalid Approov token issued. This allows preset rejection policies to be set. It is also possible to create custom rejection policies.
  • Annotation Policy: Policy for including flag information in the Approov token itself regarding characteristics of the device or runtime environment that have been determined by the Approov analysis.

When a new account is created it is allocated a security policy of default,initial,default. This provides a restricted policy of only issuing valid Approov tokens where no threat has been detected.

A rejection policy of initial is selected to ensure that iOS bitcode SDKs and app debug continue to function correctly, even if the SDK has been integrated from a package without use of the CLI. You may wish to change the rejection policy to default if you are not using bitcode, or if you are correctly marking bitcode mode using the -bitcode option during app registration. Alternatively there are bitcode mode management commands available to do this.

Note that security policies may also be set for individual devices as well as the whole account as described in Managing Devices. For this reason blanket policies such as always-pass and always-fail are provided that would not normally be applied to the whole account.

Device Properties

When Approov analyzes a particular app instance, and the environment in which it is running, it will perform an assessment against a number of different possible device properties. Any particular analysis may result in a number of different device properties being detected. The full set of possible device properties is subject to change, as new ones may be added as enhanced detection capabilities are added in new Approov versions. In some cases these may be added dynamically via security rules updates. Therefore the full set of device properties is not fixed, and you must use a command to retrive the current set. This command also provides the currently selected security policy:

$ approov policy -get
security policy is "default,allow-root,all" meaning:
  rules: default (Default security rules)
  rejection: allow-root (Accept rooted Android devices but reject emulators/simulators and Frida/Cydia/Cycript)
  annotation: default (No device properties provided)
device property settings:
  reject app-not-registered       App is not registered, which may indicate that it is fake or tampered
...

The first part of the output provides information about the security policy selected, including a description of the effect of each component of the policy.

The full set of device properties that are determined for each device then follows, with a short description for each. A reject tag is added to the output next to any device property that will cause a rejection if the propery is detected. Thus you can see the impact of the chosen rejection policy at a fine grain level. For an Approov token fetch, a rejection causes an invalid token to be returned.

If you have overridden the preset settings for the individual flag rejection status, then the rejection policy is shown as custom.

Changing Security Policy

The security policy may be changed for the account using the following command:

$ approov policy -set default,allow-root-and-jailbroken,xposed
WARNING: updating the security policy will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES

This requires an admin role and confirmation. This particular command will change the security policy to allow jailbroken devices as well and to only show the xposed flag as an annotation. The user must confirm the confirmation prompt in order to apply the new security policy.

If adding the new security policy is confirmed then it will have an effect on the account within 30 seconds. Care must be taken when making changes like this to a live account in case a new policy has a detrimental impact on legitimate users of your app.

Rejection Policies

The rejection policy is the second parameter in the comma separated list for setting a security policy. A number of preset options are available and the selection determines the set of device properties that cause a rejection of a fetch request. It is also possible to have custom rejection policies. The options are as follows:

Policy Description
default Reject all rooted/jailbroken devices, emulators, simulators, frameworks and cloned multiapps.
initial Reject all rooted/jailbroken devices, emulators, simulators, frameworks and cloned multiapps. This policy is identical to default, except that it also ensures operation with bitcode releases even prior to any registrations using the -bitcode flag. This policy also has the side effect of disabling any defences that might cause an app to crash if it is being debugged.
strict Reject all rooted/jailbroken devices, emulators, simulators, frameworks and cloned multiapps, and strictly require SafetyNet/DeviceCheck/AppAttest if enabled. Note that this causes any devices not capable of running SafetyNet/DeviceCheck/AppAttest to be rejected. Note that if you enable SafetyNet/DeviceCheck/AppAttest with this policy selected then any app that has already launched and fetched an Approov Token will need to be relaunched before it will get another valid token. Thus we suggest you only enable this policy some time after setting up SafetyNet/DeviceCheck/AppAttest if you have an existing installed base of running apps.
allow-cloned Reject all rooted/jailbroken devices, emulators, simulators and frameworks. However, cloned apps running in multiapps are allowed.
allow-xposed Allow Android Xposed, but otherwise reject all rooted/jailbroken devices and emulators, simultors, other frameworks and cloned multiapps. This option is provided because for some markets Xposed is a popular modding framework for devices, without an intent to attack a given app. If an Android device is rooted without using Xposed, or if an active Xposed module is implicated in data stealing, then a rejection is made.
allow-root Accept rooted Android devices but reject emulators/simulators, cloned multiapps and Cydia/Cycript/Frida. Detected jailbroken iOS devices are rejected.
allow-root-and-jailbroken Accept rooted Android, iOS jailbroken devices, emulator/simulators, cloned multiapps but reject Cydia/Cycript/Frida.
allow-root-and-jailbroken-only Accept rooted Android and iOS jailbroken devices, but reject emulator/simulators/Cydia/Cycript/Frida/cloned multiapps.
allow-raj-only-short-lifetime Accept rooted Android and iOS jailbroken devices, but reject emulator/simulators/Cydia/Cycript/Frida/cloned multiapps. Moreover the Approov tokens issued have a short lifetime of only 45 seconds (with an additional 15 second grace period).
always-pass A highly permissive policy that generates valid Approov tokens except when there is direct evidence of tampering in the Approov SDK. This generates valid tokens even if the app is not registered. This will typically only ever be applied to individual devices. Note this also has the side effect of disabling any defences that might cause an app to crash if it is being debugged. The app may need to be restarted to remove any already applied protection.
always-fail Always rejects, thus generating invalid Approov tokens. Typically this will only ever be applied to individual devices.

Custom Rejection Policies

In addition to the preset rejection policies, it is also possible to use a customized rejection policy. The most applicable rejection policy should be used as the starting point, then it is possible to add or remove individual device properties to modify what will cause a rejection. If such modifications are made then the rejection policy will be automatically changed to custom. You can set a new security policy at any time, which will discard your custom policy and replace it with the preset policy you select.

Firstly get the current security policy as detailed in device properties. This shows the current reject status for each device property flag. To add a property to the set that cause a rejection, you can run a command similar to the following:

$ approov policy -addRejectFlag automated
WARNING: updating the security policy will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES

This causes the device property flag automated to be added to the set that will cause a rejection. You can see the status by getting the security policy. Note you need an admin role and confirmation to perform this operation.

You can also remove a device property from the rejection set by using a command similar to the following:

$ approov policy -removeRejectFlag automated
WARNING: updating the security policy will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
security policy was set successfully

Within 30 seconds the customized policy will be applied to new Approov fetches. Note that, if the app is already running then a new fetch will be necessary before the new policy is enforced (up to 5 minutes).

It is possible to use any preset rejection policy as the starting point for changes. However, we do not recommend starting with the special policies of always-pass or always-fail as these have other, hidden, attributes.

Annotation Policies

The annotation policy is the third parameter in the comma separated list for setting a security policy. This determines what strings any anno claim in the Approov token may have. These are a subset of the device property flags. This allows some ancilliary information to be present within the token. This is particularly useful where a valid Approov token is still being issued, but analysis has demonstrated some questionable aspects of the requesting device which may need to be analyzed by the backend API in conjunction with other information sources.

The following are valid options:

Policy Description
default No annotations are made.
info This provides the properties risky-device, xposed, automated, automated-launch and non-standard-launch in the annotation. This is useful for putting in place other backend authorization mechanisms to determine if traffic should be allowed depending on the flags present and other factors.
risk This provides the property risky-device in the annotation if the device has a property that makes it high risk. This is useful for putting in place other backend analysis that might limit the operations that risky devices can perform.
all Indicates that all asserted Device Properties should be included in the Approov token. This annotation policy should never be enabled for the whole account, only for specific devices, since this information may provide an attacker with significant information about the reasons for any Approov rejection. If constant monitoring of these properties is required in the backend API then we suggest that JWE Approov tokens are used so that the content is encrypted. Note that alternative mechansims are provided using an Attestation Response Code or Rejection Reasons. We recommend using one of these alternatives instead unless the results of the property checks are to be used as part of the request processing.

Key IDs

It is possible to associate a key ID with all JWS tokens created by Approov. You may arbitrarily choose the key ID as follows:

$ approov secret -setKeyID your-keyid

Once this is set then all issued JWS tokens will contain a kid field in the header with the value provided. The currently set value can be obtained with:

$ approov secret -getKeyID

Inclusion of a key ID can be removed with:

$ approov secret -clearKeyID

The addition of a key ID does not impact tokens issued for certain Approov managed domains, such as shapes.approov.io nor for domains using encrypted JWE tokens.

Managing Devices

Approov provides facilities to apply specific policies to particular devices that are being used. This affords flexibility in work practices during development, in continuous build systems, and to allow pentesting and analysis of an Approov protected app.

Extracting the Device ID

In order to modify the policy of a particular device, its ID must be extracted. There are several methods by which this extraction may be done.

  1. Via the logging that is output by Approov when the SDK is first initialized, output with an Approov tag. On Android this can be seen by viewing the logcat output from the device. On iOS, you can look at the console output from the device using the Console app from MacOS. This provides console output for a connected simulator or physical device. Select the device and search for Approov to obtain specific logging related to Approov. Here is an example of the output (in this case from Android) with the device ID h4gubfCFzJu81j/U2BJsdg== shown at the end of the line.

    2021-05-20 13:56:57.789 29546-29546/com.criticalblue.demo I/Approov: test-account, com.criticalblue.demo, 2.6.0(5647), h4gubfCFzJu81j/U2BJsdg==
  2. Via extraction from an Approov token that has been generated on the device. A loggable token contains the device ID directly in the did claim. It can be extracted from an ordinary Approov token using the command line tool, for example:

    $ approov token -check eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkaWQiO…
    failed: {"did":"h4gubfCFzJu81j/U2BJsdg==","exp":1558626254,"ip":"85.233.105.183"}
  3. By calling the getDeviceID() method on the SDK interface. This provides the base64 encoded string of the device which may be presented in some way within the app.

  4. By looking at the devices that have recently requested an Approov token using approov device -getFetches timed. Note that if you are adding a custom device you can use the shorthand approov device -add latest to select any device that has made a request in the last two minutes, as long as it is the only device that has done so.

  5. By adding a device filter, perhaps using your IP address, and then analyzing filtered devices. From this you will be able to see the specific device ID that has been filtered.

Device ID Stability

To respect an individual’s right to privacy, both Apple and Google limit the ability to uniquely identify a device. The identifiers that are truly fixed for a device are hidden and device IDs are generated on-the-fly for new app installations. These, on-the-fly, platform generated device IDs are consistent for the same app but vary across iOS and Android as described below.

Approov device IDs are partly derived from the platform provided device ID, but also include information derived from the app identifier, so device IDs are always per-app device IDs. Thus if you are developing two different apps on the same device you will find that they will be allocated different device IDs. Moreover, any change to the package name of the app will also change the device ID.

Thus you must be aware that the ID for a particular device may change, and this will cause the applied policy for that physical device to be lost. The new device ID must be extracted and the device added again, with the old redundant one removed.

The underlying identifiers used to derive the Approov device ID are as follows:

  • iOS: The identifierForVendor is used. This ID remains constant per app vendor as long as there is one or more apps from the vendor installed. If all the apps are uninstalled then a new ID will be allocated. All apps from the same vendor share the same ID. Thus a good strategy is to always have another app signed by the same developer installed on the device to anchor the device ID for all of them.
  • Android: The ANDROID_ID is used. Since Android O, this is unique to an app installation and registered device user and is stable across app uninstalls and reinstalls. It will change if your app signing key changes or if the device user performs a factory reset.

Adding a Device Security Policy

An individual device may be assigned a specific security policy as follows:

approov device -add h4gubfCFzJu81j/U2BJsdg== -policy default,always-pass,all

This causes the given device to have the particular policy applied without applying it to the rest of the account. This change should be actioned for new Approov token requests within 30 seconds. Remember though that if your app is already running on the device and has fetched a token then it might not need to fetch a new one for up to 5 minutes, in which case the revised policy will only be apparent when that new fetch occurs.

The example rejection policy of always-pass is a common one for development. By applying this to the device, it is possible to always get a valid Approov token to access endpoints without needing to re-register modified apps. This policy also provides valid Approov tokens when debugging the app.

If you are adding an iOS device and you are using a bitcode Approov SDK in one of the Quickstart Frontend Integrations, then in order to get valid Approov tokens you must have made at least one registration of the app with the -bitcode option.

If the device is the only one that has been used recently on your account you can use the latest shortcut, rather than having to specify the device ID explicitly.

approov device -add latest -policy default,always-pass,all

Although, you should note that, the device must have performed a fetch in the last two minutes, and must be the only device doing so in that time. This option cannot be used reliably once you have your app in production where there may be a large number of end user Approov fetches in the 2 minute period.

There is a maximum of 25 devices that may be added to an account at one time.

Labelling a Device

When adding a device it is also possible to set a label for it to make it easier to remember what device it is:

approov device -add h4gubfCFzJu81j/U2BJsdg== -policy default,always-fail,default -label bobs-iPhone7

This label will then be shown when you list the devices. Note that if you wish to include spaces in the label then you must surround it with quotes. This example uses the rejection policy always-fail to ensure the device never receives a valid Approov token. This may be useful for testing.

Setting Pinning Mode

It is also possible to set the pinning mode for a particular device. This changes the way pins are handled for the device and can cause a new dynamic configuration to be downloaded to the app. This command removes all pinning for the app, by causing an empty set of pins to be transmitted as the dynamic configuration:

approov device -add h4gubfCFzJu81j/U2BJsdg== -pinMode unpin

This has the further impact of sending a special dynamic configuration update to the app on the particular device that has all the certificate public key pins removed. This causes all pinning protection to be removed from the app, allowing a proxy (such as Charles Proxy or MITM Proxy) to be used to intercept traffic between the app and the API endpoints. This can be useful for debug or pentesting. Note that some apps may require a relaunch to unpin after receiving the update if they are not written to be immediately reactive to pinning changes.

Other options may be provided for the pinning mode as follows:

  • block: This transmits a fixed but invalid pin in the dynamic configuration for all domains that have had pins added. This will force the app to experience a pinning failure in the same way it would if the API endpoint’s certificates had changed. This can be used for testing what happens in the app when such a certificate mismatch occurs.
  • blockAll: This works like block but it also causes the Approov channel to detect a MITM. This simulates what happens if all TLS traffic is being intercepted. In this case any Approov fetch (that is unable to use a cached result) will receive a MITM_DETECTED error.
  • pin: This is the default and using this option resets the device to the default pinning configuration for the account.

Note that since no security policy is explicitly set, the device is assigned the current security policy for the account. You may also set an explicit security policy for the device in the same command.

Listing Your Devices

A full list of devices that have had a special override security status can be obtained with:

approov device -list

This produces a list, for example:

1 device:
 h4gubfCFzJu81j/U2BJsdg== default,always-pass,all  unpin  A N Other

It shows the device ID, the security policy currently being applied and any pinning mode that has been set (or pin by default).

The name of the user that added the device is also provided. If a device label has been set then this is also shown. This makes it easier to determine the user of a particular device.

If the device was added by a user with the pentest role then this is also shown as an attribute on the device. A user with the pentest role is only able to see or modify devices that have been added using that role, so that they are not able to determine the device IDs being used for development.

Removing Devices

A particular device can be removed as follows:

approov device -remove h4gubfCFzJu81j/U2BJsdg==

The standard account policy will be applied to the device within 30 seconds for new Approov fetches. Note that, if the app is already running then a new fetch will be necessary before the new policy is enforced (up to 5 minutes).

Device removal is not restricted to the user that added the device.

Removing Multiple Devices

Sometimes it is desirable to be able to remove multiple devices with a single command. For instance, if we have:

approov device -list
3 devices:
 h4gubfCFzJu81j/U2BJsdg== default,always-pass,all  unpin  A N Other
 VI2c+UugQ6L7v0wkovXOSg== default,always-pass,all  pin  A N Other
 iDpOemiTdame9qvAQF4w/g== default,always-pass,all  pin  Me

You can issue a command to remove all devices associated with the user name A N Other as follows:

approov device -removeMatching "A N Other"
2 matched devices:
 h4gubfCFzJu81j/U2BJsdg== default,always-pass,all  unpin  A N Other
 VI2c+UugQ6L7v0wkovXOSg== default,always-pass,all  pin  A N Other
WARNING: are you sure you wish to remove these devices
ATTENTION: If you wish to continue then please type YES and return: YES
removed h4gubfCFzJu81j/U2BJsdg==
removed VI2c+UugQ6L7v0wkovXOSg==

You must specify the name in quotes if it contains any spaces. The matching devices will be listed and you will be asked for confirmation.

Note that the provided string also matches against any label that has been provided.

Banning a Device

This facility allows any individual device to be banned on the basis of its device ID. You would typically do this as a result of malicious activity that you may have detected. Such a device will then be unable to receive valid Approov tokens.

The first step is to determine the device ID by obtaining an Approov token that has been issued to that device. Each Approov token contains a did claim which holds the device ID. You can extract the claims from the token using the Checking Token Validity command. So, assuming a device ID of h4gubfCFzJu81j/U2BJsdg== was extracted, the device can then be banned with the following command:

$ approov device -add h4gubfCFzJu81j/U2BJsdg== -banMode ban
successfully set device h4gubfCFzJu81j/U2BJsdg==

The next time this device tries to fetch an Approov token it will be added to the banned list and will not receive a valid Approov token.

If you have the all Annotation Policy selected then tokens rejected due ban have did-ban listed as a rejection reason.

Once the ban has been actioned there is no need to retain the device in the custom set for Approov, so you can remove it again with:

$ approov device -remove h4gubfCFzJu81j/U2BJsdg==
successfully removed device h4gubfCFzJu81j/U2BJsdg==

The ban is only related to the particular device ID. On iOS in particular, if the app containing the Approov SDK is uninstalled and reinstalled again it may be allocated a different device ID and thus evade the ban. In order to combat this the DeviceCheck Integration can be used to provide a permanent ban of a physical device, unrelated to the device ID being used.

Removing a Device Ban

A device ban can be removed if the current device ID can be obtained. As discussed in Banning a Device, this may be obtained from an example Approov token issued to the device. Initiate the unban as follows:

$ approov device -add h4gubfCFzJu81j/U2BJsdg== -banMode unban
successfully set device h4gubfCFzJu81j/U2BJsdg==

The next time this device tries to fetch an Approov token it’s ban status will be removed, and it will be issued with a valid Approov token (presuming it meets all of the other criteria). Once the unban is actioned, remove the device from the custom device set.

Once a given device ID has been unbanned, it cannot be banned again (unless all device state is cleared).

Getting State of a Device

You can obtain a list of the persisted flags associated with a particular device ID as follows:

$ approov device -getDeviceState h4gubfCFzJu81j/U2BJsdg==
did-ban

A list of flags associated with the device ID is provided. In this case it shows that this particular device has been banned. You may see other flags associated with persisted state, especially those related to DeviceCheck and SafetyNet. The evaluation of these tokens are held as persisted state so that the costly exercise of obtaining these tokens doesn’t have to be repeated each time the app on a particular device is launched.

If the device has not been used on the Approov account then you will see the message device state has not been set.

If a device ID has been banned, and then subsequently unbanned, you will see both did-ban and did-unban in the list. The did-unban always takes priority.

This command is not able to retrieve device state for apps running version 2.9.0 or later Approov SDKs.

Clearing All Device State

It is possible to clear the persisted state of all devices in the account. This means that any previously banned devices will become usable again. Moreover, if you are using DeviceCheck Integration, AppAttest Integration or SafetyNet Integration then the previous results of these fetches will be erased and devices will be forced to perform the checks again next time they connect to the Approov service.

You can clear the state as follows:

$ approov device -clearDeviceState
WARNING: clearing device state will require all app installs to redo any DeviceCheck/AppAttest/SafetyNet checks (consider SafetyNet API quota limits)
WARNING: it is not advised to use this option if DeviceCheck autoban (bit availability of both) is being used
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
successfully cleared all device state

You need an admin role and confirmation to perform this operation and pay careful attention to the warnings. In particular, if you are using SafetyNet and you clear the device state, this means that new SafetyNet attestations will be required for all devices as they perform their first Approov fetch after the reset and this may exceed the SafetyNet API quota you have in place.

Note that clearing the device state will have no impact on your billing or the calculation of hourly, daily or monthly active devices. However, it will impact the derivation of the new-did flag so existing app installations will be considered to be new the next time they fetch an Approov token.

If you use this in combination with Automatic Device Banning then the count of installations on the device will be incremented. This could cause unexpected device banning.

If you are using DeviceCheck, AppAttest or SafetyNet then use a rejection policy other than strict when issuing this command. This is because this policy requires devices to have passed the appropriate checks, and the record of these checks will be cleared. The checks are not be performed again until the app is relaunched. Do not apply the strict policy again for several days to provide ample opportunity for the apps to have been restarted.

If you have a very large app user base and are using AppAttest then you might want to consider Rate Limiting before using this option to prevent throttling by Apple servers. This is because all subsequent new app launches by iOS apps with AppAttest support will attempt to perform an attestation and create a request to the Apple servers.

Device Filters

This section covers the optional device filtering feature in Approov.

Filtering Purpose

Facilities are provided to obtain detailed information about the attributes of devices. Filters may then be defined and checked against all devices attempting to fetch Approov tokens. These filters can match against specific device attributes.

When a filter matches then this is shown in a special graph within the Live Metrics. This allows an appreciation of the timing and prevalence of particular attributes to be known. This can be useful for understanding the population of devices that are using your Approov account. Moreover, these facilities may be used for understanding any suspicious behavior and/or by CriticalBlue support staff understanding any irregularities in the operation of apps using your account.

Options are provided to ban particular devices with specific characteristics, and even to apply special security policies to matching devices. This may be used by CriticalBlue support staff to run customized security rules that are able to gather more detailed telemetry from specific devices for analysis.

Getting Specific Device Information

It is possible to obtain more detailed device information for any device that has had a device specific security policy added. At least one Approov fetch must be performed to collect the information (remembering that a previously fetched Approov token may take up to 5 minutes to expire before the app needs to fetch a new one, if it is not restarted).

Once this is done the information can be obtained as follows, by specifying the device ID:

$ approov device -getInfo qZka0yfv+ExvOq3PRh6pGw==
captured: 2020-07-23 11:51:26 BST
rejection-flags: app-not-registered
public-flags: app-not-registered,rooted,root-risk,xposed
ip: 1.2.3.4
device-id: qZka0yfv+ExvOq3PRh6pGw==
device: Android 8.1.0, Nexus 5X, google, bullhead, en
archid: arm64-v8a
device-props: {'Model':'Nexus 5X','Fingerprint':'google/bullhead/bullhead:8.1.0/OPM6.171019.030.E1/4805388:user/release-keys'}
sdkid: 4000
sdk-version: 2.4.0
app-name: Approov OkHttp Shapes
app-version: 3.0(3)
appid: com.criticalblue.demo
app-id-sig: NhVaAEGs3U6fLObhZAIdRh71wVF7kSOL0aAMv+e5TvU=
app-sig: tL8CNNpf4XlekWkwuyJaCRtcntJyjZ1ujYJ7CZMO+Fk=
attest-reason: launch

The information most recently collected is shown, along with the local time of its capture. The information consists of a series of <key>:<value> attributes. The exact set of information may vary over time and also between iOS and Android.

In this case the public-flags shows the full set of device property flags that have been collected. The IP address of the client is always shown too, independently of the IP Tracking Policy that has been selected. Although, you should note that, the IP addresses are only held in the memory of the Approov cloud servers and never committed to any file storage.

In the case of Android the device-props provides more detailed information about the particular model and OS build of a device (although it does not uniquely identify an individual device). The app-sig is always present and shows the signature of the particular app. On Android the app-id-sig is also present and provides the overall identity signature used when registering an App Bundles or APKs signed by Google Play signing (as the raw app signature may change depending on the app delivered to an individual device).

The individual device information is collected and held by the Approov servers on a best effort basis. The information may be cleared from time to time so you should save it in a local file if you wish to keep it more permanently.

Analyzing New Devices

Information for new devices (i.e. device IDs that have not be seen previously) is collected automatically. It can be obtained by using new-did as the parameter for -getInfo:

$ approov device -getInfo new-did
--- w4mmGFZkpz5oPz6w6gl1Cw== 2020-07-23 12:10:43 BST ---
rejection-flags: app-not-registered
public-flags: app-not-registered,jailbroken,devicecheck-unavailable
ip: 1.2.3.4
device-id: w4mmGFZkpz5oPz6w6gl1Cw==
device: iOS, 12.1.2, iPhone7,2, en_ES
archid: arm64
sdkid: 4505
sdk-version: 2.4.0
app-name: Approov Shapes
app-version: 1.0
appid: ios.swift.shapes.demo.approov.io
app-sig: DRJNqt37tsdHwb9FKFT80dPqXlOHqZnZy68zAiVSsvM=
attest-reason: expiry

A stream of information for the most recent new devices is provided, with a separator providing the ID and the local capture time.

The new device information is collected and held by the Approov servers on a best effort basis. Only the information for the last 100 new devices is held and earlier entries are discarded. Note also that the information may be cleared from time to time so you should save it in a local file if you wish to keep it more permanently.

If you wish to obtain information for all new device IDs then the following short bash script can be used. This appends to the approov-new-did.txt file any new devices on a per-minute basis. This ensures that, unless there are more than 100 new devices per minute, all the new device information will be captured.

#!/bin/bash

while true; do
  echo "getting new devices"
  approov device -getInfo new-did -clear >> approov-new-did.txt
  sleep 1m
done

The use of the -clear option ensures that prior data is cleared on each call so there is no duplicate information in the generated file. Note that this approach cannot be used by more than one user at a time.

Adding a Device Filter

A device filter may created that checks the attributes of every device fetching an Approov token to determine if it has a particular attribute. For instance:

$ approov filter -add ipmatch -key ip -matchValue 1.2.3.4
successfully set filter ipmatch

This adds a new filter called ipmatch. This name is used to reference the filter and also appears in live metrics if the filter is matched. The name is restricted to a maximum of 20 characters of lower case alphanumerics and the - sign only. If a filter name is reused then the previous settings are overridden.

The -key option determines the particular key in the information to be checked against, ip in this case. If the key is not present then the match never occurs. The -matchValue specifies the specific text for the value for the match to occur. In this case the match is for any device using the IP address 1.2.3.4. (This initial form requires an exact verbatim match, to have a single filter with more general matching semantics, see the section on Regular Expression Filtering.)

With the default options the only impact is to show the match in the live metrics.

Filtering may be restricted to only new devices by using the -newDIDOnly flag:

$ approov filter -add special-app-sig -key app-sig -matchValue DRJNqt37tsdHwb9FKFT80dPqXlOHqZnZy68zAiVSsvM= -newDIDOnly
successfully set filter special-app-sig

In this case the matching is looking for a particular app signature for device IDs being used for the first time.

A maximum of 25 filters may be defined at any one time.

Analyzing Filtered Devices

It is possible to capture full device information for any device that matches a filter. To enable this you must use the -captureDeviceInfo flag on the added filter, for example:

$ approov filter -add ipmatch -key ip -matchValue 1.2.3.4 -captureDeviceInfo
successfully set filter ipmatch

Information for any device that matches the ipmatch filter is then collected. The informaiton can be obtained by using filtered as the parameter for -getInfo:

$ approov device -getInfo filtered
--- w4mmGFZkpz5oPz6w6gl1Cw== 2020-07-23 12:10:43 BST ---
matched-filters: ipmatch
flags-all: app-not-registered,jailbroken,devicecheck-unavailable
ip: 1.2.3.4
device-id: w4mmGFZkpz5oPz6w6gl1Cw==
device: iOS, 12.1.2, iPhone7,2, en_ES
archid: arm64
sdkid: 4505
sdk-version: 2.4.0
app-name: Approov Shapes
app-version: 1.0
appid: ios.swift.shapes.demo.approov.io
app-sig: DRJNqt37tsdHwb9FKFT80dPqXlOHqZnZy68zAiVSsvM=
attest-reason: expiry

A stream of information for the most recent filter matches is provided, with a separator providing the ID and the local capture time. Note also that the first property shown is matched-filters which lists all of the filters that were matched by the device.

The device filtering information is collected and held by the Approov servers on a best effort basis. Only the information for the last 100 new devices is held and earlier entries are discarded. Note also that the information may be cleared from time to time so you should save it in a local file if you wish to keep it more permanently.

If you wish to obtain information for all filtered devices then the following short bash script can be used. This appends to the approov-filtered.txt file any filtered devices on a per-minute basis. This ensures that, unless there are more than 100 filtered devices per minute, all the information will be captured.

#!/bin/bash

while true; do
  echo "getting filtered devices"
  approov device -getInfo filtered -clear >> approov-filtered.txt
  sleep 1m
done

The use of the -clear option ensures that prior data is cleared on each call so there is no duplicated information.

Regular Expression Filtering

Normally when a filter -matchValue is specified it must be an exact verbatim match for the specified key’s value. However, it is also possible to do Regular expression matching if the -regex option is used. For example:

$ approov filter -add android7 -key device -matchValue "Android 7" -regex
successfully set filter android7

This creates a filter that checks for the substring Android 7 in the device property. By default a specified regular expression performs a substring match. However, the full power of regular expressions may be used. There is a useful interactive tool here for constructing regular expressions.

Regular expression filtering can be particularly useful for checking if a device has particular properties in the flags-all device information key. Simply specify the required flag name with -regex and this will do a substring match to check if the flag is set, regardless of other flags (being careful to make sure the flag name is not itself a substring of some other flag name).

Conjunction Filters

It is possible to create a filter that is only matched if a set of other filters all match. This allows the creation of more complex conditions that require matches across multiple different device information keys.

For instance, if you have previously setup a filter called android7 and another one called ipmatch, then you create a new filter that is the conjunction of these two as follows:

$ approov filter -add both-matched -conjunction android7+ipmatch
successfully set filter both-matched

This new filter will only match if both the input filters are matched on the same device. You specify the set of input filters using a + separated list provided to the command. Note that these inputs must be ordinary filters and not conjunction filters themselves.

When you first add a conjunction filter a check is made that the input filters are present. However, if these are subsequently removed then the conjunction filter will never match since all inputs must be present for a match to occur.

Listing Device Filters

All currently set filters can be shown as follows:

$ approov filter -list
2 filters:
 ipmatch          ip: 1.2.3.4
 special-app-sig  app-sig: DRJNqt37tsdHwb9FKFT80dPqXlOHqZnZy68zAiVSsvM=  newDIDOnly

The list of options associated with the filter are shown on the right hand side of the filter listing.

Removing a Device Filter

Any named filter can be removed as follows:

$ approov filter -remove special-app-sig
successfully removed filter special-app-sig

If you remove a filter that is an input to a conjunction filter, then it will never match until the input filter is replaced,

Rejecting Filtered Devices

A -reject option is provided so that any device which matches is automatically rejected, and will not receive a valid Approov token. For example:

$ approov filter -add ipmatch -key ip -matchValue 1.2.3.4 -reject
WARNING: using the ban or reject option will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
successfully set filter ipmatch

This rejects any device that attempts to fetch an Approov token from the IP address 1.2.3.4.

You should be especially careful when using this option as it is available with dev role priveleges. If a match is used that covers too many devices then this could cause large numbers of app users to be rejected. Always test the match without reject first and examine the metrics to determine the prevalence of the match.

Banning Filtered Devices

A -ban option is provided so that any device which matches is automatically banned. This sets the did-ban flag on the device and it will not ever receive valid Approov tokens. For example:

$ approov filter -add ipmatch -key ip -matchValue 1.2.3.4 -ban
WARNING: using the ban or reject option will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
successfully set filter ipmatch

This bans any device ID that attempts to fetch an Approov token from the IP address 1.2.3.4.

Note that any such ban will be permanently associated with the device ID, and the device ID will continue to be banned even if the filter is subsequently removed.

You should be especially careful when using this option as it is available with dev role privileges. If a match is used that covers too many devices then this could cause large numbers of app users to be rejected. Always test the match without banning first and examine the metrics to determine the prevalence of the match.

In an emergency it is possible to clear all of the did-ban states using the Clearing All Device State option. This requires an admin role. This clears all device state and thus undoes any prior device ID bans.

Marking Filtered Devices as Risky

A -risky option is provided so that matching devices are automatically marked as risky, for example:

$ approov filter -add ipmatch -key ip -matchValue 1.2.3.4 -risky
successfully set filter ipmatch

This means any request from IP address 1.2.3.4 will have the risky-device flag asserted.

The impact of this is two-fold:

  • The device will be issued Approov tokens that have a 2 -minute lifetime rather than the usual 5.
  • If the risk Annotation Policy is set then this means that the risky-device flag will be set. This enables backend systems to observe this annotation and potentially perform different actions for the device.

Custom Filtered Security Policy

It is possible to use the special device ID value ++FilteredSecPolicy++w== to provide a security policy that is applied to any device which matches specific filters. Firstly add this pseudo device ID as follows:

$ approov device -add ++FilteredSecPolicy++w== -policy alt-rules,default,default
successfully set device ++FilteredSecPolicy++w==

For the filtered policy to have an effect, you should not use the same security rules setting as the default for your account. The example alt-rules shown above will not work (there are no such rules). Normally this feature is used in conjunction with Approov support staff for more detailed analysis of specific activity on your account and so you should really contact Approov support if you wish to use this feature.

You are not able to use the -pinMode or -banMode options on this special device ID. However, the -probeURL value is applied.

In order to enable this behavior for a particular filter you must use the -execFilteredSecPolicy option, for example.

$ approov filter -add ipmatch -key ip -matchValue 1.2.3.4 -execFilteredSecPolicy
successfully set filter ipmatch

This causes any request from IP address 1.2.3.4 to execute the custom filtered security policy.

It is also possible to make a certain percentage of all devices execute the special filtered security policy, instead of the standard one for the account. You can simply set the percentage as follows:

$ approov filter -setSamplingPercentage 0.1
WARNING: using sampling will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
successfully set sampling percentage

This sets the sampling percentage to 0.1%. An admin role and confirmation is required to make this change. This means that 0.1% of all devices will execute the special filtered secuity policy rather than the standard account security policy. This determination is made on the basis of the device ID so that the same device will either be subject to the special policy or not. However, the selections change on each day so the sampling moves across the device population.

You can always see the current setting with:

$ approov filter -getSamplingPercentage
sampling percentage is 0.10%

Adding this special security policy causes a very small addition to the latency of Approov fetches, independently of the number of devices that use it. Thus we suggest you only leave this special policy added for as long as you need to use it.

Observing All Fetching Devices

A record is kept of the device IDs of any apps that are fetching Approov tokens. This is held in time order, with an optional timestamp. It can be obtained with:

$ approov device -getFetches timed
qZka0yfv+ExvOq3PRh6pGw== 2020-07-23 12:10:45 BST
qZka0yfv+ExvOq3PRh6pGw== 2020-07-23 16:27:12 BST
w4mmGFZkpz5oPz6w6gl1Cw== 2020-07-23 16:27:20 BST

This is useful for analysis of the device IDs that are using the account, and perhaps frequency of use analysis to determine if particular device IDs are responsible for a high use of the account. These devices can then be added as custom devices for more detailed analysis if required. The parameter timed indicates that timestamps should be included.

The fetching device ID information is collected and held by the Approov servers on a best effort basis. Only the information for the last 1000 requests is held and earlier entries are discarded. Note also that the information may be cleared from time to time so you should save it in a local file if you wish to keep it more permanently.

A simple script such as the following can be used to collect this information into the local file approov-fetches.txt:

#!/bin/bash

while true; do
  echo "getting latest fetches"
  approov device -getFetches untimed -clear >> approov-fetches.txt
  sleep 1m
done

This simply captures the latest untimed information every minute and uses the -clear option to discard the obtained information so that it is not duplicated in the resultant file.

Analyzing Captured Streams

Information collected regarding fetches or the attributes of particular devices can be easily manipulated using standard commands. For instance, imagine we have captured approov-fetches.txt showing two different devices using the account as follows:

qZka0yfv+ExvOq3PRh6pGw==
w4mmGFZkpz5oPz6w6gl1Cw==
w4mmGFZkpz5oPz6w6gl1Cw==
w4mmGFZkpz5oPz6w6gl1Cw==
w4mmGFZkpz5oPz6w6gl1Cw==
qZka0yfv+ExvOq3PRh6pGw==
qZka0yfv+ExvOq3PRh6pGw==
w4mmGFZkpz5oPz6w6gl1Cw==
w4mmGFZkpz5oPz6w6gl1Cw==

We can easily count the number of occurrences of each device ID as follows:

$ sort approov-fetches.txt | uniq -c
      3 qZka0yfv+ExvOq3PRh6pGw==
      6 w4mmGFZkpz5oPz6w6gl1Cw==

We can use this technique to anayze the frequency of use by certain device IDs or the frequency of occurrence of particular device attributes. This method can be used to identify commonly occurring device attributes, which can then be used in further searches in the original file to find the full context of each interesting match.

Note that this output can of course itself be piped to a file, such as output.txt. You can then show the most commonly occurring repeats as follows:

$ sort -h -r output.txt | less

The -h and -r options cause the most frequently occurring lines to be shown first.

Token Binding

This section covers the optional token binding feature in Approov.

If you are able to use one of our Quickstart Frontend Integrations then these typically include support for token binding, by specifying a particular http header that holds the source data for the hash. Similarly, the Quickstart Backend Integrations are able to extract the same information from the header and verify that the correct token binding is included in the Approov token.

Token Binding Concept

Token binding extends the security of the Approov token through a strength in depth approach. The mechanism ties an arbitrary string to an Approov token by including its hash in one of the claims. The facility is intended for long lived data, such as an OAuth token or a user session identifier, that can be used to uniquely identify a user. The data is supplied to the Approov SDK as an ASCII encoded string. The SDK takes the string and calculates its SHA256 hash. This is then provided inside the Approov token in the pay claim as a base64 encoded string.

If the binding data changes then this invalidates all currently cached Approov tokens and new ones are requested on the next fetch. Thus it is important not to use rapidly changing data for binding. Ideally long lived user session tokens should be used that will likely not change during normal app usage.

Note that the hashing of the data sent in the pay claim is always done in the SDK itself. Only the SHA256 hash of the data is sent to the Approov cloud service, so there is no need to be concerned about additional Personal Identifiable Information (PII) being sent to the Approov cloud service.

Setting the Binding

The data value may be explicitly set using the setDataHashInToken method in the SDK or frontend quickstart. Normally though the Quickstart Frontend Integration will set the value automatically based on values provided in a binding header. If necessary, most integrations also provide a method to set the value explicitly.

When the data value is set the SHA256 hash of it is calculated and compared against any current value that is held. If the value is different, then any cached Approov token is cleared. Any subsequent Approov fetch call will obtain a new Approov token. The maximum rate at which new tokens can be fetched may be rate limited to prevent excessive usage if the binding data is modified and fetching performed in a tight loop.

The data binding is held in the pay claim of the generated Approov token. The same value is retained in all subsequently generated Approov tokens until it is changed with another setDataHashInToken call.

Note that once a pay claim has been added it is not possible to remove its inclusion in the running app, only change its value.

Generating Example Token with Binding

The example token generation also supports the ability to generate a token with a pay claim. This can be used to test backend integrations that must perform the same hashing calculation to compare the claim. For example we can use:

$ approov token -genExample your.domain -setDataHashInToken custom-data
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJl…

You can decode the generated Approov token string as follows:

$ approov token -check eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJl…
valid: JWS {"did":"ExampleApproovTokenDID==","exp":1558640470,"ip":"1.2.3.4","pay":"tih+xRFV8PMsDhKthuFdvqWtQpKdT+K8X5W3258EJnU="}

This shows the pay claim hash derived from the string custom-data:

{
  "did": "ExampleApproovTokenDID==",
  "exp": 1558640470,
  "ip": "1.2.3.4",
  "pay": "tih+xRFV8PMsDhKthuFdvqWtQpKdT+K8X5W3258EJnU="
}

Backend Integration Impact

If the token binding features are used then the pay claim must be checked on the backend to ensure the hash is consistent with the source data being presented. This data must be present in some other part of the request so that it can be extracted for comparison with the hash in the Approov token.

The recommended process for checking the pay claim against the data provided in the request is as follows:

  1. Do a basic check of the Approov Token to see if it is valid.
  2. Check whether the token has a pay claim. If claim is not present then the token may be from the Failover service.
  3. If the claim is present then the data should be compared with the SHA256 hash of the data you provided to Approov. In some cases, such as when you are providing an OAuth token and you have yet to retrieve this in the application code, you should use a known none value which you both pass into the token fetch call in your app and in your server side payload check. This is because your backend code must cope with Failover tokens. Thus you must ensure normal tokens always have some content in the pay claim or else the logic for handling failover tokens (which will only ever be issued in the unlikely case of an Approov primary outage) could provide a back door for avoiding a matching pay claim.

Apple DeviceCheck Integration

This section covers the integration between Approov and Apple’s DeviceCheck feature. If this integration is used then the Approov SDK forces the iOS device to generate a token that is passed to the Approov servers. This can then be checked with Apple and proves that the token was generated on a real iOS hardware device. This provides an additional level of protection against any spoofing attempts.

This feature is particularly useful if there is suspicion of malicious or fraudulent activity occurring via the continual re-installation of an app on the same physical device. The app itself may be unmodified and running in a clean environment so would receive a valid Approov token. The integration allows a specific physical iOS device to be banned once fraudulent activity has been detected on it so it is not able to receive valid Approov tokens again.

Apple’s DeviceCheck is only supported from iOS 11, and not all older hardware devices have the secure enclave needed to implement it. If you allow your app to be installed on earlier versions of iOS, or on devices without the required hardware support, then they will not be protected by DeviceCheck.

If this option is used then the iOS Approov SDK must make a call to generate a token to identify the device. This needs to be done on the first Approov fetch after launching the app for the first time. Performing this operation requires additional network connection(s) and CPU processing time, over which the Approov SDK has no control. This can substantially delay the fetch operation on the iOS platform by adding up to 2500ms of additional latency.

DeviceCheck Concept

As discussed in Device ID Stability, the device ID reported on iOS automatically changes if an app is removed and then reinstalled. This is to preserve the privacy of the end user, as otherwise it would be possible to track an individual indefinitely via the device ID reported on their device. However, the inability to track specific devices creates some challenges with blocking specific malicious or fraudulent behavior emanating from a particular device. If blocking is based on a device ID then the malicious actor can always circumvent any banning via reinstallation of an app. IP based blocking can also be evaded by the use of proxies.

Apple have recognized this as an issue and have introduced the DeviceCheck feature to provide some very limited tracking of specific physical devices that maintains user privacy. The facility allows up to two bits to be recorded for each physical device for each Apple developer account. These bits can be used to record information such as the detection of some fraudulent behavior on the device.

Obtaining the bit status values and updates to them is performed by calling an Apple server API. In order to identify the device to this API it is necessary to obtain a Device Token. This is an ephemeral token (approximately 3KB in size) that identifies the device. Of course to prevent this itself being used to identify the device, and breaking the privacy policy, it is derived from a randomly generated nonce value so is different every time even on the same device. Since accessing the Apple API requires an authorization key this cannot be done in the app itself, since if this key was extracted it could be used to make arbitrary bit changes for other devices. Thus the API calls must be performed server side, necessitating that a protocol be established to communicate the DeviceCheck token from the mobile app to the server.

The Approov integration of DeviceCheck handles all of this integration complexity. If a DeviceCheck key is added to the Approov account, then the Approov SDK automatically collects and transmits the DeviceCheck tokens to the Approov servers. This token is then used to get and update the status of the device physical bits and prevent banned devices from being issued with valid Approov tokens. The simple check of the validity of the token also ensures that the traffic is emanating from a real iOS hardware device. Commands are provided to easily ban and and unban devices, and an optional automatic banning facility is available to automatically detect and ban devices associated with repeated app uninstalls and reinstalls.

The status of the DeviceCheck will be reflected in the device property flags:

  • devicecheck-ban: Indicates a permanent device ban associated with the physical device.
  • devicecheck-apple-err: Indicates a problem using the Apple endpoint, possibly due to an invalid AuthKey. Use the approov devicecheck -get command to perform a check on the validity of the key provided.
  • devicecheck-completed: DeviceCheck has been completed on a device.
  • devicecheck-failed: DeviceCheck has failed indicating that the provided device token was not valid.
  • devicecheck-performed: DeviceCheck has just been performed on a device.
  • devicecheck-unavailable: Indicates that the DeviceCheck capability is not available on the device.

These flags are used in various Rejection Policies to determine if a valid Approov token should be issued. Note that most rejection policies do not make the receipt of a DeviceCheck token mandatory. However, the policy strict does do so but you should be aware that any devices unable to perform DeviceCheck will be unable to get a valid Approov token.

Getting the DeviceCheck Key

In order to use the Approov DeviceCheck (or AppAttest) integration you need to add an Apple authentication key to your Approov account. This key only needs permissions to access and update the two bits provided for physical device. This is used by the Approov servers to dynamically query the Apple servers when new devices are added, and to update the settings of the bits if a particular device is being banned (or subsequently unbanned).

Log into your Apple Developer Account, click on Account on the top menus, login and then navigate to the “Certificates, IDs & Profiles page”. Here you will see the list of keys and certificates that have been issued for your account, such as this below.

Apple Certificates Page

Select the “Keys” menu on the left hand side to navigate to the keys that have been issued for the account.

Apple Keys Page

You need to click on the blue plus button to add a new key. Type in the name of that you want to call the key (you an choose anything that is meaningful to you) and click the option for DeviceCheck.

Register New Key

You then press the “Continue” button and a dialog will be shown asking you to confirm the key addition.

New Key Confirmation

Click Register. You will then be provided with a dialog that gives you an option to download the private key that has been generated. Click this button. You will only get once chance to download this key so make sure the file is saved somewhere that is accessible for the next steps.

New Key Download

When the key is downloaded you will get a dialog such as the below with details of the key. The .p8 file itself should have been written to the Downloads folder that your browser uses by default. Also make a note of the Team ID value shown on the top right of the screen next to your company name. You will also need that.

Downloaded Key

Setting the DeviceCheck Key

Now that you have a private key you need to make it accessible to Approov.

$ approov devicecheck -addAuthKey AuthKey_XXXXXXXXXX.p8 -teamID YYYYYYYYY -bits bit0
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES

You will need an admin or delegate role and confirmation to do this, where AuthKey_XXXXXXXXXX.p8 is the private key file you downloaded and YYYYYYYYY is your team ID. In this case bit0 is selected so that the Approov service can read and update bit 0 of the two bits available per physical iOS device. You can change this to bit1 if you would rather use that bit instead. Note that if you do not specify -bits then it is assumed that no bits are available and the device token is only used as an additional check that traffic is coming from a real iOS device.

Now that this information is added to your Approov account, the Approov cloud servers are able to contact the Apple servers to read and update the state. You can confirm that the information has been recorded with:

$ approov devicecheck -get
TeamID: YYYYYYYYY
KeyID: XXXXXXXXXX
Expiry: 12m
Bits: both
Apple Endpoint: Production

If there is a problem with the information provided, and it is not possible to authorize with the Apple servers then you will see WARNING: Apple Authorization Error with the message from the Apple servers.

If you have selected usage of bits, then Approov sets those bits in order to indicate that a particular device has been banned, and should no longer receive valid Approov tokens. If you have previously used the Apple DeviceCheck facility then the bits will not be set and so the default will be to pass this aspect of attestation. If you have used the facility before and bits are set then this may cause those devices to be banned. In this case you may use the -expiry option when setting the authorization key to ignore settings made more than a certain number of months ago. If the bit setting has been more recent than one month then you will not be able to use this Approov facility on your apps until sufficient time has elapsed.

Permanent Device Banning

As discussed in Banning a Device, it is possible to ban a particular device ID from receiving valid Approov tokens. However, reinstallation of the app on the same device may generate a new device ID and evade the ban. If you are using DeviceCheck then a permanent ban for a particular physical device can be instigated.

Whenever you ban a device ID with DeviceCheck on the account active, the ban will become a permanent ban of the physical device (unless the bit availability has been set to none).

If you have the all Annotation Policy selected then tokens rejected due to a permanent DeviceCheck ban have devicecheck-ban listed as a rejection reason.

Unbanning whatever device ID the physical device is using will also remove the permanent ban.

When a particular device is banned it is across all apps associated with the same Apple developer account, even if these apps are associated with different Approov accounts. This is because Apple stores the bit states on a per-developer account basis. If you are using multiple Approov accounts associated with a single Apple developer then you may select different bits on different accounts to avoid such interference.

Removing the DeviceCheck Key

The DeviceCheck authorization key can be removed from the account at any point, if an admin role is available, as follows:

$ approov devicecheck -remove
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
DeviceCheck information removed

You will need an admin or delegate role and confirmation to do this. This will disable all lookups of DeviceCheck. Any ban will remain on a particular device ID, but if the physical device is allocated a new device ID due to app reinstallation then the ban will not follow. If the DeviceCheck key is subsequently set again then the banning of the same devices will be reinstated since the Apple bit state will not have been changed.

Automatic Device Banning

An automatic device banning feature is enabled if both bits are made available when setting the DeviceCheck key, such as the following:

$ approov devicecheck -addAuthKey AuthKey_XXXXXXXXXX.p8 -teamID YYYYYYYYY -bits both
DeviceCheck information added

In this case the two available bits are used as a counter of the number of times an app has been removed and reinstalled on a device. Each reinstallation will generate a new device ID. However the DeviceCheck bits implement a counter and when this reaches the maximum value of 3 the physical device will be automatically banned. This is because such continual re-installation behavior is typically associated with some kind of malicious activity. Once banned the abuser will no longer be able to use the device to obtain valid Approov tokens. Non-malicious users would have to uninstall and reinstall the app at least three times before receiving a ban and this would represent very unusual behavior.

Since the two bits are interpreted as a counter, we do not advise you to use this feature if the DeviceCheck bits have ever been previously used on the account for other purposes more recently than the value of -expiry. Moreover, you should never use the automatic banning feature if sharing a single Apple developer account across multiple Approov accounts or if you have multiple different iOS apps associated with even a single Approov account.

Note that once a device has been banned, the only way to unban it is via the manual Removing Device Ban method.

Apple AppAttest Integration

This section covers the integration between Approov and Apple’s AppAttest feature. If this integration is used then the Approov SDK forces the iOS device to perform a valid AppAttest attestation in addition to all of the other verifications performed by Approov. This provides an additional level of protection against any spoofing attempts, whilst hiding the integration complexity of using AppAttest on the backend.

Approov includes a full server side integration as detailed for AppAttest. If any of the AppAttest checks fail then valid Approov tokens are not generated for the iOS device. Support is provided for rate limiting AppAttest attestations and to perform optional fraud checks using information from Apple servers.

AppAttest assertion checks are also performed on subsequent Approov fetches from the device, ensuring the continued legitimacy of the device. This uses keys held in the secure enclave of the device, ensuring that the requests are really coming from the same device that passed the original AppAttest attestation.

Apple’s AppAttest is only supported from iOS 14. If you allow your app to be installed on earlier versions of iOS then they will not be protected by AppAttest. You might want to consider using DeviceCheck as well as, or instead of AppAttest, since it is supported on many devices from iOS 11.

AppAttest is only supported in version 2.9.0 and later SDKs. If you have some earlier versions of the Approov SDK in the field they will be unable to perform AppAttest, although it is still okay to enable it to target later versions.

If this option is used then the iOS Approov SDK must make calls to create a new key pair and then attest its origin with Apple. This needs to be done on the first Approov fetch after launching the app for the first time. Performing this operation requires additional network connection(s) and CPU processing time, over which the Approov SDK has no control. This can substantially delay the fetch operation on the iOS platform by adding up to 2500ms of additional latency.

AppAttest Status Flags

The status of the AppAttest will be reflected in the device property flags:

  • appattest-appid-fail: iOS device has completed an AppAttest attestation but app is not registered.
  • appattest-apple-err: Indicates a problem using the Apple fraud lookup endpoint, possibly due to an invalid AuthKey. Use the approov appattest -get command to perform a check on the validity of the key provided.
  • appattest-assert-performed: iOS device has just performed an AppAttest assertion.
  • appattest-attest-performed: iOS device has just performed an AppAttest attestation.
  • appattest-completed: iOS device has completed (now or previously) an AppAttest attestation.
  • appattest-failed: iOS device has failed an AppAttest attestation or assertion, or app is unregistered or fraud risk exceeds threshold.
  • appattest-high-risk: iOS device has completed an AppAttest attestation but fraud risk exceeds threshold.
  • appattest-unavailable: iOS AppAttest was attempted but it was unavailable. This will occur on devices running a version of iOS 13 or lower, or devices without a suitable hardware enclave (such as simulators).

These flags are used in various Rejection Policies to determine if a valid Approov token should be issued. Note that most rejection policies do not make the ability to perform an AppAttest mandatory. However, the policy strict does do so but you should be aware that any devices unable to perform AppAttest will be unable to get a valid Approov token.

AppAttest Environment Setting

In order to use AppAttest in production (or to use the optional fraud lookup facility at all) you must add the AppAttest Environment capability and entitlement into your app.

Firstly you need to register a new, or modify an existing, app identifier with the AppAttest capability. Log into your Apple account and navigate to the Identifiers section. If creating a new Identifier, press the + and go through the steps of the wizard to create a new App ID. Select the AppAttest capability, along with any others you need, as follows:

App ID

Note that you must provide a specific Bundle ID, it is not possible to add a capability when using a wildcard.

It is then necessary to add the required entitlement in your app’s .entitlements file, as follows:

Add Entitlement

The file holds key/value pairs. Ensure you set the value type to a String and then set it to either development or production. Remember to change the value to production before issuing your app to the App Store.

Enabling AppAttest

AppAttest is enabled by specifying the Apple team ID used for your apps, as follows:

$ approov appattest -addTeamID YYYYYYYYY
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
AppAttest team ID added

You will need an admin or delegate role and confirmation to make this change. The TeamID can be found by logging into your Apple account, and you will have been provided with it during the AppAttest Environment Setting step. Alternaively, go to Certificates, Identifiers & Profiles and your team ID is shown on the upper right on the web page. It is a 10-digit alphanumeric code. The Team iD is also shown when you use Approov to register one of your iOS apps.

Note that in order to obtain valid AppAttests you must have at least one app registered with the correct Bundle ID and Team ID. If not then the AppAttest will fail with the appattest-appid-fail flag. You can clear this by Registering a suitable app. Note that you can see the information collected by AppAttest by Getting Specific Device Information under the appattest-app-id key.

AppAttest can be disabled, if an admin or delegate role is available, as follows:

$ approov appattest -remove
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
AppAttest disabled

This will disable all future usage of AppAttest attestations or assertions on your account.

The persisted AppAttest state for any devices that have conducted an AppAttest attestation will be retained. This persisted state may still cause Approov rejections due to the last AppAttest result. If you wish to completely remove any persisted state, then consider Clearing All Device State.

Getting AppAttest Status

The status for AppAttest can be be viewed at any point using:

$ approov appattest -get
TeamID: YYYYYYYYY
KeyID: XXXXXXXXXX
AssertionPeriod: always
RateLimit: unlimited

If you have provided the optional KeyID to support fraud lookup and it is not possible to authorize with the Apple servers then you will see WARNING: Apple Authorization Error with the message from the Apple servers.

Controlling AppAttest Assertion Rate

Once a full AppAttest attestation has been completed for a device, subsequent Approov fetches are protected using an AppAttest assertion. This signs some challenge data provided by the Approov server with the private key in the secure enclave created in the initial attestation step. This proves that the request is being handled by the same device since it is not possible to extract the private key from the secure enclave.

An assertion is a much quicker operation than the original attestation, taking of the order of 200ms rather than around 2500ms for the original attestation. By default the assertion repeat period is considered to be always so all Approov fetches include an assertion, and thus require additional processing time of approximately 200ms.

If this additional delay is problematic for your application’s responsiveness then you can elect to use a slower assertion period, specified in hours, as follows:

$ approov appattest -setAssertionPeriod 1
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
AppAttest assertion period set

You require an admin or delegate role and confirmation to make this change. In this case this means that a new assertion is only performed if it has been an hour or more since the last one, thus reducing the latency of any intervening Approov fetches. Remember that these fetches will continue to be protected by all the usual Approov protections against request spoofing. You can reset the period back to always if required.

Note that an assertion is always performed on the first Approov fetch after a new launch of the app.

Rate Limiting AppAttest Attestations

An AppAttest attestation is performed, on all devices that support it, on the very first Approov fetch after the first launch of the app. This might be problematic if you have a very large app user base and are just enabling AppAttest, or you have very large numbers of new users. This is because the Apple documentation infers that Attestation requests from the device might be throttled if the load is very high (see Onboard Users Gradually in Preparing to Use the App Attest Service). No specific maximum numbers are provided by Apple.

By default AppAttest rates are not limited by Approov, but it is possible to set a rate limit as follows:

$ approov appattest -setRateLimit 1000
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
AppAttest rate limit set

An admin or delegate role and confirmation is required to do this. The value is the maximum number of new AppAttest requests per hour. If this rate is exceeded then subsequent new app launches during the period will not perform an AppAttest. This is delayed until the next time the app is launched, and if the rate is below the threshold. You can disable the rate limit by specifying unlimited. Note you should not use the strict rejection policy with this option, otherwise devices that failed to perform an AppAttest due to the rate limit will be unable to get valid Approov tokens.

Adding Apple Fraud Lookups

If you add a DeviceCheck key then Approov will automatically do a fraud lookup using an Apple endpoint and reject devices that exceed a user specified risk level. Get a DeviceCheck Key to enable this access and add it as follows:

$ approov appattest -addAuthKey AuthKey_XXXXXXXXXX.p8
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
AppAttest fraud lookup authorization added

Where AuthKey_XXXXXXXXXX.p8 is the private key file you downloaded. You will need an admin or delegate role and confirmation to do this. Now that this information is added to your Approov account, the Approov cloud servers are able to contact the Apple servers and assess fraud risk for all new AppAttests performed.

The fraud check guards against an attack where a single compromised device may be used to spoof many individual devices. The fraud lookup provides a metric based on the approximate count of AppAttest attestations performed on a particular device for your app. Since this is held in the secure enclave of the device it is extremely hard for an attacker to spoof this. A high value might indicate fraud associated with the device. By default, apps with a risk metric of higher than 25 are rejected, but you can set your own maximum risk metric.

In order to use the fraud lookup facility you must set the AppAttest Environment entitlement, even if you are still performing development in the sandbox. You will receive an appattest-apple-err if you haven’t done this.

You may remove the fraud lookup for new AppAttests as follows:

$ approov appattest -removeAuthKey
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
AppAttest fraud lookup authorization removed

Again, you will need an admin or delegate role and provide confirmation to do this.

Setting Maximum Fraud Risk

You can vary the maximum acceptable fraud risk as required. The risk metric grows with user reinstalls of your app, restores from a backup, or transfers of a device between users. The metric may also grow if you use the facility to clear all device state as this causes a new attestation key pair to be generated on the device.

If an individual device exceeds the maximum risk metric then it will fail with the appattest-high-risk flag set.

The Apple provided risk metric values have no specific thresholds and you will need to experiment with a suitable threshold, as described in Accessing Fraud Risk in the Interpret the Metric section.

You can see the risk metric collected by AppAttest by Getting Specific Device Information under the appattest-risk-metric key. You could collect information for devices failing with high risk by adding a filter on appattest-high-risk and then analyzing a sample of the captured results.

You can adjust the maximum acceptable fraud risk metric value as follows:

$ approov appattest -setMaxRisk 10
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
AppAttest max risk set

You will need an admin or delegate role and confirmation to do this. The new value will be used to assess both new and previously performed AppAttest attestations.

Google SafetyNet Integration

This section covers the integration between Approov and Google’s SafetyNet attestation feature. It allows enhanced assessment of the integrity of the device, and provides additional signals that Approov uses to check for rooting or modified devices.

Use of SafetyNet requires Google Play Services to be active on the device. Not all Android devices have Play Services installed or are even able to support it. Thus you should be careful about assuming that SafetyNet is universally available for your Android user base. Note also that in order to use SafetyNet your app must specify the appropriate packages in the gradle build.

In order to use SafetyNet you must use an SDK that is version 2.4.0 or later. If this option is used then the Android Approov SDK must make a call to perform a SafetyNet attestation on the device. This needs to be done on the first Approov fetch after installing the app. Performing this operation requires additional network connection(s) and CPU processing time, over which the Approov SDK has no control. This can substantially delay the fetch operation on the Android platform by adding up to 3500ms of additional latency.

How the SafetyNet Integration Works

If SafetyNet is enabled then the Approov SDK initiates an attestation the first time that app is launched after installation. The amount of time that this takes is highly dependent upon the device and can take several seconds. In order to perform this attestation, a SafetyNet API key must be added to your account. The attestation involves analysis of the device filesystem integrity and a communication with Google servers. Upon success a SafetyNet token is provided which is then transmitted to the Approov servers for verification as part of the overall enhanced attestation process performed by Approov.

In order to prevent any possibility of a replay of known good SafetyNet tokens, it contains a nonce value that is generated by the Approov servers. This is checked as part of the overall analysis of the SafetyNet token to ensure that it is a live token generated as part of the current attestation transactions.

The full validity of the SafetyNet token is checked, including analysis of its certificate chain to ensure that the token was definitely issued by Google servers. This does not require any communication between Approov and Google servers.

If there are any issues with the SafetyNet token, then these are reflected in the device property flags that are collected as follows:

  • safetynet-completed: Indicates that a SafetyNet token has been received by Approov for the device at some point.
  • safetynet-fail-cert: Indicates that the apkCertificateDigestSha256 field in the SafetyNet token does not match an expected app signing certificate. This test is done in addition to the normal Approov operation which also checks the authenticity of the app. This flag can only be asserted if Android App Signing Certificates have been setup for the account.
  • safetynet-fail-integrity: Indicates that the SafetyNet basicIntegrity flag was false. This indicates that the device is likely to have been tampered with in some way, and is likely to be rooted or an emulator.
  • safetynet-fail-profile: Indicates that the SafetyNet ctsProfileMatch flag was false. This means that the device is not running a version of Android that has passed Google’s compatibility testing.
  • safetynet-fail-token: Indicates that the SafetyNet token is invalid in some way, such as not being signed correctly or the nonce value is not as expected. This almost certainly indicates some kind of hacking attempt.
  • safetynet-performed: Indicates that a SafetyNet token has just been received by Approov.
  • safetynet-unavailable: Indicates that SafetyNet was not available. This may be because it is not supported on the device, the Google quota has been exceeded or because the app has not been built to include the necessary SafetyNet Google library (see App Build Requirements).

These flags are used in various Rejection Policies to determine if a valid Approov token should be issued. Note that most rejection policies do not make the receipt of a SafetyNet token mandatory. However, the policy strict does do so but you should be aware that any devices unable to perform a SafetyNet check will be unable to get a valid Approov token.

Since obtaining a SafetyNet token is an expensive operation, the results are recorded by Approov and are persisted against the device ID. This means that the app should only suffer the extended latency to obtain a SafetyNet token on the initial launch after installation. You might consider prefetching an Approov token in the background to make this delay less obvious.

It might not be possible to obtain a SafetyNet token with the most likely reasons being one of the following:

  • Device does not support it
  • SafetyNet usage quota was exceeded
  • SafetyNet service was temporarily down
  • Device had poor device network access

In this case subsequent Approov fetches do not retry, However, each time the app on the device is restarted a fresh attempt will be made until a SafetyNet attestation has been successfully performed.

Note that the SafetyNet API key is transmitted dynamically to your running apps. This allows you to change the API key without having to redeploy your apps. Futrhermore, since the API key is not held statically in your app’s APK image it cannot be reverse engineered and attacked. This prevents some common attack vectors such as repeated fake SafteyNet attests using your API key to exceed your usage quota, so that subsequent attempts fail for legitimate reasons.

Getting a SafetyNet API Key

You need to Obtain an API key from Google in order to use the SafetyNet API. This key must then be made available in your Approov account.

There are a number of steps to this process. Firstly, if you have not previously used Google APIs in your developer account then you need to follow the instructions in Getting Started. You will need to enable API access and link it to your developer account in the following screen:

Google API Access Enable

Go to the API Library page in the Google console for your developer account:

Google API Library

Search for and then select the Android Device Verification API. The dashboard screen then appears:

Enable Device Verification

Click the button to enable it. You should then see a screen like this:

Android Device Verification Enabled

This shows a graph of the usage of the API which you may consult later once SafetyNet is in use. Next you will need to obtain a credential (i.e. SafetyNet API Key) to use it. If the Create Credentials button appears, click on it to generate an API key. Otherwise, click the All API Credentials drop-down list, then select the API key that’s associated with your project that has enabled the Android Device Verification API as follows:

Android Device Get Credentials

Whichever route you take to get the API key, you should ultimately end up with a dialog such as this that provides the API key:

Android Device Verification Got Key

Copy and paste this API key as you will need to add it to your Approov account. Remember if you ever revoke this API key then you will need to update your Approov account with the new one, and Approov SafetyNet attestations cannot be performed unless a valid API key is registered in your Approov account.

Setting the SafetyNet API Key

Set the SafetyNet API key as follows:

$ approov safetynet -set XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
SafetyNet API key set

You will need an admin or delegate role and confirmation to do this. Once this is set, Android devices which have not already done so will immediately try and perform SafetyNet attestations when they next connect to the Approov service. Note that this includes all existing users of your app and so consider this when thinking about the initial load against your SafetyNet API quota.

You can always retrieve the configured SafetyNet key with the following:

$ approov safetynet -get
APIKey: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Once you have set your SafetyNet API key, we suggest you launch your app using Approov and then check that device’s state to ensure it has a safetynet-completed property. You can also see SafetyNet related flags in the Metrics Graphs.

Removing the SafetyNet API Key

The SafetyNet API key can be removed as follows:

$ approov safetynet -remove
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
SafetyNet information removed

You will need an admin or delegate role and confirmation to do this. This will immediately stop any usage of the SafetyNet API by your apps. The persisted SafetyNet state for any devices that have conducted a SafetyNet attestation will be retained. If you wish to completely remove any persisted state which may be causing unwanted Approov rejections then consider Clearing All Device State.

App Build Requirements

The SDK .aar cannot provide dependencies on the external libraries that it needs to use. Thus if you wish to make use of SafetyNet you must add the appropriate libraries in the dependencies part of your app’s build.gradle file as follows:

implementation 'com.google.android.gms:play-services-safetynet:18.0.1'

If the Approov SDK inside your app is unable to resolve dependencies to the required Google Play services, then the message Google GMS services not available or Google SafetyNet not available will be logged when the Approov SDK is initialized. We suggest you check your integration by launching the app with a SafetyNet API key set and then Getting State of a Device using the device’s ID. If SafetyNet has been successfully carried out then you will see safetynet-completed as one of the properties of the device.

If you are currently using Appcompat in your app then you may be forced to update older compat-v7 versions to allow use of the latest Google Play Services, see this.

Signing Certificate Integrity

The SafetyNet token may include an apkCertificateDigestSha256 claim that provides a SHA256 hash of the certificate used to sign the application. This claim might not be present if the device does not meet even basic integrity requirements. This is in contrast to the Approov app signature analysis which operates even if a device is rooted.

If this claim is present and the signing certificates have been added to the Approov account using approov appsigncert then a comparison is made as an additional check to ensure that the SafetyNet token is consistent with the identity of the calling app. If not then the flag safetynet-fail-cert is set.

Adjusting the SafetyNet API Quota

Performing a SafetyNet attestation causes the device to call a Google API. By default, accounts have a fixed quota of 10,000 requests per day across all apps using the same SafetyNet API key.

Approov will only perform a SafetyNet attestation the first time an app is launched after installation (or after setting the SafetyNet API key, if there is already an installed base of app users). The SafetyNet status is persisted by Approov servers to avoid having to use SafetyNet more frequently. Thus if your typical increase in new users is less than 10,000 per day you can use the standard quota.

If you expect higher traffic than this then you must request an increased quota from Google. When you reach the following questions you can fill them in as follows:

Quota Request

The Approov integration already takes the appropriate measures to minimize the usage of the SafetyNet service.

If you exceed your quota then some devices will not be able to perform a SafetyNet attestation. This is not a problem necessarily (unless you are using the strict rejection policy) as the SafetyNet attestation will be performed the next time the app is restarted and connects to the Approov service. This should help smooth the consumption of your quota. It is only problematic if you are continually exceeding your quota on a day-to-day basis.

Note that there is also a limit of 5 requests per minute from an individual device. However, the design of Approov is such that this limit should never be exceeded.

Secure Strings

This is the underlying SDK feature that implements “Approov Runtime Secrets Protection”. It provides a secure storage capability for secrets or access tokens held by an app. A facility is also provided to predefine secure string values using the Approov CLI. These values are only made available to running apps that pass the selected rejection policy. This provides the usual protections provided by Approov so that only apps passing the attestation process can obtain access to the secrets.

The feature provides an alternative to the use of Approov tokens when Backend Integraton is not possible for whatever reason, perhaps because the backend API is not controlled by the same organization as the frontend app. The two approaches can be used together if required, protecting some backend APIs with Approov tokens and using secure string secret storage for other purposes. In general we suggest you use Approov tokens wherever possible, because they are short lived ephemeral tokens that provide excellent security characteristics. However, secure secret storage provides a viable alternative in other cases that can leverage all of the same Approov app integrity checking capabilities.

The typical use cases are as follows:

  • Predefined Secure String: Some APIs might require an API key or secret in order to access the services. If this value is shipped in the app then it is easily possible to extract it using reverse engineering tools. Moreover, even if the value is obfuscated using an app hardening process it can still be extracted by a Man-in-the-Middle (MitM) proxy between the app and the backend. Predefined secure strings provide an easy solution to remove such secrets from the shipped app code. Instead, the API keys are added as predefined secure strings to your Approov account using the Approov CLI and with key names of your choosing. At runtime the app can then try and retrieve the secured values from the Approov SDK, by requesting the values associated with your chosen key names. This causes the Approov SDK to contact the Approov cloud service and perform the required attestation checks. It is only if these attestation checks pass that the secure strings are delivered to the app. These secrets remain protected at rest by Approov, and accessing them is subject to further attestation checks after a short time interval. Secrets, such as API keys, that need to be transmitted to a backend API need to be protected in transit using either pinning or managed trust roots to ensure they cannot be intercepted at that point. Note that a further advantage of this approach is that the secrets can be updated dynamically without any need to reissue a new app version through the app store.

  • App Instance Secure Strings: The feature also allows secure storage of app specific secret strings. These values are never transmitted to the Approov cloud. Instead they are encrypted at rest in app specific persistent storage using a device specific encryption key. This encryption key is only made available to the app at runtime after passing the Approov attestation checks. Thus these values are secured against extraction when the app is not active, and the temporary decryption of the values when the app is running is subject to passing the Approov attestation. A typical use case is the secure storage of access and refresh tokens obtained from an account login event. These need to be presented on API requests, but need to be protected at rest and in transit to prevent an attacker capturing them to script accesses against API endpoints. The app specific strings can can be protected in transit using either pinning or managed trust roots to ensure they cannot be intercepted at that point.

You should not use the secure strings feature for general storage in your app as accessing entries will sometimes be subject to delay. For example, the initial use of the feature requires a full attestation with its associated network access to Approov servers adding latency and the possibility of failure due to the lack of network connectivity. Once access has been granted, secure strings can normally be accessed without further network activity for a period of about 5 minutes. However, once the temporary access expires another full attestation will be required. You should really only use the feature for holding secrets that need to be presented upon backend API accesses. This way any Approov cloud network accesses will be correlated with the need for network accesses anyway.

You should never cache a secure string in your own app code. Always make a call to fetch the value prior to using it in an API request that needs it. The Approov SDK automatically caches the values in a protected form and only performs a network request if a refresh is required. Moreover, the SDK performs additional fast checks on app integrity every time the secure string is fetched even if it is cached in memory.

Enabling Secure Strings

Secure strings are not enabled by default, and any attempt to fetch them from the SDK will result in a DISABLED / disabled error. Enable the feature using:

$ approov secstrings -setEnabled
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
secure strings enablement updated

You will need an admin role and to provide confirmation to do this. Once enabled it is possible to use app instance secure strings but there will be no predefined strings by default.

The feature can be disabled using:

$ approov secstrings -setDisabled

Again, this will need an admin role and for confirmation to be provided. Note that this will discard all predefined secure string values.

Managing Predefined Secure Strings

You can add predefined secure string values using the Approov CLI. Imagine you wish to protect a secret-value. This might be some sort of API key or client secret that needs to be presented on an API call, but you don’t wish to hard code the value in your app. To access the value it needs to be assigned a key. This is secret-name in this case. Issue the following command:

$ approov secstrings -addKey secret-name -predefinedValue secret-value
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
secure strings updated

You will need an admin role and to provide confirmation to do this. The secret-value will then be available to any running apps that look it up using the key name secret-name and have passed the Approov attestation checks.

You may define up to 16 different secure string values. The key names are limited to a maximum of 64 characters. There is no limit on the length of individual values. However, the complete size of all key names and values is limited to approximately 8KB.

You can retrieve the status of the secure strings at any point with:

$ approov secstrings -get
secure strings feature is enabled
1 predefined string:
  secret-name: secret-value

This shows if the feature is enabled or not, and provides a list of all of the key and value pairings if it is enabled.

Finally, the predefined secure string with the key secret-name can be removed as follows:

approov secstrings -removeKey secret-name
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
secure strings updated

You will need an admin role and to provide confirmation to do this. Any apps that look up this value will start to receive an UNKNOWN_KEY / unknownKey error status from the SDK, which will result in an empty value from a Quickstart integration.

Fetching Predefined Secure Strings

The Quickstart Frontend Integrations provide a method to fetch a secure string, given a parameter of the key. In this case you should provide an empty newDef since you only wish to lookup predefined values.

The integrations allow secrets in headers or URL query parameters to be automatically inserted. Typically this means that an existing secret in the app just needs to be changed to a placeholder value and the actual secret can be inserted, for valid app instances, just in time as the network request is being made. Follow the instructons for your particular quickstart.

If the app fails its integrity check then a REJECTED / rejected status is provided and the secure string is not available (this differs from the behavior of Approov tokens, which would provide an incorrectly signed JWT in this case). Your app implementation will need to handle this gracefully and provide feedback to the user. This may include a retry option, but most rejection causes will likely persist. You should consider the use of Attestation Response Code or Rejection Reasons in order to provide feedback. An Attestation Response Code will provide an alphanumeric code that can only be decoded if it is given to your app support team (and they are setup to decode it). Rejection Reasons will provide a direct indication of the cause of the problem.

The fetch might also fail due to network connectivity issues, in which case you should provide a user initiated retry option.

Secure strings are only supported in version 3.0.0 and later SDKs.

App Instance Secure Strings

Predefined Secure Strings have their values set using the Approov CLI and those same values are accessible to all of your registered Apps. It is also possible to securely store strings for the app instance. This uses the same SDK methods as reading, but uses the newDef parameter for the call to define a new value for the given key name.

For example, suppose your app has received an accessTokenValue and you wish to store that securely in persistent storage for your app. In this case you might store it under the key value access_token. The newDef value should be assigned to accessTokenValue. Excuting the fetchSecureString will then store this value in a protected and encrypted form on the device.

Note that the store only succeeds if the operation returns the value back again. If there is an error of any sort then the value will not have been saved and your code will need to deal with such a situation.

If you store a value with the same key name as one used for a predefined secure string then subsequent accesses to that value will retrieve the local value. That is, the predefined value will be unavailable until the local value is removed.

The Approov SDK stores the string in SharedPreferences, using MODE_PRIVATE for Android and NSUserDefauts for iOS. This persists the secure strings between app restarts. The secure string values are stored in an encrypted form to protect them at rest from analysis tools. The decryption key is only provided to the app from the Approov cloud service if the attestation is passed. Note that the string values are never transmitted to or stored by the Approov cloud service itself, which only manages the encryption key and not the data.

If you try and retrieve a secure string for a value that is not defined at all then you will get an empty value (such as null) returned. Normally this shouldn’t happen because your program logic will ensure that the value is defined before it is used. But be aware that it is possible for the user to manually clear the properties persisted for an app and in that case this status will be returned, so you will need to deal with it gracefully.

Custom JWTs

This feature provides a facility to fetch custom JWTs via the SDK, where most of the payload claims are defined by the app. This is provided for very specific circumstances where it is not possible to use the claim structure of Approov tokens.

One particular use case is for the creation of software statement JWTs for OAuth2 Dynamic Client Registration. Such a JWT needs particular claims that can be provided by the app regarding the properties of that app. This allows a particular app instance to prove that it is a true and valid instance of the particular app type, in order to register itself with an Authorization provider and obtain a per-app instance client secret. This client secret can then be stored securely in the app instance using the Secure Strings feature.

The payload claims that are required are provided to the custom JWT fetch request in the form of a marshaled JSON object. These claim values are included verbatim within the generated custom JWT, except with the following claims added (or usurping the same claim provided in the payload):

  • exp: The expiry time of the JWT. This is set to the same expiry time period as Approov tokens, which is normally 5 minutes but may be shorter for some risky devices.
  • iat: The time that the JWT was issued.
  • did: The base64 encoding of the device ID that requested the custom JWT.

A valid custom JWT is only provided if the app passes the attestation checks. The same choice of signing algorithms is provided for custom JWTs as for Approov token JWTs.

Enabling Custom JWTs

Custom JWTs are not enabled by default, and any attempt to fetch them from the SDK will result in a DISABLED / disabled status error. Enable the feature using:

$ approov customjwt -setEnabled
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
custom JWT enablement updated

You will need an admin role and to provide confirmation to do this. By default custom JWTs will be signed using the HS256 algorithm and the standard acccount secret key.

You can obtain the status of the custom JWT feature at any point using:

$ approov customjwt -get
custom JWT enabled, using account secret

Finally, the custom JWT can be disabled if you have an admin role:

$ approov customjwt -setDisabled

Fetching Custom JWTs

The Quickstart Frontend Integrations provide a method to fetch a custom JWT, given a parameter of a payload to be included within it.

If the app fails its integrity check then a REJECTED / rejected status is provided and the custom JWT is not available (this differs from the behavior of Approov tokens, which would provide an incorrectly signed JWT in this case). Your app implementation will need to handle this gracefully and provide feedback to the user. This may include a retry option, but most rejection causes will likely persist. You should consider the use of Attestation Response Code or Rejection Reasons in order to provide feedback. An Attestation Response Code will provide an alphanumeric code that can only be decoded if it is given to your app support team (and they are setup to decode it). Rejection Reasons will provide a direct indication of the cause of the problem.

The fetch might also fail due to network connectivity issues, in which case you should provide a user initiated retry option.

Custom JWTs are only supported in version 3.0.0 and later SDKs.

Custom JWT Key Set Usage

When the feature is first enabled the HS256 signing algorithm is used for the custom JWT using the account secret. However, it is possible to use Key Sets to select different keys and signing algorithms. This also allows the use of an imported private key if desired.

Assuming the addition of a new key called your-key, you can select this as follows:

$ approov customjwt -keySetKID your-key
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
custom JWT keyset KID changed

An admin role and confirmation is required. The kid claim in the JWT header will be populated with the selected key identifier, and the appropriate signing algorithm and secret is used for subsequently generated custom JWTs.

It is possible to revert back to HS256 and the account secret with the following:

$ approov customjwt -clearKeySetKID
WARNING: this will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
custom JWT keyset KID changed

Again, an admin role and confirmation is required.

Managing Key Sets

When an Approov account is created it is allocated a random secret key that is used by default for Approov token signing or encryption. This provides Approov tokens signed using the HS256 algorithm (or A256GCMKW if an encrypted JWE is selected). The HS256 verification uses the symmetric 512-bit account secret key, which needs to be made available to the backend API, to check the validity of the token.

Key sets allow additional keys to be added to an Approov account, which can then be used to sign or encrypt Approov tokens for specific API domains. This allows the use of different keys for different API domains if required. Moreover, key sets also allow access to a much richer set of signing algorithms. In particular, asymmetric signing algorthms (such as RS256) allow the validity of a token to be verified using only the public key. This avoids the security risks associated with needing to add a symmetric key to the API backend (such as with HS256), which could allow valid Approov tokens to be generated if it were to be compromised.

Key sets may also be used by the Custom JWTs feature too.

Adding a New Key

A new, randomly generated, keyset key can be added as follows. You can specify the name which you wish to give the key and the algorithm used for signing and encryption, as follows:

$ approov keyset -kid your-key -add RS256
successfully added key

In this case a new key named your-key is generated for use with the RS256 signing algorithm. A random RSA private key is generated by Approov and added to your account.

The following signing algorithm are available:

  • HS256, HS384, HS512: These HMAC signing methods use a symmetric key, with differing hashing algorithms. If you use these then you must be careful to secure the symmetric key used to verify them, since it can also be used to create fresh valid tokens.
  • RS256, RS384, RS512: These use RSASSA-PKCS1-v1_5 asymmetric cryptography, with differing hashing algorithms. The Approov tokens are signed with the private key which can be verified in the backend API using the associated public key.
  • PS256, PS384, PS512: These use RSASSA-PSS asymmetric cryptography, with differing hashing algorithms. The Approov tokens are signed with the private key which can be verified in the backend API using the associated public key. The difference from RSASSA-PKCS1-v1_5 is that there is a random element to the signature, which may be advantageous to differentiate Approov tokens if many are being generated with the same expiry timestamp.
  • ES256, ES384, ES512: These use ECDSA asymmetric cryptography, with differing hashing algorithms. ES256 uses curve P-256 (secp256r1), ES384 uses P-384 (secp384r1), and ES512 uses P-521 (secp521r1). The Approov tokens are signed with the private key which can be verified in the backend API using the associated public key.
  • A256GCMKW: This is the only supported encryption algorithm to generate a JWE rather than a JWS. This uses a symmetric key, so if you use this then you must be careful to secure the symmetric key since not only can it be used to decrypt and verify tokens, it can also be used to encrypt fresh valid tokens.

This article provides a good overview of the different options.

Once a new keyset key has been added, it can be referenced by the -keySetKID option for Keyset Key API Addition.

It is also possible to specify a key length override parameter when specifying an algorithm that uses RSA (RS256, RS384, RS512, PS256, PS384, PS512) or symmetric keys (HS256, HS384, HS512, A256GCMKW).

$ approov keyset -add RS256 -keyLength 4096
successfully added key

The default length for an RSA key is 2048 bits, but it may be overridden to 1024 or 4096 bits. The default length for a symmetric key is 256 bits, but may be overridden to 128 or 512 bits.

Note also that in this case no kid parameter was specified. If this is not provided then the key is named using a simple incrementing counter for the account.

The existing Quickstart Backend Integrations are written assuming the default signing algorithm of HS256 and that the account secret key is being used. You will need to make small alterations to these to support different algorithms and the different manner in which public keys are obtained for keyset keys.

It is only possible to have a maximum of 10 keyset keys at any one time.

Listing Keys

The current keys in the keyset can be listed as follows:

$ approov keyset -list
1 key:
 your-key  alg:RS256  apis:your.domain

The algorithm associated with each key is provided, along with a list of any apis that the key is currently associated with for token signing. A given key may be associated with multiple different API domains.

Removing Keys

A keyset key can be removed as follows:

$ approov keyset -kid your-key -remove
key your-key removed

Note that you need an admin role to remove a key from the keyset. Furthermore, you can only remove a key if it is not in use on a particular API domain. If it is in use, you first need to Remove the API Domains before the key can be deleted. This needs to be done with care as it may have an immediate impact on your production apps.

Getting Public Key PEM

It is possible to obtain the PEM file for a specific key within the keyset. This is the encoded form of the public key for the key specified by the -kid option, in PKIX ASN.1 DER format. The encoded public key is a SubjectPublicKeyInfo structure, as defined in RFC5280, section 4.1. Obtain the PEM as follows:

$ approov keyset -kid your-key -getPEM your-key.pem
$ less your-key.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQU...
-----END PUBLIC KEY-----

Various external tools and API gateways support this format to allow the checking of Approov tokens.

It is only possible to obtain a PEM for RSA and ECDSA key types, that use asymmetric cryptography. The command generates a PEM containing only the public key. This enables token verification but not token creation which means public disclosure of the PEM file does not enable a path to unauthenticated access to your API. It does however mean that external parties can determine the validity of Approov tokens which is undesirable. Depending on your security posture and if this does happen, you may still want to change the token secret for the associated APIs.

Getting Keyset JWKS

It is possible to obtain the JSON Web Key Set for all keys in the keyset as follows:

$ approov keyset -getJWKS keys.jwks
$ less keys.jwks
{
  "keys": [
    {
      "alg": "RS256",
      "e": "AQAB",
      "kid": "your-key",
      "kty": "RSA",
      "n": "4NhUHZSl5ws8...",
      "use": "sig"
    }
  ]
}

Note that you need an admin role to get the JWKS for the key set. This is because this will also obtain any symmetric keys in the key set, and these require rigorous security since they allow creation as well as verification of Approov tokens. For asymmetric RSA and ECDSA keys, only the public key is obtained.

Remember that the keys encoded in a JWKS are in base64url rather than base64 encoding.

Importing Keys

It is possible to import a JSON Web Key into the keyset as follows:

$ less byok.jwk
{
  "alg": "RS256",
  "use": "sig",
  "d": "FumDxNCs...",
  "dp": "mUxVEADBN...",
  "dq": "Yv9xjIj5vOo...",
  "e": "AQAB",
  "kid": "byok",
  "kty": "RSA",
  "n": "05yGbvzgIobbtaeJ...",
  "p": "9_NNlMTz_S5jcxORGz...",
  "q": "2ns2LBc5-1f3m7iI...",
  "qi": "TxLIVbqDsTvmhTgmR..."
}
$ approov keyset -import byok.jwk
private key imported

A kid claim must be present and not be the same as any existing key in the key set. The alg and use claims must also be present and be consistent with algorithms supported by Approov, or else the import request will be rejected.

Note that you need an admin role to import a private key. For an asymmetric key, once the private key is imported it is not possible to export it again. Only the corresponding public key may be exported. Extreme care must be taken to secure the file holding the JWK since it contains the private key and can thus be used to create valid Approov tokens.

If you have multiple Approov accounts, then the importing feature allows you to Bring Your Own Key (BYOK) and share them between multiple accounts. This allows Approov tokens generated by different accounts to use the same Approov protected backend API using a common key. In this case the private key should be generated externally to Approov and then imported into the required accounts. Alternatively, you could make the backend API compatible with multiple different key IDs that it can lookup from the token header)

Message Signing

This is an advanced option that enables a method in the SDK to sign arbitrary messages, using HMAC with the SHA-256 algorithm. This ensures strict message integrity between the client app and the backend API, and is also an additional proof that the requests are truly emananting from an app that has passed the Approov attestation process. Message integrity is also assured by Public Key Pinnng, which we strongly recommend that you implement (all of our frontend integration quickstarts do this). We provide message signing as an advanced option for certain situations where an additional level of integrity assurance is required.

When message signing is enabled the Approov account is assigned a random 512-bit secret that is used for the signing process. This secret key is only transmitted to the SDK if it passes attestation and is provided with a valid Approov token. If the attestation fails, and an incorrectly signed Approov token is sent, then an incorrect message signing secret is also provided so that the app’s message signatures will be incorrect.

The client app should concatenate the relevant parts of a request into a single string. This should then be passed to the signing method in the SDK to obtain the signature. The signature should then be added to the request, typically as an additional http header, before the request is issued. It should always be submitted in addition to the Approov token. Moroever, you should always include the Approov token itself as part of the string submitted for signing as this strongly binds the Approov token to the signature and prevents replay attacks (since the Approov token has a short expiration time). The backend server is able to gather the components of the request and build the same single string as the client and calculate the expected signature, knowing the secret message signing key being used. This should match the submitted signature, or else the message has been tampered with in some way during transit or the originator of the message did not have access to the correct secret key.

A recent RFC provides an outline of the issues with implementing signing on http requests. A consistent approach must be used between the client app and the server about which particular headers to be included, and in a consistent order. Moroever, networking intermediaries may subtly transform the message between the client app and the server in semantically valid ways, but this may mean that the message is no longer bitwise equivalent and message signatures fail. To avoid this, care must be taken to transform elements of the request to some canonical form prior to the signing process on both the client and the server.

Even if you are using message signing to verify requests, you should also pass the Approov token. A check should be made on the validity of the Approov token before checking the message signature. A check on the message signature should only be performed if there is a valid unexpired Approov token with a mskid claim matching the known message signing secret key ID. If there is a valid token without an mskid then the request should be treated as legitimate. The reason for this is that the Approov failover system does not include mskid claims in the tokens it generates and so message signatures cannot be generated (or checked) when the failover is active.

Enabling Message Signing

Message signing can be enabled on the account as follows:

$ approov secret -messageSigningKey change
WARNING: changing the message signing key will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
key ID: EXTnGx
encoding: base64
RVhUbkd4b01iQ1N3R3Y2cGM4dVdsTEU1UG14S3VOTVhkVDk1dWstb0xPVFZtSEZkdVRueW1lYmRUZWFmR1U3SQ==

An admin role is required. All further Approov fetches will also transmit the signing secret to the SDK and the key ID for it will appear in the mskid claim in Approov tokens. The generated message signing secret is provided in base64 format. It can also be obtained in other formats.

The command can also be used to change the message signing secret to a new random value if required. Remember that the new secret must be made available to backend systems to do the signature verification.

Getting the Message Signing Key

The current message siging key can be obtained as follows:

$ approov secret -messageSigningKey get-raw
key ID: EXTnGx
encoding: raw
EXTnGxoMbCSwGv6pc8uWlLE5PmxKuNMXdT95uk-oLOTVmHFduTnymebdTeafGU7I

An admin role is required. This example uses get-raw to get the raw secret value which is always 64 characters long. The generated secret only consists of printable characters, to support this.

Note that the key ID, which is included in the mskid claim of Approov tokens, is composed of the first few characters of the raw secret.

You can also obtain a base64 or base64url encoded form of the secret key with get-base64 or get-base64url.

Disabling Message Signing

Message signing can be disabled on the account as follows:

$ approov secret -messageSigningKey clear
WARNING: changing the message signing key will have an immediate impact on your apps in production
ATTENTION: If you wish to continue then please type YES and return: YES
message signing key cleared

An admin role is required. Once disabled, the Approov cloud service will stop adding the mskid claim to new Approov tokens. Furthermore, once running apps receive their next token, the signing secret will be cleared and the message signing method in the SDK will no longer generate signatures.

Prior to going into production you may wish to check the impact of clearing the message signing key, and that this continues to allow backend API operation as expected. This emulates the behavior expected should the Approov cloud system automatically transition to failover operation.

Generating Message Signatures in the App

A method is provided in the SDK that is able to generate the HMAC signature of a given message (interpreted in UTF8 format). The Quickstart Frontend Integrations also provide a method for this that calls the underlying Approov SDK. Signing should only be performed after the Approov SDK has been initialized and an Approov token has been successfully fetched.

The message to be passed to the method should be constructed from the concatenation of the parts of the request which should be subject to signing. The resulting signature can then be added to a header in the request. Make sure that the approach is identical between the apps and the backend so that a consistent message will be constructed, and canonicalized forms are used for any parts of the message subject to legitimate modification by intermediate hops in the communication. Note that we strongly recommend that you always include the Approov token as part of the message.

The result is a base64 encoding of the 256-bit HMAC result. This should be added as an additional header, alongside the Approov token in the request. If the SDK is unable to sign the message then no header should be added. There are a number of possible reasons for this:

  • Message signing has not been enabled for the account
  • The app has failed to fetch an Approov token
  • The Approov cloud failover is in operation rather than the primary system

Message signatures are only supported in version 2.5.0 and later SDKs.

Checking Message Signatures in the Backend

It is important that this message signature checking is only performed in the backend as a step after having checked the Approov token in the normal way, i.e. a correctly signed and unexpired Approov token must be present (that will also be included in the signed part of the request).

A check should then be made to ensure that the Approov token includes a mskid claim. The message siganture should not be checked if this is not present, to allow correct operation with the Approov failover. You should also verify that the key ID matches one held by the backend.

The following provides an example of how the message signature might then be checked in the backend.


try {
    Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
    SecretKeySpec secretKey = new SecretKeySpec(rawSigningSecret.getBytes(), "HmacSHA256");
    sha256_HMAC.init(secretKey);
    String calculatedSignature = Base64.encodeToString(sha256_HMAC.doFinal(message.getBytes()), Base64.NO_WRAP);
    if (!calculatedSignature.equals(providedSignature)) {
        // <Replace this block with the request rejection code>
        Log.e(TAG, "Message signatures do not match, provided=" + providedSignature + ", calculated=" + calculatedSignature);
    }
}
catch (NoSuchAlgorithmException e) {
    Log.e(TAG, "No HMAC support");
}
catch (InvalidKeyException e) {
    Log.e(TAG, "Invalid secret key");
}

The inputs to this process are as follows:

  • rawSigningSecret: The message signing secret obtained from the Approov CLI.
  • providedSignature: The base64 signature as provided on an incoming header. The absence of this header should be considered equivalent to a signature mismatch.
  • message: The overall message gathered from the request, in an ordering consistent with that used by the client app.

Obviously a real example would likely reject traffic with invalid signatures rather than simply log it.

It is not necessary to enforce signature checking on all API endpoints. You may wish to only apply it on particularly security sensitive ones. Of course, there must be consistency between the app and the backend API in these choices.

Android Automated Launch Detection

Approov for Android provides a facility to detect if the app is being launched in an automated way, rather than via the standard launch icon on the device. For instance, this detects if the app is being launched from Android Studio, via an adb shell am start sequence or via monkeyrunner. Typically you would not expect these launches from a production app, and therefore such an automated launch may well be associated with activity that you wish to block. Automated ad clicking commonly uses farms of devices launched and controlled in an automated fashion.

Devices on which automated launching is detected still receive valid Approov tokens (assuming there are no other detected causes for rejection). This is because they still represent untampered instances of the real app running in a standard environment. However, you may optionally select the Annotation Policy of info to force automated launch properties to appear in the annotation of the Approov token.

In order to detect an automated launch it is necessary to provide the Approov SDK with a reference to the Activity. This should be done in the onCreate method of any starting activity for the app. Starting activities are denoted in the AndroidManifest.xml with the appropriate intent filters, for example:

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

A simple call to the Approov SDK as follows notifies it of the Activity. It performs analysis on it to determine if there is evidence of an automated activity start. Note that setActivity cannot be called until after the Approov SDK is initialized, but it is assumed that this will be done in the onCreate method of the Application so it will have been completed first.


public class MainActivity extends Activity {
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Approov.setActivity(this);

Your backend integration can detect the presence of the properties in the anno claim and react accordingly to requests from the device. The possible properties are as follows:

  • non-standard-launch: Indicates that an Android app is being launched in some non standard way. This might simply be due to the use of a custom launcher app on a consumer’s device, but may be used as a risk indicator along with other factors for automated usage.
  • automated-launch: Indicates that an Android app is being launched in some automated way rather than from the standard launcher. For a production app this is a strong indicator of automation that may be associated with some nefarious use of the app.

Metrics Graphs

Metrics graphs provide both live and longer term summary information about your account usage. They can be used to see the total number of devices that have requested Approov tokens over a time period (and therefore what the usage related costs will be) and also show the failures where particular devices have been denied valid Approov tokens. The graphs provide information about the reasons for any such failures.

There are two ways that you can reach the metrics graphs:

(1) Directly via the link that may have been provided in your onboarding email.

(2) The metrics portal can also be reached via an approov command. This automatically opens the metrics information in your browser:

$ approov metrics
opening https://metrics.approovr.com/redirect/test-account/usage?access_token=eyJhbGciOiJ…

The URL being opened is shown in the command line and a new browser window is opened with the relevant information. If the browser does not open for some reason (perhaps because there is no default browser is setup) then the given URL can be pasted in another browser window to view the information.

Note that the browser request or onboarding link contains an access token to authorize viewing of the information. Since this is pasted into a browser, it should be handled with care. It is a specially constructed token that only provides read-only access to the metrics information and no other aspects of the account. If you are ever concerned that this link may have been compromised then you can use the command approov monitoring -refreshMetricsLink and all previous links will be revoked and a new one generated. Note that this same link is shared between all users of the account.

Grafana

The metrics graphs are rendered using Grafana. Please refer to Grafana Getting Started to understand how to use the basic features of Grafana. Note that you will be provided with a fixed set of dashboards showing information from your account and will not be able to edit these dashboards or add new data sources.

A number of different individual dashboards are available for your account, each showing different information and described in subsequent sections. Each dashboard may contain a number of different graphs showing active data from your account. Individual dashboards may be selected using the pull-down menu on the top left hand side of the screen next to the Grafana logo.

Graphs are rendered over a timescale defined in the text box at the top right of the screen. If you click on this then various timescale options are provided. Moreover you can click the refresh button to the right hand side of this initiate a refresh to show the latest data. Options for automatic refresh are also available. Note that times are always shown in UTC, regardless of your local timezone setting. The timescale settings impact all graphs shown on the same dashboard. It is possible to zoom into a graph simply by left clicking on the graph and zooming into the area of interest.

Each graph shows a number of time series, depending upon the graph and the exact circumstances of your account. On many graphs there are numerous time series so it may be difficult to see an individual one. You can restrict the graph to only show a single time series by clicking on it in the legend on the right hand side of the graph. Clicking on it again enables all time series. You can use the control key to perform a multi-select to show an arbitrary set of time series together.

The legend shows the maximum value in the time range being shown. For some graphs an average is also available. Hovering over the graph allows the values to be seen on each selected time series at an arbitrary time.

The authentication method used for Approov Grafana dashboards does not allow the “Share” features to be used. If you wish to share the dashboards you can copy and share the URL generated by the approov metrics command, or in your onboarding email.

The graphs provide access to a Configuration button which lists available Plugins. Note that these are not available for use in your account.

Metrics Naming

The Approov cloud service generates a number of individual metrics for your account. These represent different activities that are occurring in your account and help you see an overview of usage and any potential issues. There are a number of different types of metrics that are described in the following sections.

Summary Metrics

Summary metrics are used to provide an overview of the status of a particular attestation request received from an app associated with your Approov account.

Metric Name Description
pass Indicates that a valid Approov token was issued in response to a mobile attestation.
fail Indicates that an invalid Approov token was issued in response to a mobile attestation because a criteria was not met, depending upon the rejection policy selected. Other metrics will provide information about the reason for the rejection.
fail-bad-request Indicates that a request was rejected outright in response to a mobile attestation because it was incorrectly formed. Under normal circumstances this should not occur, but could indicate a failed attempt to spoof requests for the account to the Approov servers.
pass-web Indicates that a valid Approov token was issued in response to a web protection request.
fail-web Indicates that an invalid Approov token was issued in response to a web protection request because a criteria was not met, depending on the configuration for your web protection services.
error-web Indicates that an error response was issued in response to a web protection request. This may indicate genuine errors received by your web app or a failed attempt to spoof requests. Error details are not available from Grafana, see the Troubleshooting Web Protection Errors section if this represents responses to legitimate requests.

Flag Metrics

Flag metrics provide information about the presence of particular characteristics of devices attesting using your account. These correspond to device properties that have been determined from the running device with a prefix flag- added. Furthermore, whenever these metrics are shown they are either prefixed with pass- or fail- depending on whether the overall request was passed or failed.

Whether a given request is rejected or not will depend on the Rejection Policy associated with the account or requesting device. This means that if the security policy is changed then flags previously associated with passes may become fails (or vice versa).

App Metrics

These are metrics generated depending on the app making the request. This allows an easy assessment of the population of apps, or those associated with a particular problematic behavior. Whenever these metrics are shown they are either prefixed with pass- or fail- depending on whether the overall request was passed or failed. Whether a given request is rejected or not will depend on the Rejection Policy associated with the account or requesting device. Note that app version metrics are only available in the live metrics.

Metric Name Description
app-<os>-<name> The package name of the app that is requesting an Approov token. The app is running on the given os, either ios or and for Android.
appver-<os>-<name>-<version> The package name of the app with its corresponding app version that is requesting an Approov token. The app is running on the given os, either ios or and for Android. This allows tracking of specific versions and the transition to a new version when it is pushed out into the app store.

SDK Metrics

These are metrics generated from statistics collected in each running Approov SDK, which are then aggregated across your entire account. These allow an assessment to be made of the rate of usage of the SDK methods and the prevalence of any errors generated.

Metric Name Description
sdk-calls-fetch-sync Number of calls to made to the synchronous fetchApproovTokenAndWait method in the SDK.
sdk-calls-fetch-async Number of calls to made to the asynchronous fetchApproovToken method in the SDK.
sdk-calls-fetch-sec-string-sync Number of calls to made to the synchronous fetchSecureStringAndWait method in the SDK.
sdk-calls-fetch-sec-string-async Number of calls to made to the asynchronous fetchSecureString method in the SDK.
sdk-calls-fetch-custom-jwt-sync Number of calls to made to the synchronous fetchCustomJWTAndWait method in the SDK.
sdk-calls-fetch-custom-jwt-async Number of calls to made to the asynchronous fetchCustomJWT method in the SDK.
sdk-calls-fetch-config Number of calls to made to the fetchConfig method in the SDK.
sdk-calls-get-pins Number of calls to made to the getPins or getPinsJSON methods in the SDK.
sdk-calls-set-data-hash Number of calls to made to the setDatahashInToken binding method in the SDK.
sdk-calls-integrity-proof Number of calls to made to the getIntegrityMeasurementProof method in the SDK.
sdk-calls-device-proof Number of calls to made to the getDeviceMeasurementProof method in the SDK.
sdk-calls-message-signature Number of calls to made to the getMessageSignature method in the SDK.
sdk-result-success Number of fetch calls resulting in a SUCCESS / success status.
sdk-result-no-network Number of fetch calls resulting in a NO_NETWORK / noNetwork status (assuming the app could subsequently get network access to report this).
sdk-result-poor-network Number of fetch calls resulting in a POOR_NETWORK / poorNetwork status.
sdk-result-mitm-detected Number of fetch calls resulting in a MITM_DETECTED / mitmDetected status.
sdk-id-<value> Number of fetch calls made from the Approov SDK with given value ID.
sdk-arch-<platform>-<processor> Number of fetch calls made from a device with a given processor architecture. The platform may be either ios or android. The processor provides the type of processor used, allowing differentiation between 32-bit and 64-bit systems. Intel architectures for iOS are for the simulator only, whereas Android supports native Intel processor instruction sets.
sdk-version-<value> Number of fetch calls made from the Approov SDK with given value version number. This is suffixed with -bitcode if the SDK is being used in bitcode mode (for iOS).

Policy Metric

The policy metric is prefixed policy- with the remainder of the metric name providing the name of the rejection policy that is being applied to the device. This will typically be the default policy for the account, but may be a device specific policy.

Filter Metrics

Filter metrics are prefixed filter- with the remainder of the metric name as defined using the approov filter -add command. Thus these are user defined labels representing particular matches of filtered values of device attributes in Approov fetches.

Web Protection Metrics

Web protection metrics are generated after integrating a web protection service with one of your web apps; see Web Protection Integration. The metrics are prefixed pass-web- or fail-web- as appropriate. The metrics summarise the activity and failure reasons for your integrated web-protections.

Metric Name Description
pass-web-fpjs A valid Approov token was issued for a web protection request requiring a FingerprintJS check
pass-web-hcap A valid Approov token was issued for a web protection request requiring an hCaptcha check
pass-web-recap A valid Approov token was issued for a web protection request requiring a Google reCAPTCHA check
fail-web-aprv-rate-limit-exhausted An invalid Approov token was issued because a rate limit was triggered for one or more of the integrated web protections
fail-web-fpjs-vis-or-rqst-id-unknown An invalid Approov token was issued because the FingerprintJS lookup failed to recognise the specified VisitorID or RequestID
fail-web-fpjs-timestamp-too-old An invalid Approov token was issued because the timestamp for the FingerprintJS request happened too far into the past. This may indicate a malicious attempt to reuse RequestIDs or that the current Max Elapsed Time setting for the Subscription is too short. See the section on FingerprintJS configuration.
fail-web-fpjs-bot-probability An invalid Approov token was issued because the BotProbability score returned by the FingerprintJS lookup was higher than the configured maximum for the subscription. See the section on FingerprintJS configuration.
fail-web-hcap-request-invalid An invalid Approov token was issued because the hCaptcha lookup responded with the Success property set to false
fail-web-hcap-domain-not-found An invalid Approov token was issued because the hCaptcha lookup responded with a domain that is not in the configured set of acceptable domains. This only triggers if the hCaptcha site in Approov has been configured with a set of domains to check. See the section on hCaptcha configuration.
fail-web-hcap-bad-score An invalid Approov token was issued because the hCaptcha lookup responded with a score that was below the minimum configured for the site. See the section on hCaptcha configuration.
fail-web-recap-request-invalid An invalid Approov token was issued because the reCAPTCHA lookup responded with the Success property set to false
fail-web-recap-action-not-found An invalid Approov token was issued because the reCAPTCHA lookup responded with an action that is not in the configured set of acceptable actions. This only triggers if the reCAPTCHA site in Approov has been configured with a set of actions to check. See the section on reCAPTCHA configuration.
fail-web-recap-domain-not-found An invalid Approov token was issued because the reCAPTCHA lookup responded with a domain that is not in the configured set of acceptable domains. This only triggers if the reCAPTCHA site in Approov has been configured with a set of domains to check. See the section on reCAPTCHA configuration.
fail-web-recap-bad-score An invalid Approov token was issued because the reCAPTCHA lookup responded with a score that was below the minimum configured for the site. See the section on reCAPTCHA configuration.

Live Metrics

The Live Metrics dashboard allows you to see what is happening in an account on a near real time basis. Information shown in the graphs is updated within a maximum of 2 minutes from the event occurring. New data is made available every minute.

Live Metrics

The live metrics are shown across four independent graphs:

  • Live Passes: This shows Summary, Flag, App and Web Protection metrics from requests that pass and for which a valid Approov token was provided. Metrics are prefixed with pass- indicating this status. The pass summary metric shows the total number of mobile app attestation passes, the pass-web summary metric shows the same for passing web protection requests.
  • Live Fails: This shows Summary, Flag, App and Web Protection metrics from requests that fail and for which an invalid Approov token was provided. Metrics are prefixed with fail- indicating this status. The fail summary metric shows the total number of mobile app attestation failes, the fail-web summary metric shows the same for failing web protection requests. For mobile attestations, it is important to understand that this shows the properties of the failing device, but these are not necessarily the properties that caused it to fail. Those are shown in the Live Rejections graph. For web protection requests, this graph includes all causes of failure.
  • Live Rejections: Shows the Flag that are causal for the rejection to be made. These are prefixed with rejection- to indicate this. This graph also shows the Policy Metric which is being applied.
  • Filter Matches: Shows the Filter Metrics for any matches being made to Device Filters that have been defined.

The y axis for the graphs are in terms of the volume of requests (requests per minute). The same device making multiple requests in a time period will be counted multiple times.

During initial development, when there are no production apps in the account also providing data, the graph can be used for quickly determining if requests are reaching the Approov servers and assessing the response made.

Billing Usage

This dashboard provides an overview of the usage of an account over time showing Summary Pass and non-versioned App metrics. A new entry is generated on each hour. For mobile attestation billing, the y axis scale is based on the number of unique device IDs that have been seen since the start of your account’s billing period in the month. For web protection integrations, the y axis shows the accumulated number of web protection requests resulting in valid Approov tokens.

Billing Usage

This figure will grow over the month until it is reset on the “billing day” anniversary each month. The maximum value that the monthly-pass and monthly-pass-web figures reach during the month is used to calculate the account’s usage invoice for the month. Since billing is calculated only on the basis of passing attestation and web protection requests all metrics shown are in fact prefixed monthly-pass.

In addition to the overall figure, mobile app attestation metrics are also provided for each app package name that has been successfully used on the account. This allows an assessment to be made between iOS and Android usage, or for different apps associated with the account.

Hourly Metrics

This dashboard provides an overview of the hourly usage of the account, in terms of the number of different device IDs that used the account in an hour period and the total number of web protection requests that were made. A new sample is output every hour. It shows Summary, Flag, App and Web Protection metrics. This allows assessment on the level of account usage from hour to hour in terms of the count of different devices or web protection requests.

Hourly Metrics

The upper graph shows devices and web protection requests that were granted a valid Approov token in the last hour, and metrics are prefixed with hourly-pass. The lower graph shows the devices and web protection requests that had at least one failure to receive a valid Approov token in the last hour, and metrics are prefixed with hourly-fail. Pass metrics are restricted to a total and per-app package breakdown. Fail metrics also show flags that are a cause of the failure (i.e. those shown with the rejection- prefix in the live metrics). Note that if a device both passed and failed in the last hour then it will be counted in both graphs.

Daily Metrics

This dashboard provides an overview of the daily usage of the account. The number of devices and web protection requests are counted throughout the day, until reset at midnight UTC. A new sample is output every hour. It shows Summary, Flag, App and Web Protection metrics. This allows assessment on the level of account usage from day to day in terms of the count of different devices or web protection requests.

Daily Metrics

The upper graph shows devices and web protection requests that were granted a valid Approov token in the last day, and metrics are prefixed with daily-pass. The lower graph shows the devices and web protection requests that had at lest one failure to receive a valid Approov token in the last day, and metrics are prefixed with daily-fail. Pass metrics are restricted to a total and per-app package breakdown. Fail metrics also show flags that are a cause of the failure (i.e. those shown with the rejection- prefix in the live metrics). Note that if a device both passed and failed in the last day then it will be counted in both graphs.

Monthly Metrics

This dashboard provids an overview of the monthly usage of the account. The number of devices and web protection requests are counted throughout the month, until reset at midnight UTC on the billing day of the account. A new sample is output every hour. It shows Summary, Flag, App and Web Protection metrics.

Monthly Metrics

The upper graph shows devices and web protection requests that were granted a valid Approov token in the month, and metrics are prefixed with monthly-pass. The lower graph shows the devices and web protection requests that had at lest one failure to receive a valid Approov token in the month, and metrics are prefixed with monthly-fail. Pass metrics are restricted to a total and per-app package breakdown. Fail metrics also show flags that are a cause of the failure (i.e. those shown with the rejection- prefix in the live metrics). Note that if a device both passed and failed in the last month then it will be counted in both graphs.

SDK Metrics

This dashboard shows live SDK metrics that are being collated from running Approov SDKs in apps associated with the account. These are aggregated across all SDKs with a new sample being generated every minute. These metrics are not directly associated with a pass or fail.

The metrics are shown across three independent graphs:

  • SDK Fetches: Shows the sdk-result metrics. These in particular can be used to determine if there are any widespread issues affecting running SDKs. The vertical scale is of succeeding or attempted fetches. Note that if a particular SDK instance is without network for an extended period while trying to perform fetches then when it reconnects the count of attempts made is associated with that connection time, which may cause a spike in the graph for sdk-result-no-network or sdk-result-poor-network results.
  • SDK Calls: Shows the sdk-calls metrics. These are related to counted calls made in the SDK, and will typically be larger than the number of actual Approov fetches. For instance, calls to get an Approov token when one is already cached are counted here.
  • SDK Libraries: Shows the sdk-arch and sdk-id metrics. This shows the particular architectures and library IDs that are in use.

SDK Metrics

Exporting Data

It is possible to export raw graph data into a CSV file using the menu available on the right click button on each graph, as follows:

Export CSV

Service Monitoring

Approov provides facilities that allows monitoring of the status of your account. A healthcheck API endpoint is supported, along with monthly or even daily summaries of usage and notification emails if there is a certificate problem with one of your endpoints.

Summary Emails

Summary emails can be sent automatically at the end of each billing month. This is typically on the anniversary day within the month of your signup to the Approov service. Typical emails are of this form:

Summary Email Example

Information provided is as follows:

  • Monthly Usage: Provides an overview of the usage of the account in the last month, based ont he monthly endpoint of the information in Billing Usage
  • Security Policy: A reminder of the Security Policy that is currently set for your account. This directly impacts which devices are passed and which are failed.
  • Passing Devices: Provides an overview of the properties of the devices which were passed during the month, based on the monthly summary of the information in Monthly Metrics.
  • Failing Devices: Provides an overview of the properties of the devices which failed during the month, based on the monthly summary of the information in Monthly Metrics.
  • Rejection Policy: Provides a list of all of the device properties, a short description of each, and whether they will cause a rejection if detected.
  • Metered Metrics: Provides information about usage for any web protection integration.

The email should be received shortly after midnight UTC on your billing day. The email is copied to all those on the recipient list. The Managing Email Recipients shows how you may update this. Shortly after receiving the summary email you will also receive an invoice or automated credit card charge reflecting the usage shown in the summary email.

API Monitoring

The Approov cloud service is able to monitor your API endpoints to ensure that they are both accessible and that the certificates presented match one or more of the pins you have set in your account. The endpoints are checked every 15 minutes, and a notification email is sent if a problem is detected. This will list each of the monitored API domains that are experiencing an issue.

When you add an API domain, monitoring for it will be activated automatically, unless no pin was added or one was added via local access (implying the API endpoint is not generally visible on the Internet). Note that notifications can only be sent if your account’s alert email or email recipients list has been set up. API monitoring alerts are sent to all these email addresses.

You can always set a new API for monitoring as follows:

$ approov monitoring -addAPI your.domain
API monitoring updated successfully

An admin role is required. If the API is not accessible on the standard port of 443 you can use the -port option to select monitoring on a different port.

If an email is sent then, by default, no further ones will be sent for 24 hours. However, you can override this behavior by issuing the following command:

$ approov monitoring -resumeAPINotifications
API monitoring notifications resumed

You will then receive an email again if there is a further problem after the APIs are checked on the next (or a subsequent) 15 minute cycle.

Monitoring for a specific API domain can be removed as follows:

$ approov monitoring -removeAPI your.domain
API monitoring updated successfully

This might be required if the API domain is not accessible from the Approov cloud service, or is not part of your production system and you don’t wish to monitor it continuously.

Managing Alert Email

It is possible to set an email address for receiving API monitoring alerts as follows:

$ approov monitoring -addAlert ops-alert@your.domain
new alert email recipient added

An admin role is required. Be careful with the addition of email addresses as these are not verified at the time of addition. There can only be a single alert email address.

This email will only be sent API monitoring emails, not any summary emails. Thus an email address can be used that will generate an internal alert within your systems to provide immediate notification that there is a problem with your API domains.

You can retrieve the current settings as follows:

$ approov monitoring -get

Producing a response such as:

monitoring emails will be sent to:
  you@your.domain
summary frequency: monthly
alert recipient: ops-alert@your.domain

The alert email can be removed with:

$ approov monitoring -removeAlert
alert email recipient removed

Managing Email Recipients

When your account is first created your email will be setup to receive summary emails and API monitoring alerts. You may add new recipients as follows:

$ approov monitoring -add another@your.domain
new email recipient added

An admin role is required. Be careful with the addition of email addresses as these are not verified at the time of addition. It is possible to have up to 10 different monitoring email recipients.

You can retrieve the current settings as follows:

$ approov monitoring -get

Producing a response such as:

monitoring emails will be sent to:
  you@your.domain
  another@your.domain
summary frequency: monthly

Email recipients can be removed with:

$ approov monitoring -remove another@your.domain
email recipient removed

Setting Summary Frequency

By default only a monthly summary email will be sent. However, it is also possible to opt into a daily summary email that is also sent soon after midnight UTC. It provides a summary of the passing and failing devices from the day, representing the daily endpoint of the data in Daily Metrics.

Opt into daily emails as follows:

$ approov monitoring -selectDailySummary

You may always return to monthly emails only with:

$ approov monitoring -selectMonthlySummary

Emergency Contact

A facility is provided to allow you to set an emergency contact. This will allow Approov to contact your operations team in an exceptional circumstance, such as a major Approov outage or if we detect a serious problem with your account. Ideally therefore you should provide some mechanism to allow us to contact your operations team out of hours.

You can specify a string containing contact information with:

$ approov monitoring -setEmergencyContact "Email at ops@your.domain, out of hours cell +1 23456789"

Remember you can always contact our operations team using the technical support email support@approov.io.

Healthcheck Endpoint

The Approov cloud service incorporates an always-on health monitoring system which actively monitors the state of various internal cloud server components, reporting the overall health state and operational readiness of the primary service. This has an externally accessible API for determining the system health for your account. You can retrieve the URL for this endpoint as follows:

$ approov monitoring -getHealthCheckURL

This provides the URL that you should use for checking your particular account health, e.g.

https://healthcheck.approovr.io/healthcheck/att-your-account

Note that it is common for account names to be prefixed with att-, as shown here. You can query this endpoint to determine the system health as follows:

$ curl -X GET https://healthcheck.approovr.io/healthcheck/att-your-account

This endpoint will return a “200 OK” HTTP response with a JSON body including a HealthState key with value initializing, passed or failed. You would normally expect:

{
  "HealthState": "passed"
}

You can regularly poll this endpoint if you wish to determine the system heath. We do not recommended that you poll more than once a minute. The possible states are as follows:

  • initializing: Appears temporarily after a service restarts one or more components and indicates that the system is gathering data to determine the health status. When this operation is complete, the health monitor will report a passed or failed health state as appropriate.
  • passed: Indicates that the system is up and running correctly. All operations can be used as normal.
  • failed: Indicates that the system has encountered a fault in one or more of its components. The administration APIs may be down which means the service cannot be administered using the approov command line tool. In the unlikely event that the service is unhealthy, the health monitoring system will report a passed state as soon as the system becomes healthy again.

Note that the endpoint only returns the health of the primary service. If there is a problem with the primary service then the failover system is automatically enabled, as described in Cloud Server Redundancy. This means that even if the primary system is being reported as being unhealthy then it is highly likely that Approov tokens will still be being server by the system. Note that if the health endpoint itself is down then it is not possible to determine the system state. However, since this endpoint is not itself served by the primary system and is independent of it, the likelihood is that it remains fully operational.

User Management

It is possible to provide access to your Approov account (via the approov CLI) to other members of your team.

Best Practice

When a new account is created the account holder is issued with dev and admin roles. One the capabilities of the admin role is the ability to add new users, with specific roles.

In a larger organization where multiple personnel need to interact with the Approov service, we expect that there will be some internal control of the access to Approov. We recommend that only a single individual, or small restricted group, should have access to the admin role. We suggest that dev roles are created for each of the individuals that are involved in the development of the apps that use the Approov service. These tokens allow access to all of the facilities required for app development, without more dangerous privileges that might impact apps that are live in production. The dev user roles can be issued to named individuals, preferably for a timescale that represents their likely involvement. Access can be revoked by the administrator at any time.

For larger and more complex teams and projects we recommend having multiple Approov accounts to provide enhanced insulation between development and production operations. If this is a requirement then please contact Approov support.

User Roles

There are five different types of role may be used with the approov command line tool. These are dev, admin, delegate, pentest and automation.

Admin Role

An admin role has additional privileges that are not available for the dev role as follows:

  • Removing app registrations that do not have an expiry date. Typically, this type of registration should be reserved for apps in production and so the removal of such registrations is protected.
  • Removing multiple app registrations in single command invocation using the -removeMatching option.
  • Modifying the security policy applied to the whole account. If this is changed then it could cause invalid Approov tokens to be sent to a range of different users that might cause a partial outage event.
  • Removing or modifying the set of API domains and pins for the account. If these are changed incorrectly then connection may be denied in production apps via an incorrect pin, or if an active API domain is accidentally removed then it will no longer receive valid tokens. All these actions could result in an outage event. Note that new API domains can be added with a dev role as this does not carry a risk of outage.
  • The creation, revocation and listing of user roles as discussed in this section.
  • Creating long lived Approov tokens for server-to-server communication or testing.
  • The extraction and update of the account secret key. This secret must be considered to be extremely sensitive since its possession allows arbitrary valid Approov tokens to be generated.
  • Removing Android app signing certificates.
  • Adding or removing Apple credentials for DeviceCheck usage.
  • Adding or removing Google SafetyNet API keys.
  • Removing or importing keys in the keyset.
  • Exporting the JWKS for the keyset.

Delegate Role

The delegate role has a more limited set of rights, and it will only ever be required in special circumstances. It is used when a 3rd party (who also has their own Approov account) is responsible for developing and registering the app that will be used to access endpoints controlled by this account. The privileges of the role are as follows:

  • Being the destination account for registration cloning using the registration command with the -cloneTo, -cloneToAccounts or -cloneToAllDelegateAccounts options.
  • Obtaining the SDK config using the approov sdk -getConfigString or approov sdk -getConfig commands.
  • Managing the app signing certificates with the approov appsigncert commands.
  • Managing any DeviceCheck configuration with the approov devicecheck commands.
  • Managing any AppAttest configuration with the approov appattest commands.
  • Managing any SafetyNet configuration with the approov safetynet commands.
  • Checking the validity of tokens, and generating example ones, with approov token commands.
  • Viewing metrics for the account, either with a link in the onboarding email, or via approov metrics.

Note that the delegate role provides no rights to get the account secret key, or keyset keys, associated with the account.

Pentest Role

The pentest role has a very limited set of rights. It is designed to allow an independent pentester of the app to modify the security policy applied to a device. This, for example, allows pinning to be disabled or an Annotation Policy to be set showing the reason for a rejection on a device. The privileges of the role are as follows:

  • Adding and removing custom devices. Note that only the devices added using a pentest role can be seen or removed.
  • Obtain the current security policy using approov policy -get.
  • Generate an example Approov token witrh the approov token -genExample command, for testing the backend API.

Automation Role

The automation role has a very limited set of rights. It is intended to support automated scripted use of the approov CLI, especially for Continuous Integration (CI) build systems (see Automated Approov CLI Usage.

  • Downloading the SDK itself using the approov sdk -getLibrary command.
  • Obtaining the SDK config using the approov sdk -getConfigString or approov sdk -getConfig commands.
  • Creating new app registrations with approov registration -add.
  • Getting the current set of APIs and their pins with approov apis -getAll, and associated api and pin commands that only read the API and pinning state. This also includes approov api -check.

Note if there are any other operations you would like to perform from your build and other automation scripts using an automation role, then please contact Approov support.

Adding New User Roles

Additional user roles may only be issued if you have access to an admin role. Here is an example of issuing Approov access to a new user with dev role privileges:

$ approov users -add bob@your.domain
WARNING: you are adding dev role access to account your-account for bob@your.domain (bob)
ATTENTION: If you wish to continue then please type YES and return: YES
onboarding email has been sent to bob@your.domain

The -add option has a parameter of the user email. By default the new user role will have the same duration as the admin role used to create it. Moreover the new user role will be password protected (unless overridden with the -noPassword option). The user will receive an Approov Onboarding email with instructions of how to initialize access and they will be invited to set their password.

By default a dev user role will be created. This has limited privileges as discussed in the previous section. A new admin role may be created as follows, in this case with a shortened validity period of one week.

$ approov users -add boss@your.domain -admin -expireAfter 7d
WARNING: you are adding admin role access to account your-account for boss@your.domain (boss)
ATTENTION: If you wish to continue then please type YES and return: YES
onboarding email has been sent to boss@your.domain

The -expireAfter parameter will normally be specified in terms of the number of days that access will be available for, but years (y) or hours (h) may also be used. Note that it is not possible to generate a user role that has an expiry time after that of the admin role used to create it.

A user name can also be associated with the role. By default this is derived from the part of the email address before the @. You can override this using the -userName option. Quotes must be used around the parameter if you wish to use spaces in the user name.

A new delegate user role may be created as follows:

$ approov users -add appdev@theirdomain.com -delegate
onboarding email has been sent to appdev@theirdomain.com

The delegate role can be provided to an independent app developer, who will then be able to use it to clone registrations from their own Approov account.

A new pentest user role may be created as follows:

$ approov users -add pentester@theirdomain.com -pentest
onboarding email has been sent to pentester@theirdomain.com

The pentest role can be provided to an independent pentester, which will enable them to control security policies for specific devices only, and to generate example Approov tokens for testing.

Note that there is currently a maximum limit of 25 user roles that may be live for any individual Approov account. If this limit is reached then old unused user roles should be revoked to allow the creation of new ones.

Access Expiry Reminders

Approov will send access expiry reminder emails to the holder of the user role. These are sent soon after midnight UTC daily for the few days prior to the expiry to remind the user that their access is about to expire. No further messages are sent if access is revoked or reaches its expiration.

Note that you will also receive expiration reminders about your primary user roles provided when you first initialized access to your Approov account. If you have a paid plan then you should receive a new onboarding email from Approov shortly after the reminder emails are issued.

Listing User Roles

The available user roles can be listed as follows:

$ approov users -list
3 user roles:
  admin-5794 you@your.domain, A N Other, expires 2029-05-08 15:01:05
  dev-0639   you@your.domain, A N Other, expires 2029-05-08 15:01:05
  dev-1234   bob@your.domain, bob, expires 2029-05-08 15:01:05, password protected

This command output provides the information about the active user roles with a unique ID for each. The first part of the ID is the role, which may be dev, admin or delegate. Other information includes the email addresses, user name, expiry date and if password protection is enabled.

Revoking User Access

In some cases it is desirable to be able to revoke the use of a specific user role before its expiry time. This may be necessary if there is a concern that the access has been compromised or the individual that was provided access has left the project. A user role can be revoked as follows:

$ approov users -revoke dev-1234
WARNING: you are revoking dev-1234 for bob@your.domain, bob, expires 2029-05-08 15:01:05
ATTENTION: If you wish to continue then please type YES and return: YES
user access dev-1234 revoked

The user role ID provided as the parameter can be obtained using the -list option. Revocation can take up to 30s. After revocation completes, attempts to use the role will result in an authorization error, e.g.

$ approov registration -list
ERROR: access is revoked
error: Forbidden, while getting management token status

Note that it is not possible to revoke the user roles issued by Approov when you first signed up. If you feel that your access may have been compromised, then please contact Approov support who are able to revoke these roles and then provide new ones.

Resending Onboarding Emails

It is possible to send another onboarding email to an existing user. This is may be desirable if the user is has lost access to Approov for whatever reason, or they wish to access Approov from a different machine and their original onboarding email has expired. You must select an email address that is associated with one or more roles, and use the following command:

$ approov users -sendOnboardingTo bob@your.domain
onboarding email has been sent to bob@your.domain

An onboarding email is sent to the user which will give them 24 hours to install access to Approov on to the machine(s) of their choosing.

Automated Approov CLI Usage

You may wish to use the Approov CLI from within automated scripts, perhaps on remote runner machines for Continuous Integration (CI) systems. In this case the interative approov role mechanism may not be appropriate, since it requires a user to type in the password and the session only lasts for one hour. Thus a mechanism is provided whereby an automation role management token can be defined in a local environment variable to provide Approov account access. This will not be password protected.

An automation role management token has limited rights, but should be sufficient for the operations required in a build environment.

Management tokens must be considered to be sensitive secrets since they allow access to your Approov account. Take care with security when setting these up. Never log them and never commit them to source code repositories.

Creating an Automation Management Token

You should create an automation management token for the purposes of the scripted access. An email address must be provided, for the user that is the custodian of the management token. We suggest you override the user name with information about the intended purpose, or the machine that the management token is going to be used on. For instance:

$ approov users -add you@your.domain -userName "CI Machine" -automation
WARNING: you are adding automation role access to account your-account for you@your.domain (CI Machine)
ATTENTION: If you wish to continue then please type YES and return: YES
automation management token written to automation-1234.tok
set this in an APPROOV_MANAGEMENT_TOKEN environment variable on the machine that requires it

This writes the automation management token to the file automation-1234.tok, in this case. Follow the instructions for Linux, MacOS or Windows to set the APPROOV_MANAGEMENT_TOKEN environment variable.

If you have multiple different build machines then you could consider having a differently named automation managament token for each one. They can then be independently revoked if required. Moreover, any app registrations made will be tagged with the management token name.

If you have also performed an approov init for the same user that is using an automation management token set with APPROOV_MANAGEMENT_TOKEN then you will get a warning on approov CLI command invocations. This reminds you that the APPROOV_MANAGEMENT_TOKEN is usurping the role that would normally be selected. We generally encourage you to not issue approov init for users or machines that will only be using an automation token. You can remove initialized roles by removing the .approov file in the user’s home directory.

Automation Setup on Linux

You can do this easily with the following command:

$ read -r APPROOV_MANAGEMENT_TOKEN < automation-1234.tok; export APPROOV_MANAGEMENT_TOKEN

The parameter automation-1234.tok should point to the file containing the development management token that you received on signup. You can test the environment variable was set by issuing an approov whomai command.

Note that the environment variable APPROOV_MANAGEMENT_TOKEN will only be set while this shell is running. If you want to make the setting more permanent then you can edit your ~/.bashrc file (or equivalent for other shells) and add the line:

APPROOV_MANAGEMENT_TOKEN=eyJhbGciOiJIUzI1NiI…

The string for your development token should be copied from the automation-1234.tok file. Alternatively you can run the read command above in the context of your shell startup. Now any newly created shells have the management token available in the environment so that it is not necessary to make it available on each approov command invocation.

Automation Setup on MacOS

You can do this easily with the following command:

$ read -r APPROOV_MANAGEMENT_TOKEN < automation-1234.tok; export APPROOV_MANAGEMENT_TOKEN

The parameter automation-1234.tok should point to the file containing the development management token that you received on signup. You can test the environment variable was set correctly by issuing an approov whoami command.

Note that the environment variable APPROOV_MANAGEMENT_TOKEN will only be set while this shell is running. If you want to make the setting more permanent then you need to edit your shell initialization file. This is ~/.bashrc for versions prior to Catalina, or ~/.zshrc since Catalina which uses the zsh by default. If you are using a non-standard shell then you will need to consult its documentation. Add the line:

export APPROOV_MANAGEMENT_TOKEN=eyJhbGciOiJIUzI1NiI…

The string for your development token should be copied from the automation-1234.tok file. Alternatively you can run the read command above in the context of your shell startup. Now any newly created shells have the management token available in the environment so that it is not necessary to make it available on each approov command invocation.

Automation Setup on Windows

Open the advanced settings page:

Windows Advanced Settings Page

Then click on the “Environment Variables” button. This opens up another dialog where you can click on the New for user variables to add a new environment variable. The token should be put in the user, rather than system, variables so that it is not accessible to other users of the same machine.

alt_text

The development token string should be copied from the automation-1234.tok file.

Command shells created after setting the value and closing the dialog will have the management token available in the environment so that it is not necessary to make it available on each approov command invocation. You can test that this is correctly setup with an approov whoami command.

Retrieving an Existing Automation Management Token

If you have previously created an automation role management token then you can retrieve its value again as follows. Firstly, list the user roles to find the role ID value (on the left hand side of the listing):

$ approov users -list
...
automation-1234 you@your.domain, CI Machine, expires 2021-12-04 11:47:11
...

You can then obtain the management token itself using the role ID:

$ approov users -getManagementToken automation-1234
management token written to automation-1234.tok