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.
Login flow
Section titled “Login flow”Step 1: Obtain tokens
Section titled “Step 1: Obtain tokens”Send a POST request to /auth/login with user credentials:
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" } }}Step 2: Use the access token
Section titled “Step 2: Use the access token”Include the access token in the Authorization header:
curl -X POST https://api.suit.pe/api/invoices \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \ -H "Content-Type: application/json" \ -d '{ ... }'Step 3: Refresh when expired
Section titled “Step 3: Refresh when expired”Access tokens expire after 15 minutes. Use the refresh token to obtain a new access token without requiring the user to log in again:
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.
Token details
Section titled “Token details”| Token | Lifetime | Purpose |
|---|---|---|
| Access Token | 15 minutes | Authenticate API requests |
| Refresh Token | 7 days | Obtain new access tokens |
User roles
Section titled “User roles”| Role | Permissions |
|---|---|
admin | Full access: emit documents, manage users, update settings |
facturador | Emit and query documents, manage clients and products |
viewer | Read-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)
Error handling
Section titled “Error handling”Invalid credentials
Section titled “Invalid credentials”{ "statusCode": 401, "error": "Unauthorized", "message": "Invalid email or password"}Expired access token
Section titled “Expired access token”{ "statusCode": 401, "error": "Unauthorized", "message": "Token expired"}When you receive this error, use the refresh token to obtain a new access token.
Expired refresh token
Section titled “Expired refresh token”{ "statusCode": 401, "error": "Unauthorized", "message": "Refresh token expired"}The user must log in again with their email and password.
Implementation example
Section titled “Implementation example”// Token management in a frontend applet 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();}