Skip to content

JWT Authentication

JWT (JSON Web Token) authentication is designed for user-facing applications where users log in with email and password. It provides role-based access control and short-lived tokens for security.

Send a POST request to /auth/login with user credentials:

Terminal window
curl -X POST https://api.suit.pe/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "admin@yourcompany.com",
"password": "your_password",
"ruc": "20123456789"
}'

Response:

{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "cuid_xxx",
"name": "Admin",
"email": "admin@yourcompany.com",
"role": "admin",
"tenant": {
"id": "cuid_xxx",
"name": "Your Company",
"ruc": "20123456789"
}
}
}

Include the access token in the Authorization header:

Terminal window
curl -X POST https://api.suit.pe/api/invoices \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{ ... }'

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

Terminal window
curl -X POST https://api.suit.pe/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}'

Response:

{
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Store the new refresh token — the previous one is invalidated.

TokenLifetimePurpose
Access Token15 minutesAuthenticate API requests
Refresh Token7 daysObtain new access tokens
RolePermissions
adminFull access: emit documents, manage users, update settings
facturadorEmit and query documents, manage clients and products
viewerRead-only access: query documents, view reports

JWT tokens have access to:

  • All /api/* endpoints (same as API Key)
  • /auth/refresh (token renewal)
  • /admin/users (user management — admin role only)
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid email or password"
}
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Token expired"
}

When you receive this error, use the refresh token to obtain a new access token.

{
"statusCode": 401,
"error": "Unauthorized",
"message": "Refresh token expired"
}

The user must log in again with their email and password.

// Token management in a frontend app
let accessToken = null;
let refreshToken = null;
async function login(email, password, ruc) {
const response = await fetch('https://api.suit.pe/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password, ruc })
});
const data = await response.json();
accessToken = data.accessToken;
refreshToken = data.refreshToken;
return data.user;
}
async function apiCall(url, options = {}) {
options.headers = {
...options.headers,
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
};
let response = await fetch(url, options);
// If token expired, refresh and retry
if (response.status === 401) {
const refreshResponse = await fetch('https://api.suit.pe/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken })
});
const tokens = await refreshResponse.json();
accessToken = tokens.accessToken;
refreshToken = tokens.refreshToken;
// Retry original request with new token
options.headers['Authorization'] = `Bearer ${accessToken}`;
response = await fetch(url, options);
}
return response.json();
}