Skip to Content
chalvien 1.0 is released
DocumentationGuidesSecurityAuthenticationJWTJWT Overview

JWT Authentication Overview

This document explains how authentication works in the VMS backend API.

The backend provides authentication independently from the frontend.
The Next.js frontend acts as a pure HTTP client that consumes API endpoints.

Stack

  • Backend: Express + PostgreSQL + Prisma
  • Frontend: Next.js (pure HTTP client)
  • Auth model: JWT access token + refresh token cookie

1. Authentication Architecture

The system uses a two-token strategy:

TokenPurposeStorageLifetime
Access Token (JWT)Authenticate API requestsClient memoryShort (e.g. 15 minutes)
Refresh TokenObtain new access tokenHttpOnly cookieLonger (e.g. 7 days)

2. Access Token (JWT)

The access token is a JSON Web Token (JWT) signed using the HS256 algorithm.

Example request header:

Authorization: Bearer <jwt_token>

The backend verifies the token using a server secret stored in:

JWT_SECRET

3. Typical JWT Payload

Example payload:

{ "sub": "user_id", "email": "admin@example.com", "role": "ADMIN", "iat": 1710000000, "exp": 1710000900 }

Field description:

FieldMeaning
subUser ID
emailUser email
roleAuthorization role
iatIssued at timestamp
expExpiration timestamp

4. Authentication Flow

Step 1 — Login
POST /api/auth/login

Response:

{ "accessToken": "<jwt>" }

Cookie set:

refresh_token (HttpOnly)
Step 2 — Call Protected API

Client sends:

Authorization: Bearer <jwt_token>

Example:

GET /api/orders
Step 3 — Token Expired

If the access token expires:

POST /api/auth/refresh

The refresh token cookie is automatically sent.

Response returns a new access token.

5. Refresh Token

Refresh tokens are:

  • Stored as HttpOnly cookies
  • Not accessible from JavaScript
  • Sent automatically by the browser

Default cookie settings:

Name: refresh_token HttpOnly: true Path: /api/auth Secure: true (production) SameSite: Strict

6. JWT Secret

The JWT secret is a strong random string used to sign tokens.

Environment variable:

JWT_SECRET=<secure_random_string>

Never commit this value to Git.

7. How to Generate a Secure JWT Secret Using Node.js

Run the following command in your terminal:

node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"

Example output:

3e8c5b2c71f9a8f2f50d38b9f6c44a9b7f62f80a9fbbd4a2c86f4c4e33f5c74d4a4b6a7f0a7d8a6b5e2e2d6f8e5d4a1b

Add it to your .env file:

JWT_SECRET=3e8c5b2c71f9a8f2f50d38b9f6c44a9b7f62f80a9fbbd4a2c86f4c4e33f5c74d4a4b6a7f0a7d8a6b5e2e2d6f8e5d4a1b

Typical values:

ACCESS_TOKEN_TTL = 15 minutes REFRESH_TOKEN_TTL = 7 days

Example .env configuration:

JWT_ACCESS_TTL=15m JWT_REFRESH_TTL=7d

9. Security Best Practices

Always follow these rules:

Keep JWT_SECRET private

  • Store only in environment variables
  • Never commit to Git

Use short-lived access tokens

Reduces damage if leaked.

Use HttpOnly refresh cookies

Prevents XSS attacks.

Use HTTPS in production

Required for secure cookies.

Validate roles server-side

Never trust role data from frontend.

10. Backend Responsibility

Authentication logic lives entirely in the Express API.

The Next.js frontend:

  • does not manage sessions
  • does not store refresh tokens
  • only sends HTTP requests

The backend remains the single source of truth for authentication.