Skip to content

Pier228/level-0-basic-roles-auth

Repository files navigation

Second Level Logo

Level 0 - Basic Roles Auth

This level represents the entry-level implementation of a role-based authentication system using JWT tokens and cookies. It lays the foundation for managing user access rights based on predefined roles and demonstrates how to combine secure token handling with simple, maintainable authorization logic.

The goal of this level is to introduce the simplest working model of role-based access control (RBAC), where the system restricts access to certain endpoints depending on the user's assigned role. It is designed to be clean, understandable, and easy to extend in more advanced levels.

In this level, you'll find a full-cycle authentication system that:

  • Issues and validates tokens via secure cookies
  • Assigns roles to users
  • Controls route access based on roles

This project is especially useful as a starting point for developers who are building APIs or web applications where permissions and roles are required, and who want to start with a straightforward, yet production-ready, approach.

Table of Contents

Description

This level implements a basic yet secure role-based authentication system that builds upon a hybrid approach combining elements from Level 1 and Level 3 of JWT authentication. Specifically, it integrates:

  • Login + Password authentication (Level 1)
  • Access & Refresh Token mechanism with HTTP-only cookies (Level 1)
  • Access token blocklisting using a caching layer (Redis) to invalidate tokens on sign-out or misuse (Level 3)

The authentication flow avoids any form of 2FA or email verification in this level, focusing instead on a minimal and functional structure suitable for projects that need clear role separation without the complexity of multi-step verification flows.

By blending the simplicity of Level 1 and the enhanced token lifecycle management of Level 3, this implementation offers a practical middle ground between usability and security, while remaining easy to reason about and extend.

The system securely issues JWT-based access tokens and UUID-based refresh tokens, stores them in secure HTTP-only cookies, and ensures logout safety through cache-based blacklisting of expired or revoked access tokens.

This level intentionally strips away components like two-factor authentication (2FA) and email-based confirmation to keep the focus on the core of role-based access logic and token-based session handling.

Features

Authentication

  • Users register via /auth/sign-up by providing credentials: login and password.

Authorization

  • Sign-In Route: Users authenticate via /auth/sign-in using login and password.

  • Secure Routes: Protected endpoints require access and refresh tokens stored in secure cookies.

  • Token Validation Middleware:

    • Every request checks the access_token cookie.

    • If expired, the system uses the refresh_token (also from cookies) to issue a new access token.

    • The refresh token is validated against the database.

    • If the refresh token is invalid or expired:

      • It is removed from the DB.
      • Both cookies (access_token and refresh_token) are cleared.
    • Ensures short-lived access tokens and automatic session invalidation.

Logout Route

  • /auth/sign-out clears cookies, removes the refresh token from the database and add access token to block list to fully log the user out.

Expired Refresh Token Cleanup

  • CRON Job:

    • Runs daily at 04:00 AM.
    • Removes expired refresh tokens from the database to maintain security and performance.

Database Management

  • Prisma ORM: Type-safe PostgreSQL operations via Prisma.
  • Defined Schema: Structured schema for clean and efficient data organization.

Data Validation and Integrity

  • DTO-Based Validation: Request/response schemas based on DTOs ensure consistent and secure data handling.
  • Validation Middleware: Captures and processes invalid or malformed data.

Security Measures

  • Built-in Middleware:

    • CORS, Helmet, and rate limiting for robust protection.
  • XSS Protection:

    • Helmet middleware sanitizes user input.
  • Rate Limiting:

    • Prevents brute-force attempts.
  • Token Storage:

    • Access & refresh tokens stored in HTTP-only, secure, signed, sameSite: 'lax' cookies.

Testing Framework

  • End-to-End Testing:

    • Uses Supertest for API testing and integration assurance.
  • Comprehensive Test Coverage:

    • Ensures high reliability of critical features.

Documentation and Discovery

  • Swagger UI:

    • Available at /api, providing an interactive interface for exploring the API.

Deployment and Containerization

  • Docker Support:

    • Containerized environment for streamlined deployment and scalability.

Protected Routes

  • Security Middleware: Validates user's access or refresh tokens to get access to the user's access or refresh token to get access to the protected route.
  • Roles Guard: Validates the user's role to confirm that he has enough rights to get access to this route.

Access Token Blocklist

  • Access tokens are actively invalidated on logout.
  • A caching layer (Redis or in-memory) stores invalidated tokens with a TTL equal to their remaining lifespan.
  • Incoming requests are checked against the blocklist to prevent reuse of logged-out tokens.

Flexible Caching Support

  • Blocklisted tokens are stored in Redis (preferred) or in-memory fallback.
  • Ensures invalidated tokens are efficiently rejected during their remaining lifetime.
  • Makes the logout experience immediate and secure, even with stateless JWTs.

Tech Stack

Database Structure

  • users table:
    • Stores login, password (hashed) and role (enum Roles).
  • tokens table:
    • Stores refresh tokens and the expiration time linked to a user. Attributes: expires_at and a reference to the associated user.

How It Works

1. User Sign-Up or Sign-In

The user's journey begins when they attempt to register or log in:

  • POST /auth/sign-up: New users provide their login and password to create an account.
  • POST /auth/sign-in: Existing users provide their login and password to authenticate.

2. Server Validation

The server validates incoming data:

  • For sign-up: ensures uniqueness of login and validates data structure.
  • For sign-in: verifies that the user exists and the password is correct.

3. Record Creation (Sign-Up Only)

Upon successful validation during registration, the server creates:

  • A user record (login, hashedPassword, role: User).
  • A token record (expiresAt).

4. Access & Refresh Token Generation

Upon successful authorization or authentication, the server generates a short-lived access token (JWT) for the user. This token contains essential information about the user, such as their ID and role. Also, the server generates the long-lived refresh token (UUID), which is stored in the database.

5. Client-Side Token Storage

The client-side application receives access and refresh tokens inside secured HTTP-only cookies from the server. These tokens will be automatically sent to the server with each request.

6. Accessing Protected Routes

Each time the client accesses a protected route, it automatically sends the access and refresh tokens from cookies with the request.

7. Backend Verification and Authorization

The backend server receives the request and verifies the validity of the access token. If the access token is valid, the request will successfully pass the security middleware and get to the roles guard. If the access token has expired or is undefined, the refresh token will generate a new access token. During this process, the refresh token is rigorously validated against the database. If valid, it’s reissued, but if expired or invalid, it’s immediately revoked (deleted from the database) and both the access_token and refresh_token cookies are cleared from the client. The roles guard gets the request and validates the user's role to confirm that he has enough rights to get access to this endpoint. If everything is okay, the request goes to the controller.

8. User Sign-Out

POST /auth/sign-out clears the cookies, removes the refresh token from the database, and adds the access token to the block list for the remaining duration of its lifetime to ensure full logout.

9. Scheduled Cleanup (CRON Jobs)

The server will automatically start the CRON job to schedule a task that periodically deletes all expired refresh tokens from the database (every day, at 4:00 am).The delete setting in the database models is set up as Cascade, so when the user is deleted, all references to that user will be deleted too.

Endpoints

Method Endpoint Description Required Body Required Auth Required Roles
POST /auth/sign-up Register a new user and set auth tokens login: string, password: string No None
POST /auth/sign-in Login and set access & refresh token login: string, password: string No None
POST /auth/sign-out Clear auth tokens and invalidate session None Yes Any
POST /example/admin This route is available only for admins None Yes Admin
POST /example/staff This route is available only for staff None Yes Admin, Moderator, Owner

For a detailed overview of the available API endpoints, request/response structures, and data models, the Swagger documentation is available at /api. This documentation provides interactive API exploration and helps developers understand and integrate with the API efficiently.

Example Request

POST /auth/sign-in
{
  "login": "exampleLogin312",
  "password": "examplePassword123"
}

Response

Body

{
  "message": "User successfully logged in"
}

Headers

Set-Cookie: access_token=s%...; Path=/; HttpOnly; Secure; Expires=...GMT
Set-Cookie: refresh_token=s%...; Path=/; HttpOnly; Secure; Expires=...GMT

Cookie Configuration

  • httpOnly: true
  • secure: true
  • sameSite: lax
  • signed: true
  • maxAge: 15 minutes for access token and 7 days for refresh token (should be set in milliseconds)
  • path: /

Ось адаптований розділ Security Notes для рівня level-0-basic-roles-auth:


Security Notes

✅ Recommended for Production Use — With Caution

This level provides a minimal yet structured approach to authentication and authorization based on roles, combining essential security features such as login + password authentication, JWT-based access tokens, refresh tokens in HTTP-only cookies, and Redis-based blocklisting for access token invalidation.

By excluding more advanced security layers like email verification, device fingerprinting, and 2FA, this level remains lightweight and easier to implement — but may not be robust enough for high-risk or public-facing applications without further hardening.

While it offers a clean foundation for RBAC (Role-Based Access Control) and session lifecycle management, the system relies primarily on the correctness of token validation and cookie handling. All sensitive operations are guarded by middleware that validates the token and checks for user roles using a roles guard.

Use Cases Where This Level Is a Good Fit

  • Internal tools, dashboards, or admin panels for trusted users
  • MVPs or prototypes requiring basic role-based access
  • Small to medium-scale applications with low security risk
  • Projects where authentication is only one of many concerns, and simplicity is a priority

Use with Caution If:

  • Your app is publicly exposed, especially with open registration
  • You handle personally identifiable or regulated data
  • You require multi-factor authentication, login anomaly detection, or geo/device-level access control
  • You expect frequent logins from different devices or locations, which increases the risk of token theft or replay

🧠 TL;DR: This level is suitable for lightweight projects or internal tools, assuming HTTPS, secure cookie flags, strong password hashing, and proper Redis cache management are used. For production-grade, publicly exposed systems, consider integrating country/device validation, 2FA, and email confirmation to mitigate token abuse and impersonation risks.


Testing

To ensure the application is working correctly, comprehensive testing has been implemented to cover all aspects of the JWT authentication flow. The application utilizes Supertest for E2E testing, which allows making HTTP requests directly from test code and verifying expected responses. Here's a snapshot of the test results:

Test results

As you can see, all tests passed successfully. This gives confidence in the correctness of the JWT authentication implementation and ensures it works as expected in different scenarios. You can also run this test cases using npm run test:e2e command.

Installation

GitHub

$ git clone https://github.com/Pier228/level-0-basic-roles-auth.git
$ cd level-0-basic-roles-auth
$ npm install

Docker Image

The Docker image for this project is available on Docker Hub.

Docker Hub

Environment Variables

To run this application, you need to configure several environment variables.

  1. Create a .env file in the root directory of the project.
  2. Add required environment variables:
  • PORT: The port on which the server will run. This field is optional. By default will run on 3000 port.
  • DATABASE_URL: MongoDB connection URL used to connect to the database.
  • SALT_ROUNDS: Number of rounds for hashing passwords (bcrypt).
  • JWT_SECRET: Secret key for signing and verifying JWT tokens.
  • CORS_ALLOWED_ORIGIN: The URL of the domain from which it is allowed to send requests to the server (CORS settings).
  • COOKIE_SECRET: Secret key for signing and verifying cookies.
  • REDIS_CONNECT: Redis connection URL.

You can also refer to the .env.example file for a complete list of required environment variables.

Running the app

After setting up the .env file, you can start the application using the following commands:

# Generate prisma client
$ npx prisma generate

# Build the application
$ npm run build

# Start in development mode
$ npm run start

# Start in watch mode
$ npm run start:dev

# Start in production mode
$ npm run start:prod

License

This project is licensed under the MIT License - see the LICENSE file for details.