Skip to main content

Overview

The OdontologyApp API uses cookie-based session authentication. After successfully logging in, the server sets an HTTP-only session cookie that is automatically included in subsequent requests.

Authentication Flow

  1. Client sends credentials to /api/auth/login
  2. Server validates credentials against the database
  3. Server creates a session and sets a cookie
  4. Client includes the cookie in all subsequent requests
  5. Server validates the session on each request via hooks.server.js

Login Endpoint

To authenticate, send a POST request to the login endpoint:
POST /api/auth/login

Request Body

username
string
required
The user’s username
password
string
required
The user’s password (will be compared with bcrypt hash)

Example Request

curl -X POST http://localhost:5173/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "username": "admin",
    "password": "secure-password"
  }'

Success Response (200)

{
  "success": true,
  "user": {
    "id": 1,
    "name": "Dr. Admin",
    "email": "[email protected]",
    "role": "admin",
    "initials": "DA",
    "theme": "light",
    "branch": "Todas las sucursales",
    "avatar_url": null
  }
}
success
boolean
Indicates successful authentication
user
object
User session data stored in the cookie
id
number
User’s unique identifier
name
string
User’s full name
email
string
User’s email address
role
string
User’s role (admin, doctor, receptionist, user)
initials
string
User’s initials for display
theme
string
User’s preferred theme (light/dark)
branch
string
Associated clinic branch name
avatar_url
string
URL to user’s avatar image

Error Responses

{
  "message": "Falta usuario o contraseña"
}
Returned when username or password is not provided.
{
  "message": "Usuario no encontrado"
}
Returned when the username doesn’t exist in the database.
{
  "message": "Contraseña incorrecta"
}
Returned when the password doesn’t match the stored hash.
{
  "message": "Error del servidor: [error details]"
}
Returned when a server-side error occurs during authentication.
Upon successful login, the server sets a session cookie with the following properties:

Session Data Structure

The session cookie contains JSON-encoded user information:
{
  "id": 1,
  "name": "Dr. Admin",
  "email": "[email protected]",
  "role": "admin",
  "initials": "DA",
  "theme": "light",
  "branch": "Todas las sucursales",
  "avatar_url": null
}

Authentication Middleware

The API uses a server hook (src/hooks.server.js) to validate sessions on every request:

How It Works

  1. Session Parsing: The hook reads the session cookie and parses the JSON data
  2. User Injection: Valid session data is injected into event.locals.user
  3. Route Protection: Non-authenticated users are redirected to /login (except for /api routes)
  4. Role-Based Access: Admin-only routes are protected based on the user’s role

Protected Routes

The following routes require admin role:
  • /admin/settings
  • /admin/treatments
  • /admin/reports
  • /users
  • /branches
  • /logs

API Route Behavior

API routes (/api/*) are not automatically redirected. Instead, each endpoint checks for authentication:
if (!locals.user) {
  return json({ message: "No autorizado" }, { status: 401 });
}

Making Authenticated Requests

After logging in, include the session cookie in all API requests:

Using cURL

curl -X GET http://localhost:5173/api/patients \
  -H "Cookie: session=your-session-cookie-value"

Using JavaScript (Browser)

fetch('/api/patients', {
  method: 'GET',
  credentials: 'include', // Automatically includes cookies
  headers: {
    'Content-Type': 'application/json'
  }
})

Using JavaScript (Node.js)

import fetch from 'node-fetch';

const response = await fetch('http://localhost:5173/api/patients', {
  method: 'GET',
  headers: {
    'Cookie': 'session=your-session-cookie-value'
  }
});

Permission System

Beyond authentication, most endpoints require specific permissions. The system uses three levels:

1. Admin Role

Users with role: "admin" automatically have access to all endpoints and permissions.

2. Permission-Based Access

Other users must have specific permission codes assigned. Common permissions include:
  • VIEW_PATIENTS - View patient list and details
  • CREATE_PATIENTS - Create new patients
  • EDIT_PATIENTS - Modify patient information
  • DELETE_PATIENTS - Delete patients
  • VIEW_APPOINTMENTS - View appointments
  • CREATE_APPOINTMENTS - Create appointments
  • MANAGE_INVENTORY - Manage inventory items
  • VIEW_INVENTORY - View inventory

3. Permission Resolution

The checkPermission() function resolves permissions in this order:
  1. Admin check: If user is admin, return true
  2. Database check: Query sp_check_single_permission(user_id, permission_code)
  3. Static fallback: Check ROLE_PERMISSIONS object for role-based defaults

Example Permission Check

import { checkPermission, forbiddenResponse } from '$lib/server/checkPermission';

export async function GET({ locals }) {
  if (!locals.user) {
    return json({ message: "No autorizado" }, { status: 401 });
  }

  if (!(await checkPermission(locals, 'VIEW_PATIENTS'))) {
    return forbiddenResponse(); // Returns 403
  }

  // Proceed with endpoint logic
}

Forbidden Response

When a user lacks the required permission, the API returns:
{
  "message": "No tienes permiso para realizar esta acción.",
  "code": "FORBIDDEN"
}
Status Code: 403 Forbidden

Logout Endpoint

To end a session, send a DELETE request to the login endpoint:
DELETE /api/auth/login

Example Request

curl -X DELETE http://localhost:5173/api/auth/login \
  -H "Cookie: session=your-session-cookie-value"

Response (200)

{
  "success": true
}
The session cookie is deleted with the same properties it was set with.

Session Expiration

Sessions automatically expire after 24 hours (86400 seconds). After expiration:
  1. The cookie is no longer valid
  2. API requests return 401 Unauthorized
  3. User must log in again to obtain a new session

Security Considerations

The current configuration uses secure: false to allow HTTP access on local networks. For production deployment, enable HTTPS and set secure: true.

Password Security

  • Passwords are hashed using bcrypt before storage
  • The API never returns password hashes in responses
  • Password comparison uses bcrypt.compare() for timing-attack resistance
  • HttpOnly: Prevents JavaScript access (XSS protection)
  • SameSite: lax: Prevents CSRF attacks
  • Path: /: Cookie available to all routes
  • Secure: Should be true in production with HTTPS

Login Logging

Successful logins are logged to the database:
await pool.query('CALL sp_create_log(?, ?, ?, ?, ?)', [
  user.id,
  'Login',
  'Auth',
  `El usuario ${user.username} ha iniciado sesión`,
  ip_address
]);
This creates an audit trail for security monitoring.

Troubleshooting

Possible causes:
  • Session cookie expired (>24 hours old)
  • Cookie not being sent with request
  • Session data corrupted
Solution: Log in again to obtain a fresh session.
Cause: Your user account lacks the required permission for this endpoint.Solution: Contact an administrator to grant the necessary permissions.
Cause: Some API clients don’t automatically handle cookies.Solution: Manually extract the Set-Cookie header from the login response and include it in subsequent requests.

Next Steps

Error Handling

Learn about error responses and HTTP status codes

Build docs developers (and LLMs) love