Skip to main content

Fingerprint

Fingerprint provides a powerful mechanism for fingerprinting the browser environment of a user and deriving a visitor ID based on both the raw fingerprint and the history of prior visits for that user. This visitor ID can then be compared against a user identity in the backend system to determine if they match. If they do, then there is a high probability that it is indeed the correct user and operations can proceed. If not, then this may indicate an attempt at account takeover or simply that the user has moved to a different browser environment. In either case, additional verification steps should be introduced into the flow to protect the user’s account.

Fingerprint Signup and Setup

Before proceeding with an integration you must sign up for an account: Fingerprint Signup. Each Fingerprint account can have one or more subscriptions and each subscription needs a Fingerprint public API key and secret API key to work. You should follow the most appropriate JavaScript agent documentation to the point where you obtain an fp.get() result.

tip

Importantly, for best results from the Fingerprint service, you should follow the instructions for adding a subdomain to handle Fingerprint queries: Subdomain setup.

Configure Approov with a Fingerprint Subscription

A Fingerprint subscription can be added by specifying the subscription region and by providing a valid Fingerprint public API key and secret API key. You can add multiple subscriptions: the public API key identifies the target subscription for Approov web protection. The following command would add a subscription in the Rest-of-the-World (RoW) region leaving all other settings at their default values:

approov web -fingerprint -add your-Fingerprint-public-API-key -secret your-Fingerprint-secret-API-key -region RoW

This will output something like the following and requires confirmation:

WARNING: changing the web configuration will have an immediate impact in production
ATTENTION: If you wish to continue then please type YES and return: YES
fingerprint subscription your-Fingerprint-public-API-key added

Listing all the configured web integration properties shows that the new subscription has been added:

approov web -list

Will output something like the following:

Site Key: your-Approov-site-key
Token Lifetime: 120 seconds
Refresh Token Lifetime: 7200 seconds
Fingerprint:
Optional: true
Subscription Key: your-Fingerprint-public-API-key
Region: RoW
Max Elapsed Time: 2.00s
Max Bot Probability: 1.00
Embed Result: false
Max Result Lifetime: 0s

The following table lists properties in order and provides their description:

Property NameDescription
Site KeyThis is the Approov site key you need to use to identify your Approov account in web protection API requests
Token LifetimeThis is the lifetime given to Approov tokens obtained from the Approov web protection service. It may be changed using approov web -setTokenLifetime <seconds>.
Refresh Token LifetimeThis specified the lifetime of the refresh token and determines the duration of an Approov session. The length of an Approov session is also limited by the maximum lifetime of any result obtained from Fingerprint's server (see Max Result Lifetime below). When the Approov session ends, any result obtained from Fingerprint's server must be renewed. The refresh token lifetime may be changed using approov web -setRefreshTokenLifetime <seconds>.
FingerprintThe heading that separates Fingerprint specific properties from general properties and those of other integrations.
OptionalIndicates whether it is optional to provide the result of a Fingerprint identification request for the initial token fetch of an Approov session or not. This defaults to true which allows a valid Approov token to be provided for web protection using another configured integration even if a Fingerprint result is not provided. This property may be unset using approov web -fingerprint -setRequired and reset using approov web -fingerprint -setOptional.
Subscription KeyDisplays the <Fingerprint-public-API-key> used to configure the subscription and serves as the heading for properties related to just this subscription. Note that the <Fingerprint-secret-API-key> is not listed; it is never displayed or logged by Approov. If you use the Fingerprint dashboard to change the secret API key for a subscription, then you can always update the subscription by adding it again with the new Fingerprint secret API key.
RegionThe configured region for the subscription, either RoW or EU. This must match the region specified for the subscription in the Fingerprint dashboard.
Max Elapsed TimeSpecifies the maximum permitted time between a Fingerprint get call and the subsequent Approov token fetch request. The 2 second default matches the delay enforced by the Google reCAPTCHA and hCaptcha flows. To change this value, use the -maxElapsedTime <duration> parameter when you add the subscription.
Max Bot ProbabilityOne of the values returned from a Fingerprint server-side lookup is a BotProbability score. Approov will return invalid tokens if the Fingerprint lookup returns a score higher than the configured max. The default, 1.0, will accept all scores. To change this value, use the -maxBotProbability <score> parameter when you add the subscription.
Embed ResultIf this is true and you have chosen to use encrypted tokens, JWEs, for the target API then the full Fingerprint result object will be included in generated Approov tokens. It defaults to false, use -embedResult when you add a subscription to turn it on.
Max Result LifetimeThis specifies the maximum lifetime of any result obtained from Fingerprint's server, after which it must be renewed. It can be set by using the -maxResultLifetime <value> parameter when you add the subscription. A value of 0, the default, denotes that it is equal to the refresh token lifetime. The duration of an Approov session is determined by the smaller of the maximum result lifetime and the refresh token lifetime (see Refresh Token Lifetime above).
Rate LimitThis is not in the above list because no rate limit was specified, but it may be configured when you add a subscription to specify the maximum number of requests per minute: -rateLimit <limit>. Attempts to make requests beyond the limit will result in an error. The limit is specified in terms of the maximum number of requests per minute. If this is not specified, or set to 0, then no limit is imposed.

To change a subscription you simply add it again with all the properties required for the changed subscription. Each addition of the same Fingerprint public API key completely overwrites the previously stored entry.

Call Approov Web Protection with Fingerprint

Once the site is set up in Approov (and you've waited a couple minutes or so for the configuration to propagate), you can try retrieving an Approov token using the Approov web SDK. For the full documentation of the Approov web SDK please refer to the reference section. The web SDK can be downloaded using the Approov command line tool:

approov sdk -packageID approov.js.zip -getClientPackage approov.js.zip

This writes the latest available web SDK package to the approov.js.zip file. Unzip the file, copy approov.js into your project and load it as part of your web app.

Some example invocations of the Approov web SDK functions are provided below, where the api argument is your Approov protected API domain and result is the result of a Fingerprint identification request made by calling Fingerprint's get() function. Once an Approov session has been initialized, the first Approov token fetch must include the result of a recent Fingerprint identification request, but this is not required for any subsequent Approov token fetches during the same Approov session:

// Import the Approov web SDK
import { Approov, ApproovError, ApproovFetchError, ApproovServiceError,
ApproovSessionError } from '/approov.js'

// Initialize the Approov session
await Approov.initializeSession({
approovHost: 'web-1.approovr.io',
approovSiteKey: 'your-Approov-site-key',
fingerprintPublicAPIKey: 'your-Fingerprint-public-API-key'
})
// ...

// Initial token fetch of Approov session provides the result of the Fingerprint
// identification request
const approovTokenPromise = Approov.fetchToken(api, {fingerprintIDResult: result})

// Subsequent token fetches during an Approov session don't require the result of
// the Fingerprint identification request
const approovTokenPromise = Approov.fetchToken(api, {})

With a small modification the example code provided by Fingerprint can be adapted to call the Approov web SDK function. The example code below is based on the Fingerprint Quick Start Guide and shows how to integrate Fingerprint into a web page so that a Fingerprint identification result is included with the API request:

<html>
<head>
<title>Fingerprint Demo</title>
<script>
// Initialize the Fingerprint agent at application startup.
const fpPromise = import('https://fpjscdn.net/v3/' +
'your-Fingerprint-public-API-key')
.then(FingerprintJS => FingerprintJS.load())
</script>
</head>
<body>
<script>
function onClick(event) {
// Get the Fingerprint visitor identifier when you need it.
fpPromise
.then(fp => fp.get())
.then(fingerprintResult => {
// Perform fetch call to API, passing Fingerprint identification result
// in a header
fetch("your-API-endpoint", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Fingerprint-Result': fingerprintResult
},
body: JSON.stringify(/* JSON data to send */)
}).then(response => {
// Handle API response
})
})
}
</script>
<button id="submit">Submit</button>
<script>
document.getElementById('submit').onclick = onClick
</script>
</body>
</html>

There are few changes needed for integrating Approov into this flow. Add a function (fetchApproovToken) to obtain an Approov token and then call this in place of the Fingerprint identification request call and include the obtained Approov token in the API request. The function fetchApproovToken shows how to integrate Approov web protection in a single function using lazy (re-)initialization of Approov sessions:

<html>
<head>
<title>Fingerprint Demo</title>
<script>
// Initialize the Fingerprint agent
const fpPromise = import('https://fpjscdn.net/v3/' +
'your-Fingerprint-public-API-key')
.then(FingerprintJS => FingerprintJS.load())
</script>
</head>
<body>
<script>
// Fetches an Approov token and refreshes a Fingerprint identification
// result if required
async function fetchApproovToken(api) {
let {Approov, ApproovSessionError} = await import("./approov.js")
try {
// Try to fetch an Approov token
let approovToken = await Approov.fetchToken(api, {})
return approovToken
} catch (error) {
if (error instanceof ApproovSessionError) {
// If Approov has not been initialized yet or the Approov session has
// expired, initialize and start a new session
await Approov.initializeSession({
approovHost: "web-1.approovr.io",
approovSiteKey: "your-Approov-site-key",
fingerprintPublicAPIKey: "your-Fingerprint-public-API-key"
})
// Get a fresh Fingerprint result
let result = await (fpPromise.then(fp => fp.get()))
// Fetch the Approov token
let approovToken = await Approov.fetchToken(api,
{fingerprintIDResult: result})
return approovToken
} else {
throw error
}
}
}

function onClick(event) {
// Get an Approov token
fetchApproovToken("your-API-domain").then(approovToken => {
// Perform fetch call to API, passing Approov token in a header
fetch("your-API-endpoint", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Approov-Token': approovToken
},
body: JSON.stringify(/* JSON data to send */)
}).then(response => {
// Handle API response
})
})
}
</script>
<button id="submit">Submit</button>
<script>
document.getElementById('submit').onclick = onClick
</script>
</body>
</html>

Approov embed token claim for Fingerprint

You may wish to record or evaluate the Fingerprint results in your backend system. Fingerprint properties are added to the embed claim of the Approov token which is a JSON object with a property called fp:your-Fingerprint-public-API-key, where 'your-Fingerprint-public-API-key' is the Fingerprint public API key registered to your account and used in the Approov token request. By default only the visitorId and requestId are included in the token (using the same JSON structure as the full Fingerprint result). The following example shows the full decoded body of an Approov token with the default properties embedded from a Fingerprint request lookup:

{
"exp": 1620146455,
"ip": "1.2.3.4",
"arc": "LL3BRGIELU",
"embed": {
"fp:your-Fingerprint-public-API-key": {
"visitorId": "eZsCHxhztqEOX0ZmOlwi",
"visits": [
{
"requestId": "lsodLAU4ubccLnMzrI3N"
}
]
}
}
}

If the -embedResult flag is used when you register the Fingerprint subscription and you have chosen to use encrypted tokens, JWEs, for the target API then the full results are included in the token. A slightly abbreviated example is shown below:

{
"exp": 1620128085,
"ip": "1.2.3.4",
"arc": "EAM2W37PSU",
"embed": {
"fp:your-Fingerprint-public-API-key": {
"visitorId": "eZsCHxhztqEOX0ZmOlwi",
"visits": [
{
"requestId": "Otc6rGJcax7PrUuby7GA",
"browserDetails": {
"browserName": "Chrome",
"browserMajorVersion": "90",
"browserFullVersion": "90.0.4430",
"os": "Linux",
"device": "Other",
"userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
"botProbability": 0
},
"incognito": false,
"ip": "1.2.3.4",
"ipLocation": { "<IP-keys...>": "<IP-values...>" },
"time": "2021-05-04T11:32:30Z",
"timestamp": 1620127950391,
"url": "<URL-of-the-calling-webpage>",
"tag": {}
}
]
}
}
}

You should now be set up to generate and receive web protection Approov tokens using Fingerprint. For the full reference on the web protection API and the more advanced features that are provided, please see the reference section after the integration summaries. For how to verify Approov tokens in your backend API server please see the section Backend Integration of the Approov Reference Guide and for information as to how to make use of the DPoP (Demonstrating Proof of Possession) token please refer to DPoP Token Use and Verification.