Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ricardomb-tech/auth-service/llms.txt

Use this file to discover all available pages before exploring further.

Auth Service uses a two-token model: a short-lived, stateless JWT access token that clients present on every API call, and a long-lived opaque refresh token stored server-side that can be exchanged for a fresh access token without re-authentication. This separation keeps the blast radius of a leaked access token small (it expires in minutes) while allowing sessions to stay alive for days without prompting the user to log in again.

JWT Configuration

JWT properties are bound from application.properties into the JwtProperties record under the auth.jwt.* prefix. The record validates all values at startup — a blank secret or an out-of-range TTL will abort the application immediately rather than silently accepting an insecure configuration.
# application.properties
auth.jwt.secret-current=${JWT_SECRET_CURRENT}
auth.jwt.secret-previous=${JWT_SECRET_PREVIOUS:}
auth.jwt.access-ttl=15m
auth.jwt.issuer=auth-service
auth.jwt.secret-current
string
required
The active HS256 signing secret. All new access tokens are signed with this key; incoming tokens are verified against it first.Sourced from the JWT_SECRET_CURRENT environment variable. Must not be blank — JwtProperties throws IllegalStateException at startup if it is.
auth.jwt.secret-previous
string
The previous signing secret, accepted only for signature verification during a rolling key rotation. Tokens signed with this key are still considered valid until they expire, giving in-flight clients time to exchange them for tokens signed with the new current key.Sourced from JWT_SECRET_PREVIOUS. Defaults to an empty string (rotation inactive). Safe to leave blank when not rotating.
auth.jwt.access-ttl
duration
required
Lifetime of each issued access token. Accepts any java.time.Duration-compatible string (e.g. 15m, 1h, 30m).Default: 15mConstraint: Must be a positive duration and cannot exceed 1d. JwtProperties rejects values outside this range at startup.
auth.jwt.issuer
string
The value placed in the iss claim of every issued JWT.Default: auth-service
JWT_SECRET_CURRENT must contain at least 256 bits (32 bytes) of entropy. A shorter secret weakens the HS256 signature and may allow tokens to be forged. Generate a cryptographically secure secret with the command shown below — never use a human-memorable passphrase.

Generating a Secure Secret

openssl rand -base64 32
This produces a 44-character Base64 string that encodes 32 random bytes (256 bits). Use the full output as JWT_SECRET_CURRENT.

JWT Claims

Every access token issued by Auth Service contains the following claims:
ClaimTypeDescription
substring (UUID)The internal account identifier
emailstringThe account’s verified email address
rolesstring[]Array of granted roles, e.g. ["USER"] or ["USER","ADMIN"]
issstringToken issuer — value of auth.jwt.issuer (default auth-service)
iatnumberIssued-at timestamp (Unix epoch seconds)
expnumberExpiry timestamp (Unix epoch seconds)
Example decoded payload:
{
  "sub": "a3f8c1d2-4e56-7890-abcd-ef1234567890",
  "email": "user@example.com",
  "roles": ["USER"],
  "iss": "auth-service",
  "iat": 1715000000,
  "exp": 1715000900
}

Zero-Downtime Secret Rotation

The dual-secret design (secret-current / secret-previous) lets you rotate the HS256 signing key without forcing all current users to re-authenticate. During a rotation window, the service signs new tokens with the incoming key while still accepting tokens signed by the outgoing key.
1

Generate the new secret

Create a fresh 256-bit secret and note the current value of JWT_SECRET_CURRENT:
openssl rand -base64 32
# → e.g. "nK8z3Qp7vR2mWxYjLtAoHsBcDfEgIuJ0"
2

Promote the current secret to previous

Set JWT_SECRET_PREVIOUS to the current value of JWT_SECRET_CURRENT. This tells Auth Service to keep accepting tokens that were signed before the rotation.
JWT_SECRET_PREVIOUS=<old value of JWT_SECRET_CURRENT>
JWT_SECRET_CURRENT=<new secret from step 1>
3

Deploy the updated configuration

Restart Auth Service (or perform a rolling deployment) with both environment variables set. Immediately after restart:
  • All new access tokens are signed with the new JWT_SECRET_CURRENT.
  • Existing tokens signed with the previous key are still accepted until they expire.
No user is logged out during this window.
4

Wait for the rotation window to close

Wait for the duration of auth.jwt.access-ttl (default 15 minutes). After this window, no tokens signed with the old secret can still be in circulation.
5

Clear the previous secret

Once the rotation window has elapsed, remove or blank out JWT_SECRET_PREVIOUS:
JWT_SECRET_PREVIOUS=
JWT_SECRET_CURRENT=<new secret>
Deploy again. Rotation is complete.
Refresh tokens are opaque (not JWTs) and are stored in the database — they are unaffected by JWT secret rotation. Only the short-lived access tokens need to be re-issued after the rotation window.

Token Lifetime Configuration

Refresh token and email-related token TTLs are bound from application.properties into the AuthTokenProperties record under the auth.token.* prefix. These can be overridden per environment without changing code.
# application.properties
auth.token.verification-ttl=24h
auth.token.refresh-ttl=7d
auth.token.password-reset-ttl=1h
auth.token.verification-ttl
duration
How long an email verification token remains valid after it is issued. After this window, the user must request a new verification email.Default: 24h
auth.token.refresh-ttl
duration
Lifetime of an opaque refresh token. A user who has not used the service for longer than this duration will need to log in again.Default: 7dConstraint: Must be a positive duration and cannot exceed 90d.
auth.token.password-reset-ttl
duration
How long a password-reset token remains valid after it is issued. After this window, the user must submit a new forgot-password request.Default: 1h
Shorter access token TTLs (auth.jwt.access-ttl) reduce the damage window if a token is intercepted, but they increase the frequency of refresh requests from clients. 15 minutes is a common balance for web applications. If your clients are mobile apps on unreliable connections, consider raising the refresh token TTL (auth.token.refresh-ttl) rather than the access token TTL.

Build docs developers (and LLMs) love