Skip to main content
The Banca Management Backend uses JWT (JSON Web Tokens) for secure authentication with a dual-token system.

Token System

The authentication system uses two types of tokens:

Access Token

Short-lived token for API requests. Default expiration: 15 minutes.

Refresh Token

Long-lived token for obtaining new access tokens. Default expiration: 7 days.

Authentication Flow

1

Login

User provides credentials (username/email and password) to /api/v1/auth/login.
curl -X POST http://localhost:4000/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "identifier": "your-username",
    "password": "your-password"
  }'
Response:
{
  "success": true,
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIs...",
    "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
  }
}
2

Authenticated Requests

Include the access token in the Authorization header:
curl http://localhost:4000/api/v1/tickets \
  -H "Authorization: Bearer {accessToken}"
3

Token Refresh

When the access token expires, use the refresh token to get a new one:
curl -X POST http://localhost:4000/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refreshToken": "eyJhbGciOiJIUzI1NiIs..."}'
4

Logout

Revoke the refresh token to prevent further token refreshes:
curl -X POST http://localhost:4000/api/v1/auth/logout \
  -H "Content-Type: application/json" \
  -d '{"refreshToken": "eyJhbGciOiJIUzI1NiIs..."}'

Middleware Protection

The protect middleware (from src/middlewares/auth.middleware.ts) validates JWT tokens on protected routes:
export const protect = async (
  req: AuthenticatedRequest,
  _res: Response,
  next: NextFunction
) => {
  const header = req.headers.authorization;
  if (!header || !header.startsWith("Bearer ")) {
    throw new AppError("Unauthorized", 401);
  }

  const token = header.split(" ")[1];
  
  // Verify JWT signature and expiration
  let decoded: any;
  try {
    decoded = jwt.verify(token, config.jwtAccessSecret);
  } catch {
    throw new AppError("Invalid token", 401);
  }

  // Attach user to request
  req.user = { 
    id: decoded.sub, 
    role: decoded.role,
    ventanaId: decoded.ventanaId,
    bancaId: decoded.bancaId 
  };
  next();
};

Token Payload

Access tokens contain the following claims:
sub
string
required
User ID (subject)
role
enum
required
User role: ADMIN, VENTANA, or VENDEDOR
ventanaId
string
Ventana ID (for VENTANA and VENDEDOR roles)
bancaId
string
Banca ID (for all users)
iat
number
required
Issued at timestamp
exp
number
required
Expiration timestamp

Environment Configuration

Configure JWT secrets and expiration in .env:
# JWT Configuration
JWT_ACCESS_SECRET=your-access-secret-key
JWT_REFRESH_SECRET=your-refresh-secret-key
JWT_ACCESS_EXPIRES_IN=15m
JWT_REFRESH_EXPIRES_IN=7d

# Development Only: Bypass authentication
DISABLE_AUTH=false
Never use DISABLE_AUTH=true in production. This is only for development and simulates an ADMIN user for all requests.

Security Features

Graceful Degradation

The auth middleware separates JWT verification from infrastructure operations (Redis/Database):
  • JWT errors → 401 Unauthorized
  • Infrastructure errors → Retries with connection retry logic, then 500 if exhausted
This prevents temporary database issues from logging out all users.

Refresh Token Revocation

Refresh tokens are stored in the database and can be revoked:
  • On logout, the refresh token is marked as revoked
  • Revoked tokens cannot be used to obtain new access tokens
  • Each user can have multiple active refresh tokens (different devices)

Rate Limiting

Authentication endpoints are protected with rate limiting:
import rateLimit from 'express-rate-limit';

const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 requests per window
  message: 'Too many login attempts, please try again later'
});

router.post('/login', authLimiter, AuthController.login);

Common Error Codes

CodeMessageCause
401UnauthorizedMissing or invalid token
401Invalid tokenToken signature verification failed
401Token expiredAccess token has expired (use refresh)
403ForbiddenValid token but insufficient permissions
429Too Many RequestsRate limit exceeded

Best Practices

  • Never store tokens in localStorage (vulnerable to XSS)
  • Use httpOnly cookies for web apps
  • Use secure storage (Keychain/Keystore) for mobile apps
  • Implement automatic token refresh before expiration
  • Show re-authentication prompt if refresh fails
  • Clear tokens and redirect to login on 401 errors
  • Consider implementing refresh token rotation for enhanced security
  • Issue a new refresh token with each refresh request
  • Revoke the old refresh token after successful rotation

Roles & Permissions

Learn about the RBAC system

API: Login

Login endpoint reference

Build docs developers (and LLMs) love