Skip to content

Authentication

Sairo uses JWT-based authentication with secure cookie storage. Tokens are issued on login and validated on every API request.

Sairo supports two authentication modes, controlled by the AUTH_MODE environment variable:

ModeAUTH_MODELogin FieldsBest For
Local (default)localUsername + PasswordTeams with multiple users, Sairo-managed RBAC, 2FA
S3 Keyss3S3 Access Key + Secret KeyDelegating access control to your S3 provider’s IAM; headless / quick start

In S3 mode, users authenticate by entering their S3 access key and secret key. Sairo validates the credentials by calling list_buckets() against the configured S3 endpoint. No Sairo user accounts are needed — access is governed entirely by the S3 provider.

Since v3.4.1, every S3 operation in this mode is performed with the logged-in user’s own keys (kept encrypted in the session token), so the provider’s IAM scopes exactly what each user can see and do:

  • A user sees and can manage only the buckets their keys can access — not every bucket the server can reach, and not buckets on other endpoints.
  • Access is enforced per request: object listings come from Sairo’s local index, so each bucket request is independently checked against the provider with the user’s keys before any indexed data is returned.
  • In multi-endpoint setups, a session is bound to the endpoint it logged into.
environment:
AUTH_MODE: "s3" # Authenticate with S3 credentials instead of username/password

Both modes can be used simultaneously — the login page shows a toggle to switch between “S3 Keys” and “Password”. In s3 mode, the S3 tab is shown first. In local mode, the password tab is shown first (S3 tab appears only if explicitly enabled).

When a user logs in, the backend issues a signed JWT and sets it as an httpOnly cookie with SameSite=Strict. This prevents JavaScript from reading the token and blocks the cookie on all cross-site navigations.

Every subsequent request includes the cookie automatically. The backend validates the token signature, checks expiration, and extracts the user identity.

Sessions last 24 hours by default. You can change this with the SESSION_HOURS environment variable:

environment:
SESSION_HOURS: "48" # 48-hour sessions

Five minutes before a session expires, a toast notification appears in the UI with an Extend button. Clicking it issues a fresh token without requiring re-login.

If the session expires without extension, the user is redirected to the login page.

The SECURE_COOKIE environment variable controls whether the cookie is sent only over HTTPS:

DeploymentSECURE_COOKIE
Behind HTTPS reverse proxytrue (recommended)
Plain HTTP (local/dev)false
environment:
SECURE_COOKIE: "true"

If SECURE_COOKIE=true but you access Sairo over plain HTTP, the browser will not send the cookie and login will appear broken. Set it to false for HTTP deployments.

Login attempts are rate-limited with two layers:

  • 10 requests per minute via the global rate limiter (applied to the login endpoint)
  • 10 requests per 5 minutes per IP address via a hardcoded per-IP window

Both limits apply simultaneously. After exceeding either limit, the API returns 429 Too Many Requests until the window resets. These limits are not independently configurable.

All passwords are hashed with bcrypt before storage. Plaintext passwords are never written to disk or logs. Passwords must be at least 8 characters long.

On first startup, Sairo auto-generates:

  • A JWT_SECRET used to sign tokens (generated in-memory if not set via env var)
  • An admin account with the username and password from ADMIN_USER and ADMIN_PASS environment variables

If JWT_SECRET is not explicitly set, a random secret is generated in memory on each startup. This means all active sessions are invalidated on restart. For production and multi-instance deployments, always set JWT_SECRET explicitly.

environment:
ADMIN_USER: "admin"
ADMIN_PASS: "your-secure-password"
JWT_SECRET: "a-long-random-string"