Skip to main content
A JSON Web Token (JWT) is a compact, URL-safe string that carries a signed set of claims about a user: who they are, what they can do, and when the token expires. Because the signature proves the token was issued by your server, you can authenticate a request by validating the token alone, without a session lookup. The @talosjs/jwt component wraps the JOSE library in a single injectable Jwt class that signs tokens with HS256, verifies their signature and expiration, and decodes their payload and header.

What the Jwt class handles

Signing and verification run on the audited JOSE library, so HS256 handling is correct and spec-compliant rather than hand-rolled crypto. A verified token is proof of identity on its own, with no session store to maintain, which suits horizontally scaled services and a middleware-driven request pipeline. create<T> and getPayload<T> are generic, so your custom claims (role, permissions, tenant) are typed end to end. The standard claims iss, sub, aud, exp, iat, nbf, and jti are handled directly: set them on the payload and the class maps them to the right JOSE setters. The signing secret is read from JWT_SECRET via AppEnv and injected by the container, so it never lives in your code.

How it works

The Jwt class is injectable. Its constructor pulls AppEnv from the container and throws a JwtException immediately if JWT_SECRET is missing, so a misconfigured app fails fast at startup rather than at the first request.

Methods

getPayload and getHeader only decode — they perform no cryptographic check. Anyone can craft a token whose payload says role: "admin". Always call isValid (or create it yourself) before trusting a decoded payload.

Algorithms and payload options

The component signs every token with HS256 (HMAC-SHA256, a symmetric algorithm using a shared secret). The header algorithm is fixed. The table below covers the claims and options you control through the payload. JwtExpiresInType is a relative-duration string accepted by exp:

Signing a token

Issue a token on login. Put the user id in sub, set a short expiration, and add any custom claims you want to read back later.
You can also set protected header parameters such as a key id:

Verifying a token

Verify on every request. isValid returns a boolean and never throws, so it is safe to branch on directly.

Decoding without verifying

getPayload and getHeader read the token’s contents without checking the signature. This is handy for inspecting an expired token, reading a kid before verification, or debugging. Treat the result as untrusted until isValid passes.

In an auth flow

The two halves of the flow are: issue a token when the user authenticates, then verify it in a middleware on every subsequent request. The middleware verifies first, then decodes, then attaches the user to the context for the controller. See Authentication for the full login flow and Users for the resolved user model.
Because the middleware short-circuits with context.response.exception(...) on failure, an unauthenticated request never reaches the controller. See Middleware for how the pipeline runs.

Error handling

The constructor throws a JwtException when JWT_SECRET is missing. JwtException extends the framework Exception, so it carries a message, a key, and a status. Catch it to distinguish JWT configuration errors from other failures.
Note that isValid does not throw on a bad or expired token — it returns false. Reserve try/catch for configuration and decoding errors (e.g. getPayload on a malformed string).

Working with tokens safely

Set JWT_SECRET via AppEnv/.env, never in source, and use a long, random value you can rotate when needed. Prefer exp: '15m' for access tokens paired with a separate, longer-lived refresh token, so a leaked access token expires quickly. Always call isValid before reading claims with getPayload, because a decoded payload is attacker-controlled until the signature checks out. The component signs only with HS256, so reject tokens whose header advertises a different alg, and reject anything you did not issue. Use sub for the user id, iss/aud to scope a token to your app, and jti when you need per-token revocation. Centralize verification in an auth middleware so every protected route enforces it the same way, rather than checking tokens in individual controllers.
  • Authentication — the login flow that issues tokens.
  • Users — the user model attached to the request after verification.
  • Middleware — the pipeline where tokens are verified per request.
  • Utilities: JWT — helper utilities for working with tokens.