Client-side vaulting writes sensitive user data to a user's vault directly from a mobile or web app. Your backend creates a short-lived client token, and the client uses it to vault, and optionally decrypt, the fields the token names.

Before you start

You need a server-side API key; see API authentication.

Step 1: Use an existing vault or create a new one (server-side)

Each user in your system gets a single Footprint vault. If the user has no fp_id yet, create one from your backend with POST /users.

bash
1curl https://api.onefootprint.com/users \
2    -X POST \
3    -u sk_test_CXUsbCR8j2kH6e5GeEl8eSBnQTIPCUaKpv:

The response returns the new user's fp_id.

json
1{
2  "id": "fp_id_K0q6Eh6Rr3WOOfFBLPiHsr"
3}

Store the fp_id on your user record; every call that reads or vaults data uses it. To bring over data you already hold, see Migrating user data.

Step 2: Create a client token (server-side)

A client token is a short-lived credential that lets client code vault data. Create it from your backend.

A vault holds structured data, such as identity and cardholder fields, and custom key-value data. Footprint validates structured fields on write, so the data is in a known format when you use it in your applications or for reporting and compliance. Custom fields hold any other sensitive user data.

Cards are named, for example card.primary or card.secondary, so a vault holds any number of cards under names you choose. Payment cards explains how identity, card, and custom data are namespaced.

Request a token for the exact fields the client vaults, with the vault scope.

bash
1curl https://api.onefootprint.com/users/fp_id_K0q6Eh6Rr3WOOfFBLPiHsr/client_token \
2    -X POST \
3    -u sk_test_CXUsbCR8j2kH6e5GeEl8eSBnQTIPCUaKpv: \
4    -d '{
5          "fields": [
6            "card.primary.number",
7            "card.primary.cvc",
8            "card.primary.expiration",
9            "card.primary.name"
10          ],
11          "scope": "vault",
12          "ttl": 180
13      }'

The response returns the token and when it expires.

json
1{
2  "expires_at": "2023-05-24T14:15:22Z",
3  "token": "ctok_vJK5Ze2N5fQ1GtE5V770BH8CZtQwXHF1hxowB9Nowh0"
4}

Send the token to your client; the client vaults data with it in the next step.

Step 3: Use the client token to store data in the vault (client-side)

From the client, send the fields to PATCH /users/vault with the token in the x-fp-authorization header.

bash
1curl https://api.onefootprint.com/users/vault \
2    -X PATCH \
3    -H 'x-fp-authorization: ctok_vJK5Ze2N5fQ1GtE5V770BH8CZtQwXHF1hxowB9Nowh0' \
4    -d '{
5            "card.primary.number": "4242424242424242",
6            "card.primary.cvc": "424",
7            "card.primary.expiration": "10/29",
8            "card.primary.name": "Whitfield Diffie"
9      }'

A successful request returns status 200 and an empty object.

Step 4 (optional): Use a client token to decrypt data

The client-side vaulting APIs decrypt data in two ways: structured decryption and downloads.

Structured decrypt example

Structured decryption returns several small fields at once, such as id.ssn9 or card.*.number, and works like its backend counterpart.

On your backend, create a client token with the fields to decrypt and the decrypt scope. The token is safe to pass to your frontend: it expires quickly and is limited to those fields.

bash
1curl https://api.onefootprint.com/users/fp_id_K0q6Eh6Rr3WOOfFBLPiHsr/client_token \
2    -X POST \
3    -u sk_test_CXUsbCR8j2kH6e5GeEl8eSBnQTIPCUaKpv: \
4    -d '{
5          "fields": [
6            "id.ssn9",
7            "card.primary.number"
8          ],
9          "scope": "decrypt",
10          "ttl": 180,
11          "decrypt_reason": "test structured"
12      }'

The response returns the token.

json
1{
2  "expires_at": "2023-07-31T14:15:22Z",
3  "token": "ctok_vJK5Ze2N5fQ1GtE5V770BH8CZtQwXHF1hxowB9Nowh0"
4}

On the client, call the decrypt endpoint with that token. It decrypts any field named when the token was created.

bash
1curl https://api.onefootprint.com/users/vault/decrypt \
2    -X POST \
3    -H 'x-fp-authorization: ctok_vJK5Ze2N5fQ1GtE5V770BH8CZtQwXHF1hxowB9Nowh0' \
4    -d '{
5        "fields": ["id.ssn9", "card.primary.number"]
6      }'

The response returns the decrypted values.

json
1{
2  "id.ssn9": "123-45-6789",
3  "card.primary.number": "4242424242424242"
4}

Download decrypt

Download decryption suits larger objects such as files, and in particular the case where the user downloads the file directly instead of your app decrypting it.

On your backend, create a client token with a single field and the decrypt_download scope.

bash
1curl https://api.onefootprint.com/users/fp_id_K0q6Eh6Rr3WOOfFBLPiHsr/client_token \
2    -X POST \
3    -u sk_test_CXUsbCR8j2kH6e5GeEl8eSBnQTIPCUaKpv: \
4    -d '{
5        "fields": [
6          "custom.paystub_w2"
7        ],
8        "scope": "decrypt_download",
9        "ttl": 180,
10        "decrypt_reason": "download w2 test"
11      }'

The response returns the token.

json
1{
2  "expires_at": "2023-07-31T14:15:22Z",
3  "token": "ctok_vJK5Ze2N5fQ1GtE5V770BH8CZtQwXHF1hxowB9Nowh0"
4}

The client then decrypts and downloads the object with a GET request that carries the token in the path. The response body is the contents of the object named in fields, so your frontend can save it straight to the user's device.

bash
1curl https://api.onefootprint.com/users/vault/decrypt/ctok_vJK5Ze2N5fQ1GtE5V770BH8CZtQwXHF1hxowB9Nowh0

Next steps

Once the data is in the vault, the Vault introduction shows how your backend lists, decrypts, and searches it. Every field a client token can name, with its format, is in Vault fields.