TaskForge API uses JSON Web Tokens (JWT) for authentication. Every protected endpoint requires a valid access token in the Authorization header. Refresh tokens allow you to obtain new access tokens without re-entering credentials.
Never expose your access token or refresh token in client-side code, logs, or version control. Treat them with the same care as passwords.
Token overview
| Token | Lifetime | Purpose |
|---|
| Access token | 1 hour (configurable via JWT_ACCESS_TOKEN_EXPIRES) | Authenticate requests to protected endpoints |
| Refresh token | 30 days (configurable via JWT_REFRESH_TOKEN_EXPIRES) | Obtain new access tokens; stored and tracked in the database |
The typical authentication flow is:
- Register or log in to receive an access token and a refresh token.
- Include the access token in the
Authorization: Bearer <token> header on every request.
- When the access token expires, call
POST /api/auth/refresh with the refresh token to get a new access token.
- Call
POST /api/auth/logout to revoke the refresh token and end the session.
Registration
Creates a new user account with the user role. Rate limited to 5 requests per hour.
Request body
Unique username. Must be 3–80 characters and contain only letters, numbers, underscores (_), and hyphens (-).
Unique email address. Must be a valid email format, 3–120 characters, with no consecutive dots.
Account password. Must be 8–128 characters and contain at least one uppercase letter, one lowercase letter, and one number.
User’s first name. Optional.
User’s last name. Optional.
Example
curl -X POST http://localhost:5000/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"username": "johndoe",
"email": "[email protected]",
"password": "Password123!",
"first_name": "John",
"last_name": "Doe"
}'
{
"success": true,
"message": "Usuario registrado con exito",
"data": {
"id": 1,
"username": "johndoe",
"email": "[email protected]",
"first_name": "John",
"last_name": "Doe",
"full_name": "John Doe",
"is_active": true,
"role": {
"id": 2,
"name": "user",
"description": null
},
"created_at": "2026-03-17T12:00:00",
"updated_at": "2026-03-17T12:00:00"
}
}
Password rules
Passwords are validated by app/utils/validators.py and must meet all of the following:
- Minimum 8 characters, maximum 128 characters
- At least one uppercase letter (
A–Z)
- At least one lowercase letter (
a–z)
- At least one digit (
0–9)
Login
Authenticates a user and returns a JWT access token, a refresh token, and the user object. Rate limited to 10 requests per hour.
Request body
The registered email address.
Example
curl -X POST http://localhost:5000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "Password123!"}'
{
"success": true,
"message": "Inicio de sesion exitoso",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"username": "johndoe",
"email": "[email protected]",
"first_name": "John",
"last_name": "Doe",
"full_name": "John Doe",
"is_active": true,
"role": {
"id": 2,
"name": "user",
"description": null
},
"created_at": "2026-03-17T12:00:00",
"updated_at": "2026-03-17T12:00:00"
}
}
}
The refresh token is stored in the database so it can be individually revoked on logout or password change.
Using access tokens
Include the access token in the Authorization header of every request to a protected endpoint:
curl -X GET http://localhost:5000/api/tasks \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
The server validates the token on each request using the current_user_required middleware decorator (app/middleware/auth.py). If the token is missing, expired, or invalid, the server responds with 401 Unauthorized.
Refreshing tokens
Exchanges a valid refresh token for a new access token. Pass the refresh token in the Authorization header.
curl -X POST http://localhost:5000/api/auth/refresh \
-H "Authorization: Bearer <refresh_token>"
{
"success": true,
"message": "Token refrescado con exito",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
If the refresh token is expired or has been revoked, the server returns 401 Unauthorized.
Logout
Requires a valid access token in the Authorization header. Revokes the given refresh token in the database, invalidating that session. The access token itself continues to be accepted until it naturally expires.
Request body
The refresh token to revoke.
curl -X POST http://localhost:5000/api/auth/logout \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"refresh_token": "<refresh_token>"}'
{
"success": true,
"message": "Sesion cerrada con exito"
}
Get current user
Returns the profile of the currently authenticated user.
curl -X GET http://localhost:5000/api/auth/me \
-H "Authorization: Bearer <access_token>"
{
"success": true,
"data": {
"id": 1,
"username": "johndoe",
"email": "[email protected]",
"first_name": "John",
"last_name": "Doe",
"full_name": "John Doe",
"is_active": true,
"role": {
"id": 2,
"name": "user",
"description": null
},
"created_at": "2026-03-17T12:00:00",
"updated_at": "2026-03-17T12:00:00"
}
}
Change password
POST /api/auth/change-password
Updates the authenticated user’s password. Rate limited to 3 requests per hour. On success, all existing refresh tokens for the user are automatically revoked, requiring re-login on all devices.
Request body
The user’s current password.
The new password. Must satisfy the same rules as registration: 8–128 characters, at least one uppercase letter, one lowercase letter, and one digit.
curl -X POST http://localhost:5000/api/auth/change-password \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"old_password": "Password123!", "new_password": "NewPassword456!"}'
{
"success": true,
"message": "Contrasena cambiada con exito"
}
Role-based access control
Every user is assigned a role at registration. Two roles exist:
| Role | Value | Description |
|---|
| Admin | admin | Full access to all users’ tasks and user management endpoints |
| User | user | Access limited to their own tasks and profile |
New accounts always receive the user role. Admin accounts must be created directly in the database or by an existing admin.
The RBAC decorators in app/middleware/rbac.py enforce these rules:
@admin_required — endpoint accessible only to users with role admin. Returns 403 Forbidden for any other role.
@role_required(RoleType.ADMIN, RoleType.USER) — endpoint accessible to any of the specified roles.
@resource_owner_or_admin — endpoint accessible to the resource owner or any admin.
Endpoints that require the admin role include user management routes (GET /api/users, DELETE /api/users/<id>, etc.). Standard task endpoints use @resource_owner_or_admin, so admins can see and manage all tasks while regular users can only manage their own.
Rate limits on auth endpoints
| Endpoint | Limit |
|---|
POST /api/auth/register | 5 per hour |
POST /api/auth/login | 10 per hour |
POST /api/auth/change-password | 3 per hour |
All other endpoints inherit the global default: 200 requests per day / 50 requests per hour. Rate limiting is controlled by Flask-Limiter and can be disabled or reconfigured via the RATELIMIT_ENABLED and RATELIMIT_DEFAULT environment variables.
Token expiration
Token lifetimes are set in the .env file:
JWT_ACCESS_TOKEN_EXPIRES=3600 # seconds — default 1 hour
JWT_REFRESH_TOKEN_EXPIRES=2592000 # seconds — default 30 days
The application reads these at startup and passes them to Flask-JWT-Extended. Changing these values requires a server restart.