Access Data Using Sessions
This guide will show you how to implement a session authorization flow to grant temporary elevated access to your frontend applications using sessions.
Key concepts in this guide:
Getting Started
To get started, you will need a Basis Theory account.
Create a Public Application
Next you will need a Public Application that will be used within our frontend web or mobile application. We will be granting this Public Application just-in-time access to read a token within our frontend application using Sessions.
If you do not already have a Public Application, click here to create one.
Create a Private Application
Next you will need a Private Application that will
be used within our backend service. We will be using this private application to create a token and authorize a session to read this token,
so ensure that you have granted at least the token:create
and token:read
permissions.
If you do not already have a Private Application with these permissions, click here to create one.
Create a Token
In order to have a token available to reveal to our frontend application in later steps, we will first create a token. For simplicity, we are creating this token through the Basis Theory API using the Private Application created above, however you can imagine this token could have been collected by a frontend application using Elements.
Run the following in your terminal to create the token:
curl "https://api.basistheory.com/tokenize" \
-X "POST" \
-H "BT-API-KEY: test_priv_1234567890" \
-H "Content-Type: application/json" \
-d '{
"type": "token",
"data": {
"first_name": "Luke",
"last_name": "Skywalker",
"social_security_number": "111-22-3333",
"email_address": "luke@skywalkerranch.com"
},
"containers": [ "/" ]
}'
test_priv_1234567890
with the Private API Key you created in the Create a Private Application step.Create a Session
The first step in the session authorization flow begins with creating a session
in the frontend application. This endpoint returns a session_key
, which can later be used within the BT-API-KEY
header
to authenticate against the Basis Theory API, and a nonce
, which is a one-time use code that will be used to authorize this session.
The following examples illustrate how to create a session through the Elements SDKs, but you can also call the API directly.
- Web
- Android
- iOS
// using the CDN-based version of the basis-theory-js SDK
const bt = await BasisTheory.init("test_pub_1234567890");
const { sessionKey, nonce } = await bt.sessions.create();
val bt = BasisTheoryElements.builder()
.apiKey("test_pub_1234567890")
.build()
val session = runBlocking { bt.createSession() }
val sessionKey = session.sessionKey
val nonce = session.nonce
BasisTheoryElements.createSession("test_pub_1234567890") { data, error in
let sessionKey = data?.sessionKey
let nonce = data?.nonce
}
test_pub_1234567890
with the Public API Key you created in the Create a Public Application step.At this point, the session has not yet been authorized and attempts to use the session_key
will be rejected by the API.
Authorize the Session
Next, we will use the nonce
to authorize the session.
To do this, we will create a secure server-side endpoint to authorize our session.
Creating a Server-Side Endpoint
For illustrative purposes, we show an example of an HTTP-based API with JSON content, written in Node.js + Express and using the Node.js SDK, but you are free to implement this step in any language and technology of your choice. You could even integrate the authorize session operation into another existing API endpoint, if desired.
The key point is that your frontend application will need to provide the one-time use nonce
to this server-side endpoint
so that it can be forwarded to the Basis Theory authorize session API
using the Private API Key created earlier to authenticate.
// example server-side application using Node.js + Express
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const { BasisTheory } = require("@basis-theory/basis-theory-js");
let bt;
app.use(bodyParser.json());
app.post("/authorize-session", async (request, response) => {
if (!bt) {
bt = await new BasisTheory().init("test_priv_1234567890");
}
const { nonce } = request.body;
// authorizing a session returns an empty 200 response
await bt.sessions.authorize({
nonce: nonce,
rules: [
{
description: "Allow reading only our token",
priority: 1,
conditions: [
{
attribute: "id",
operator: "equals",
value: "token_id_1234567890",
},
],
permissions: ["token:read"],
transform: "reveal",
},
],
});
// this response is arbitrary and not required
response.json({
result: "success",
});
});
test_priv_1234567890
with the Private API Key you created in the Create a Private Application step, and token_id_1234567890
with the id of the token created in the Create a Token step.Passing the nonce to the Server-Side Endpoint
This step is entirely up to you to implement in your frontend framework of choice based on how you typically interact with your APIs.
The following example shows how to call our example /authorize-session
endpoint within a JavaScript environment using fetch.
const bt = await BasisTheory.init("test_pub_1234567890");
const { sessionKey, nonce } = await bt.sessions.create();
// note: you would typically also provide some form of authentication on this request to your backend
await fetch("https://my-api-is-hosted-here.com/authorize-session", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ nonce }),
});
Notes and Best Practices
- You must implement some server-side method for authorizing sessions in order to access the Private API Key - only Private Applications can authorize sessions.
- Your server-side endpoint should use some form of authentication to guarantee that sessions are only authorized for known users in your system.
- Your server-side endpoint should apply some form of authorization logic to ensure that sessions are only granted access to tokens that should be accessible to the authenticated user.
- Follow the principle of least privilege. In particular, try to only grant
token:read
ortoken:use
access to specific tokens using conditions, and avoid granting access to entire containers of tokens.
Retrieve the Token
Finally, let's retrieve our token using our newly authorized Session Key.
Retrieving the Token from the API
First, let's run the following curl command in your terminal to inspect the raw HTTP response returned from the API:
curl "https://api.basistheory.com/tokens/token_id_1234567890" \
-H "BT-API-KEY: test_sess_1234567890"
test_sess_1234567890
with the Session Key you received when creating a session and token_id_1234567890
with the id of the token created in the Create a Token step.You should see a JSON response similar to:
{
"id": "token_id_1234567890",
"type": "token",
"tenant_id": "306b9c97-f974-4a87-b7b5-7f286333c4a4",
"created_by": "51df57ce-ef0f-47ff-b523-a08ecb9bad8a",
"created_at": "2022-12-22T15:07:46.6158347+00:00",
"data": {
"first_name": "Luke",
"last_name": "Skywalker",
"social_security_number": "111-22-3333",
"email_address": "luke@skywalkerranch.com"
},
"containers": ["/"]
}
Notice that plaintext token data is returned from the API since we authorized this session to have the
token:read
permission and a reveal
transform.
If we were to make this same request with the original Public API Key instead of the Session Key, the request would have
failed with a 403 error since the Public Application was not permitted to read tokens.
Retrieving the Token in the Frontend
Next, we will illustrate how the frontend application could use the Session Key to natively retrieve the token in plaintext.
- Web
- Android
- iOS
// using the basis-theory-js SDK initialized with elements: false
const token = await bt.tokens.retrieve(tokenId, {
apiKey: sessionKey,
});
const plaintextTokenData = token.data;
// using the basistheory-java SDK
val tokensClient = Configuration.getDefaultApiClient().let {
(it.getAuthentication("ApiKey") as ApiKeyAuth).also { auth ->
auth.apiKey = sessionKey
}
TokensApi(it)
}
val token = tokensClient.getById(tokenId)
val plaintextTokenData = token.data
// using the basistheory-swift SDK
TokensAPI.getByIdWithRequestBuilder(id: tokenId)
.addHeader(name: "BT-API-KEY", value: sessionKey)
.execute { result in
do {
let plaintextToken = try result.get().body
} catch {
// do something with `error`
print(error)
}
}
If you would like to securely display sensitive data within a frontend application while keeping your code out of compliance scope, you should use Elements to reveal sensitive data that was retrieved using a session. Check out our guide to learn more!
Conclusion
🎉 You now know how to implement a session authorization flow within your system to start using sessions within your frontend applications!
Sessions enable you to securely retrieve tokens within your frontend applications to reveal data within Elements, or they can be used enhance the security within Public Applications when performing any token operation.