Skip to content

JWT plugin

This plugin adds support for using JWT in Elysia handlers.

Install with:

Terminal window
bun add @elysia/jwt@next

Set JWT_SECRET to a private signing secret before starting the server. The routes below demonstrate signing and verification; a real sign-in endpoint must verify credentials before issuing a token.

Then use it:

cookie
import { Elysia } from 'elysia'
import { jwt } from '@elysia/jwt'
const app = new Elysia()
.use(
jwt({
name: 'jwt',
secret: process.env.JWT_SECRET!
})
)
.get('/sign/:name', async ({ jwt, params: { name }, cookie: { auth } }) => {
const value = await jwt.sign({ name })
auth!.set({
value,
httpOnly: true,
secure: true,
sameSite: 'lax',
maxAge: 7 * 86400,
path: '/profile',
})
return `Sign in as ${value}`
})
.get('/profile', async ({ jwt, status, cookie: { auth } }) => {
const profile = await jwt.verify(auth!.value)
if (!profile)
return status(401, 'Unauthorized')
return `Hello ${profile.name}`
})
.listen(3000)
headers
import { Elysia } from 'elysia'
import { jwt } from '@elysia/jwt'
const app = new Elysia()
.use(
jwt({
name: 'jwt',
secret: process.env.JWT_SECRET!
})
)
.get('/sign/:name', ({ jwt, params: { name } }) => {
return jwt.sign({ name })
})
.get('/profile', async ({ jwt, status, headers: { authorization } }) => {
const profile = await jwt.verify(authorization?.startsWith('Bearer ') ? authorization.slice(7) : undefined)
if (!profile)
return status(401, 'Unauthorized')
return `Hello ${profile.name}`
})
.listen(3000)

These cookie settings require HTTPS. The header example expects Authorization: Bearer <token>.

This plugin extends config from jose.

Below is a config that is accepted by the plugin.

Name to register the jwt function as.

For example, the jwt function will be registered with a custom name.

app
.use(
jwt({
name: 'myJWTNamespace',
secret: process.env.JWT_SECRET!
})
)
.get('/sign/:name', ({ myJWTNamespace, params }) => {
return myJWTNamespace.sign(params)
})

Because some might need to use multiple jwt instances with different configs in a single server, explicitly registering the JWT function with a different name is needed.

The private key to sign JWT payload with.

Strict type validation for JWT payload.


The following options describe JWT claims and JWS headers supported by jose.

Default: HS256

Signing Algorithm to sign JWT payload with.

Possible properties for jose are: HS256 HS384 HS512 PS256 PS384 PS512 RS256 RS384 RS512 ES256 ES256K ES384 ES512 EdDSA

The issuer claim identifies the principal that issued the JWT as per RFC7519

TLDR; it is usually (the domain) name of the signer.

The subject claim identifies the principal that is the subject of the JWT.

The claims in a JWT are normally statements about the subject as per RFC7519

The audience claim identifies the recipients that the JWT is intended for.

Each principal intended to process the JWT MUST identify itself with a value in the audience claim as per RFC7519

JWT ID claim provides a unique identifier for the JWT as per RFC7519

The “not before” claim identifies the time before which the JWT must not be accepted for processing as per RFC7519

The expiration time claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing as per RFC7519

The “issued at” claim identifies the time at which the JWT was issued.

This claim can be used to determine the age of the JWT as per RFC7519

This JWS Extension Header Parameter modifies the JWS Payload representation and the JWS Signing input computation as per RFC7797.

A hint indicating which key was used to secure the JWS.

This parameter allows originators to explicitly signal a change of key to recipients as per RFC7515

(X.509 certificate SHA-1 thumbprint) header parameter is a base64url-encoded SHA-1 digest of the DER encoding of the X.509 certificate RFC5280 corresponding to the key used to digitally sign the JWS as per RFC7515

(X.509 certificate chain) header parameter contains the X.509 public key certificate or certificate chain RFC5280 corresponding to the key used to digitally sign the JWS as per RFC7515

(X.509 URL) header parameter is a URI RFC3986 that refers to a resource for the X.509 public key certificate or certificate chain [RFC5280] corresponding to the key used to digitally sign the JWS as per RFC7515

The jwk header contains the public JSON Web Key corresponding to the signing key. The separate jku header is a URL for a JWK Set. See RFC7515.

The typ (type) Header Parameter is used by JWS applications to declare the media type [IANA.MediaTypes] of this complete JWS.

This is intended for use by the application when more than one kind of object could be present in an application data structure that can contain a JWS as per RFC7515

Content-Type parameter is used by JWS applications to declare the media type [IANA.MediaTypes] of the secured content (the payload).

This is intended for use by the application when more than one kind of object could be present in the JWS Payload as per RFC7515

Below are the values added to the handler.

Signs a payload to create a JWT.

Type:

sign(payload: Omit<Claims, 'nbf' | 'exp' | 'iat'> & JWTPayloadInput): Promise<string>

Claims is the shape of schema, or any record when no schema is set. JWTPayloadInput holds the registered claims iss, sub, aud, jti, nbf, exp and iat; a value set here overrides the one from config.

Verify a token with the provided JWT config

Type:

verify(jwt?: string, options?: JWTVerifyOptions): Promise<(Claims & Omit<JWTPayloadSpec, keyof Claims>) | false>

Returns the decoded payload, or false when the token is missing or invalid. JWTPayloadSpec holds the registered claims iss, sub, aud, jti, nbf, exp and iat as decoded values. options is passed to jose’s jwtVerify.

Below you can find the common patterns to use the plugin.

Set exp to control token expiration. A cookie’s lifetime and a JWT’s expiration are separate settings.

const app = new Elysia()
.use(
jwt({
name: 'jwt',
secret: process.env.JWT_SECRET!,
exp: '7d'
})
)
.get('/sign/:name', async ({ jwt, params }) => jwt.sign(params))

This will sign a JWT with an expiration date 7 days from now.

Type to search the documentation.

    Up arrowDown arrow to navigateEnter to selectEscape to close