Skip to main content

Token Containers

Token containers are a feature in /id that extends the idea of an authentication token, making it more flexible and extensible, while retaining a familiar and easy to use structure.

What is a token container?

Token containers are JSON web tokens (JWTs) that include the registered claims as defined in RFC 7519 alongside custom claims used within /id.

The token container payload is structured as follows:

{
// -- JWT registered claims --
"exp": 123456, // the expiration of the token container
"iat": 234567, // issued at; the time at which the token container was issued
"id": "abcdef", // a unique identifier for the token container
"iss": "slashid", // the issuer of the token container
"nbf": 987654, // not before; the time before which the token container will not be accepted
"aud": "org-id", // audience; the intended recipient of the token container

// -- SlashID custom claims --
"user_token": "aaa.bbb.ccc", // a SlashID user token as a signed and encoded JWT; always included
"oidc_tokens": [
// sets of OIDC tokens from third-party IdPs; only present if the user authenticated with SSO
{
"provider": "google", // the IdP used for SSO
"access_token": "xyz123", // access token from the IdP
"id_token": "ddd.eee.fff", // OIDC-compliant identity token from the IdP
"refresh_token": "pqr456", // optional refresh token from the IdP
"expires_at": "123456" // epoch time when the tokens will expire
}
]
}

A /id token container will always include a valid /id user token with an identical expiry to the container. The user token payload has the following structure:

{
// -- JWT registered claims --
"exp": 123456, // the expiration of the token container
"iat": 234567, // issued at; the time at which the token container was issued
"id": "abcdef", // a unique identifier for the token container
"iss": "slashid", // the issuer of the token container
"nbf": 987654, // not before; the time before which the token container will not be accepted
"aud": "org-id", // audience; the intended recipient of the token container

// -- SlashID custom claims --
"first_token": true, // boolean indicating whether this is the first token issued
"person_id": "pid:1234abcd:2", // a unique identifier for the person authenticated
"oid": "abc-123-def", // the organization ID
"prev_token_id": "uvwxyz", // the ID of the previous token (e.g., if the user has authenticated with multiple factors)
"authenticated_methods": [
// the methods the user has authenticated with. Deprecated, see "authentications" claim
"email_link",
"webauthn"
],
"authentications": [
// the methods the user has authenticated with
{
"handle": {
"type": "email_address",
"value": "user@example.com"
},
"method": "email_link",
"timestamp": "2023-04-30T08:48:33.867846988Z"
},
{
"handle": {
"type": "email_address",
"value": "user@example.com"
},
"method": "webauthn",
"timestamp": "2023-05-15T18:00:14.185639586Z"
}
]
}

How do I get a token container?

When a user authenticates through /id, the backend always returns a signed token container, with at least the registered claims and a signed user token. The User class exposed by the SDK provides accessor methods to retrieve the signed and encoded strings for both the token container and the user token, as well as the fields within the user token.

// In a module script
import * as slashid from "@slashid/slashid"
const sid = new slashid.SlashID()

const org_id = "my_org_id" // organization ID, provided on registration with /id

let user = await sid.id(
org_id,
{
type: "phone_number",
value: "+13337777777",
},
{
method: "webauthn",
}
)

// Retrieve the token container string
let token_container = user.tokenContainer
console.log(token_container)

// Retrieve the user token string
let user_token = user.token
console.log(user_token)

// Get the authentication factors
console.log(user.authentication)

How do I use a token container?

Both token containers and user tokens are valid JWTs signed by /id, and so can be used interchangeably when interacting with /id services. The token validation endpoint accepts both token container and user token strings, and either can be used as authorization headers with /id APIs.

One major advantage of the token container structure is that the individual components can be used independently. For example, suppose a user authenticates with SSO, and so the token container has both the user token and the OIDC tokens. Your frontend can access the token container using the SDK methods described above.

Suppose you want to pass the OIDC tokens to your backend in order to build a user profile, and use the /id SDK in another part of your frontend to securely store user attributes. Rather than passing the entire token container to the second part of your app, you can pass the token container to your backend, which can then verify its contents with the /id token validation endpoint. The frontend can extract the user token only and pass it on, and safely discard the token container. The receiving frontend component can recreate the User object and verify the user token, then use it to store attributes:

let user = await sid.id(user_token)

let tokenValidityInfo = await user.validateToken()

if (tokenValidityInfo.valid) {
await user.set({ attr1: "value1" })
}