Sessions and JSON Web Tokens

A session is created when a user authenticates with Hanko (either by registering a new account or by signing in to an account). The session is represented by a JSON Web Token (JWT). JWTs encode claims about subjects (users) as JSON objects. They can also include a signature, in which case their structure is that of a JSON Web Signature (JWS). All JWTs issued by Hanko are signed JWSs.

API operations that establish a session (login, registration) return a session token in an X-Auth-Token header.

When using Hanko Elements or the Hanko Frontend SDK, the session token is read from the X-Auth-Token header and used to set a cookie (name: hanko) on the client-side. If you use neither Hanko Elements nor the SDK, you have to take care of storing the session token yourself.

Subsequent requests to protected API endpoints must then provide the session token in a Cookie request header or alternatively in an Authorization header with the Bearer scheme (i.e. Authorization: Bearer <JWT>).

Stateless vs. stateful sessions

Sessions can be configured as either stateless or stateful (server-side) sessions.

  • Stateless: with stateless sessions, a session JWT is generated that contains claims about the user. For all future requests to protected endpoints, the API validates the JWT’s expiry and signature (see below for details on the JWT structure).
  • Stateful (default): with stateful sessions, a JWT is generated in the same way but session validation makes use of a unique identifier that is generated, persisted in the database alongside its association to a user, and stored in the session JWT under the session_id claim. For all future requests, the Hanko API validates the JWT signature and uses the session_id to query the database for a matching active session. Stateful sessions have the benefit of allowing for remote session revocation. This means that if a user is logged in on one device but also has multiple sessions across other devices, the API’s Profile flow allows listing and explicitly terminating the session on those devices. This feature is also reflected in the UI provided by the Hanko Elements’ Profile Component.

To configure the desired session type:

  1. Log in to Hanko Cloud and select your project.
  2. Navigate to Settings > Session.
  3. Under Server side sessions, toggle the desired session type and click Save.

Session validation

JWTs should be parsed and its claims and signature validated to ensure the token is authentic and has not been tampered with or has expired.

Validating stateless sessions

The JWT token signature is generated using the RS256 (RSA Signature with SHA-256) algorithm. It is an asymmetric algorithm, that uses a public/private key pair. The private key is kept secret and stored by the Hanko API. It is used to create the token’s signature. The public key, a JSON Web Key (JWK), is published through the Hanko API’s .well-known/jwks.json endpoint as part of a JSON Web Key Set (JWKS). To validate the JWT:

  1. Fetch the JWKS from the.well-known/jwks.json endpoint.
  2. Parse and validate the JWT using the JWKS. We recommend using a web framework middleware (if you are using one) or a third-party library instead of parsing and validating the token yourself. Use a library that supports the aforementioned signing algorithm (RS256).

Validating stateful sessions

With stateful sessions you can instead use the sessions/validate endpoint to validate the session. You need to provide the session token in the request body. The endpoint validates the token’s expiry and signature and ensures that the encoded session_id matches a persisted session.

The session endpoint returns an object that contains information about the validity of a session, the session token’s expiry as well as the ID of the user the session is associated with. The latter allows you to later retrieve additional user information through public or administrative user management endpoints.

Session termination

Depending on configuration, there multiple ways of (explicitly or implicitly) terminating a session.

Explicit user logout

A user can explicitly request a logout. This requires a request to the /users/logout endpoint. A successful request clears session cookies and, if stateful sessions are enabled, terminates the session associated with the session token.

Limiting session duration

Sessions can be terminated (or: become invalid) by exceeding an expiry. This expiry can be configured by setting the session duration. Session duration determines how long a user remains logged in after authenticating. By default, the session duration is set to 12 hours in the Hanko Cloud Console. You can change this to a value between 1 minute and 1 month to suit your application’s needs.

To change the session duration, follow these steps:

  1. Log in to Hanko Cloud and select your project.
  2. Navigate to Settings > Session.
  3. Under Session duration, set the desired session duration and click Save.

Limiting concurrent session

Sessions can also be (implicitly) terminated by exceeding the number of allowed active sessions. By default, Hanko allows 5 concurrent sessions. If a user establishes another session, then the oldest session becomes invalid.

Stateful (server-side) sessions must be enabled (see: Stateless vs. stateful sessions) to configure concurrent session limits.

To configure the allowed amount of concurrent sessions:

  1. Log in to Hanko Cloud and select your project.
  2. Navigate to Settings > Session.
  3. Under Session limit, enter the desired amount and click Save.

Session JWT structure

The session JWT is a compact JWS. It is a string composed of three base64 URL safe encoded parts (header, payload and signature), separated by a dot (.). The JWT payload contains the claims about a user.

JWT Header

{
  "alg": "RS256",
  "kid": "2288bfa9-3214-4f19-9757-92631190420b",
  "typ": "JWT"
}
alg
string

The algorithm used for signing this token.

kid
string

The key ID indicating which key was used to secure the token.

typ
string

The media type of this token.

JWT Payload

{
  "aud": [ "example.com" ],
  "email": {
    "address": "user@example.com",
    "is_primary": true,
    "is_verified": true
  },
  "exp": 17123108000,
  "iat": 1712307200,
  "session_id": "140f3967-ab87-4caa-80bd-603ac59c545f",
  "sub": "9930ac89-1584-488c-bd63-1607f03ab1e8"
}
aud
string[]

The audience for which the JWT was created. It specifies the intended recipient or system that should accept this JWT. When using Hanko Cloud, the aud will be your App URL.

email
object

An object containing information about the user’s email address.

exp
integer

The (UNIX) timestamp indicating when the JWT will expire.

iat
integer

The (UNIX) timestamp indicating when the JWT was created.

session_id
string

The ID of the session.

sub
integer

The ID of the user.