> ## Documentation Index
> Fetch the complete documentation index at: https://woku.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Login flow, persistent sessions, idle timeout, and refresh tokens

## Login

Users log in at `admin.woku.app/login` with their email (or
username) + password. The password is compared against a bcrypt
hash; the plaintext password is never stored or transmitted beyond
the form itself.

A successful login generates:

* An **access token** (signed JWT) that the client attaches as
  `Authorization: Bearer <token>` on every request.
* An opaque **refresh token** (32 random bytes, single-use) valid
  for 30 days.
* A server-side persisted **Session** that binds the token to a
  user and allows it to be revoked or expired.

## Idle timeout

Every authenticated request refreshes the session's `lastActivity`
field (debounced every 60 seconds so the database is not
overloaded). If the session stays inactive for longer than the
configured time, it closes automatically: the next request receives
`401 Unauthorized` and the user must log in again.

* **Default**: 30 minutes of inactivity leads to closure.
* **Per-session override**: optional, via the session's
  `idleTimeoutMin` field.
* **Global override**: the `SESSION_IDLE_TIMEOUT_MIN` environment
  variable.

Idle closure also persists `isClosed: true` on the session, so an
attacker with the stolen token cannot use it either.

## Refresh tokens (single-use rotation)

When the client wants to extend the session without asking the user
to enter their credentials again, it sends its current refresh token
to the authentication service. The server:

1. Verifies that the refresh token exists, is not closed, and is not
   expired.
2. Generates **a new pair** (access + refresh) and **invalidates the
   old one** atomically in the same `Session` row.
3. Returns the new pair.

If the refresh token is unknown, closed, or already expired, the
response is `401 Unauthorized` and the user must log in again.

## Logout

On logout, the session is marked as closed (`isClosed: true`). From
that point on, no request with that access token or its refresh token
works.

## Guarantees

* **Tokens never appear in the URL**: they only travel in the header
  or body, and TLS protects them in transit (see [Headers and CSP](/docs/en/seguridad/headers-y-csp)
  for HSTS).
* **Immediate revocation**: the admin can revoke any session from the
  backoffice endpoint; the next request from the revoked token fails.
* **Compatibility**: the access-token-only flow still works for
  clients that do not implement refresh (rotation is opt-in).
