Skip to main content

Overview

The Juadah API uses JWT (JSON Web Token) based authentication with a dual-token system. Authentication tokens are stored in HTTP-only cookies for enhanced security.

Key Features

  • JWT-based authentication with access and refresh tokens
  • Cookie-based token storage with HTTP-only and secure flags
  • Email verification via OTP (One-Time Password)
  • Role-based access control (Admin and User roles)
  • Automatic token refresh for seamless user experience

Token System

The API uses two types of tokens:

Access Token

Short-lived token (10 minutes) used for API requests

Refresh Token

Long-lived token (10 days) used to obtain new access tokens

Token Storage

Both tokens are stored as HTTP-only cookies:
  • Access Token: Available on all paths with HttpOnly, Secure, and SameSite=none flags
  • Refresh Token: Restricted to /api/refresh path with the same security flags
Tokens are automatically included in requests when using cookies. You don’t need to manually add them to headers.

Registration Flow

Create a new user account with email verification.
1

Send Registration Request

Send a POST request to /api/register with user details.
curl -X POST https://juadah-backend.vercel.app/api/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "fullname": "John Doe",
    "password": "securePassword123",
    "passwordConfirmation": "securePassword123"
  }'
2

Receive Tokens

On successful registration, you receive:
  • User data in the response body
  • Access token in Set-Cookie header
  • Refresh token in Set-Cookie header
  • OTP sent to email for verification
Response (201 Created):
{
  "status": "success",
  "data": {
    "user": {
      "id": 1,
      "fullname": "John Doe",
      "email": "user@example.com",
      "role": "USER"
    }
  }
}
3

Store Cookies

The browser automatically stores the cookies from the response headers:
Set-Cookie: accessToken=eyJhbGc...; Path=/; HttpOnly; Secure; SameSite=None; Max-Age=600000
Set-Cookie: refreshToken=eyJhbGc...; Path=/api/refresh; HttpOnly; Secure; SameSite=None; Max-Age=864000000

Registration Validation

The API validates the following fields:
FieldRequirements
fullnameMinimum 1 character
emailValid email format, must be unique
passwordMinimum 1 character
passwordConfirmationMust match password
New users are assigned the USER role by default. Admin accounts must be created through a different process.

Login Flow

Authenticate existing users and obtain access tokens.
1

Send Login Request

curl -X POST https://juadah-backend.vercel.app/api/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "securePassword123"
  }'
2

Verify Credentials

The API performs the following checks:
  1. Validates email format
  2. Retrieves user from database
  3. Compares password using bcrypt (salt rounds: 10)
  4. Generates new access and refresh tokens
See implementation in src/auth/service.ts:104-175
3

Receive Authentication

Success Response (200 OK):
{
  "status": "success",
  "data": {
    "user": {
      "id": 1,
      "fullname": "John Doe",
      "email": "user@example.com",
      "role": "USER"
    }
  }
}
Error Response (400 Bad Request):
{
  "status": "fail",
  "errors": {
    "code": 400,
    "message": "email or password is incorrect"
  }
}

Token Refresh Flow

Access tokens expire after 10 minutes. Use the refresh token to obtain a new access token without requiring the user to log in again.
1

Detect Token Expiration

When you receive a 401 Unauthorized response, it’s time to refresh the access token.
2

Request New Access Token

The refresh token is automatically sent via cookies.
curl -X GET https://juadah-backend.vercel.app/api/refresh \
  --cookie "refreshToken=eyJhbGc..."
3

Validation Process

The API validates the refresh token:
  1. Verifies JWT signature and expiration
  2. Extracts user data from token payload
  3. Compares token with stored value in database
  4. Generates new access token
See implementation in src/auth/service.ts:177-231
4

Receive New Access Token

Success Response (200 OK):
{
  "status": "success",
  "data": {
    "user": {
      "id": 1,
      "fullname": "John Doe",
      "email": "user@example.com",
      "role": "USER"
    }
  }
}
A new access token is set in the cookies.
The refresh endpoint returns both the user data and sets a new access token cookie. The refresh token remains the same.

Role-Based Access Control

The API supports two user roles with different permissions:

User Roles

Standard user role assigned during registration.Permissions:
  • View products
  • Create orders
  • View own orders
  • Update own profile

Role in JWT Payload

The user’s role is encoded in both access and refresh tokens:
{
  "tokenId": 0.123456789,
  "fullname": "John Doe",
  "email": "user@example.com",
  "role": "USER",
  "iat": 1234567890,
  "exp": 1234568490
}

Security Best Practices

Passwords are hashed using bcrypt with 10 salt rounds before storage.
// From src/lib/Auth.ts:14-16
protected async hashPassword(password: string | Buffer) {
  return await hash(password, 10)
}
All tokens are signed using HMAC-SHA256 algorithm and verified on each request.
// From src/lib/token.ts:17-29
export function verifyToken(token: string) {
  const decoded = verify(token, tokenSecret, {
    algorithms: ['HS256']
  })
  return { decodedData: decoded }
}
Refresh tokens are stored in the database and validated against the stored value to prevent token reuse attacks.

Code Examples

// Registration
const response = await fetch('https://juadah-backend.vercel.app/api/register', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  credentials: 'include', // Important: Include cookies
  body: JSON.stringify({
    email: 'user@example.com',
    fullname: 'John Doe',
    password: 'securePassword123',
    passwordConfirmation: 'securePassword123'
  })
});

const data = await response.json();
console.log(data.data.user);

Troubleshooting

Error: email or password is incorrectSolutions:
  • Verify email format is correct
  • Check password matches the registered password
  • Ensure account exists (try registration if new user)
Error: invalid request, refresh token unavailableSolutions:
  • Ensure cookies are enabled in your client
  • Check that credentials: 'include' is set in fetch requests
  • Verify the refresh token hasn’t expired (10 day limit)
Error: invalid refresh tokenSolutions:
  • Token may have expired (10 day maximum)
  • Token may have been invalidated (user logged out)
  • User needs to log in again to get a new refresh token
Error: this email already existsSolutions:
  • Use a different email address
  • If you own this account, use the login endpoint instead
  • Contact support if you believe this is an error

Next Steps

Error Handling

Learn how to handle API errors gracefully

Products API

Start working with the Products API

Rate Limits

Understand API usage limits and best practices

Payments

Implement payment processing