Token Containers
Token containers are a feature in SlashID that extend 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 SlashID.
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
"jti": "container-token-id", // 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
"sub": "person-id", // subject; a unique identifier for the person authenticated
// -- SlashID custom claims --
"user_token": "aaa.bbb.ccc", // a SlashID user token as a signed and encoded JWT; always included
"oidc_tokens": [
// information about OIDC tokens issued by third-party IdPs; only present if the user authenticated with SSO
{
"authn_id": "abcdef12-3456-7890-abcd-ef1234567890", // a unique identifier for the authentication that caused these tokens to be issued
"token_types": ["access", "refresh", "id"], // a list of the token types issued
"provider": "google", // the IdP used for SSO
"client_id": "client_id@google", // the client ID used to obtain these tokens
"oidc_groups": ["admins", "users"] // a list of groups that this user belongs to in the third-party IdP
}
]
}
A SlashID token container will always include a valid SlashID 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 user token
"iat": 234567, // issued at; the time at which the user token was issued
"jti": "user-token-id", // a unique identifier for the user token
"iss": "slashid", // the issuer of the user token
"nbf": 987654, // not before; the time before which the user token will not be accepted
"aud": "org-id", // audience; the intended recipient of the user token
"sub": "person-id", // subject; a unique identifier for the person authenticated
// -- SlashID custom claims --
"first_token": true, // boolean indicating whether this is the first token issued
"person_id": "person-id", // a unique identifier for the person authenticated. Usually the same as `sub`
"person_type": "regular", // Indicates if the person is "regular" or "anonymous"
"prev_anonymous_person_id": "anonymous-person-id", // When present the specified anonymous person was being used prior to the signin.
"oid": "abc-123-def", // the organization ID. Usually the same as `aud`
"region": "region", // the geographic region where the person's data is stored.
"prev_token_id": "old-user-token-id", // the ID of the previous user 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": "[email protected]"
},
"method": "email_link",
"timestamp": "2023-04-30T08:48:33.867846988Z"
},
{
"handle": {
"type": "email_address",
"value": "[email protected]"
},
"method": "webauthn",
"timestamp": "2023-05-15T18:00:14.185639586Z"
}
],
"groups": ["group1", "group2"], // a list of groups that this user belongs to
"groups_claim_name": "groups", // the name of the claim where the list of groups is stored
"gdpr_consent_levels": ["consent1", "consent2"] // a list of GRPR consents selected by this user
}
How do I get a token container?
When a user authenticates through SlashID, 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 SlashID
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 SlashID, and so can be used interchangeably when interacting with SlashID services. The token validation endpoint accepts both token container and user token strings, and either can be used as authorization headers with SlashID 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 token information. Your frontend can access the token container using the SDK methods described above.
Suppose you want to use the OIDC tokens in your backend to build a user profile, and use the SlashID 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 SlashiD 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" })
}
The OIDC token information can be used in conjunction with an API key to retrieve the tokens issued by the IdP. The entire SlashID token container can be exchanged for the OIDC tokens it references using the get SSO OIDC tokens endpoint, or you can query available tokens for an individual person using the query SSO OIDC tokens endpoint.