Login
Verify credentials with your user model, then ask the JWT guard to issue a pair:
const user = await User.verifyCredentials(email, password)
const tokens = await auth.use('jwt').login(user)The response contains tokenType, accessToken, expiresIn, refreshToken, and
refreshExpiresIn. Access tokens are signed JWTs. Refresh tokens are opaque, high-entropy values;
only their hashes are stored.
Authenticate
const user = await auth.use('jwt').authenticate()
const claims = ctx.jwtClaimsVerification requires the configured algorithm, issuer, audience, kid, subject, jti, issued-at,
not-before, and expiration claims. An expired access token raises E_TOKEN_EXPIRED; every other
invalid signature or claim fails as unauthorized.
Refresh
const next = await auth.use('jwt').refresh(request.input('refreshToken'))Every successful refresh consumes the presented token and returns a new access token plus a new
refresh token in the same family. With sliding: false, the family keeps its original expiration;
with sliding: true, each successful rotation receives the configured refresh TTL.
Concurrent clients may retry inside reuseGraceMs; the stale token is rejected without treating
that short race as an attack. After the grace period, reuse raises E_REFRESH_TOKEN_REUSE, revokes
every token in the family, emits jwt:refresh_reuse_detected, and creates a jwt.reuse_detected
span. The client must discard the session and require credentials again.
Logout
Protect logout with JWT authentication so the current access claims are available:
await auth.use('jwt').authenticate()
await auth.use('jwt').logout(request.input('refreshToken'))This revokes the supplied refresh token, optionally denylists the current access-token jti, and
clears cookie transport state.
To end every session for a user:
await auth.use('jwt').logoutAll(auth.use('jwt').getUserOrFail())Client behavior
- Keep bearer access tokens in memory, not local storage, when possible.
- Replace the stored refresh token atomically after every refresh.
- Never retry a refresh indefinitely. Reuse detection is a security event, not a transient error.
- Treat 401 responses as session invalidation. Re-authenticate rather than weakening claim checks.