description:Manage users, built-in and custom roles, permissions, API keys, teams, sessions, and the audit log in SnapOtter.
---
# Users, Roles & Permissions
SnapOtter ships three built-in roles, 17 granular permissions, and support for custom roles with optional per-tool access control. This page covers the full authorization model, API key scoping, team management, and audit logging.
Admins can create users through the admin panel or the `POST /api/auth/users` endpoint. Each user has a username, role, team assignment, and an optional email address.
### Default admin
On first startup SnapOtter creates a default admin account. The credentials come from environment variables:
| Variable | Default | Description |
|---|---|---|
| `DEFAULT_USERNAME` | `admin` | Username for the initial admin account |
| `DEFAULT_PASSWORD` | `admin` | Password for the initial admin account |
The default admin is required to change their password on first login.
Set `AUTH_ENABLED=false` to disable authentication entirely. In this mode a synthetic anonymous user with the `admin` role is used for all requests. No login is required.
::: warning
Disabling authentication grants full admin access to anyone who can reach the instance. Only use this in trusted environments.
:::
## Built-in roles
SnapOtter includes three built-in roles. They cannot be modified or deleted.
### Admin
All 17 permissions. Full control over the instance.
| `tool` | Restrict by individual tool ID | Requires the `per_tool_permissions` enterprise feature |
When `tool` mode is set but the enterprise feature is not available, SnapOtter degrades gracefully and allows access to all tools.
```json
{
"name":"image-only",
"permissions":["tools:use","files:own"],
"toolPermissions":{
"mode":"category",
"allowed":["image"]
}
}
```
### Deleting a custom role
When a custom role is deleted, all users assigned to it are automatically reassigned to the `user` role.
## Teams
Teams group users for storage and retention management. A `Default` team is created on first startup.
| Field | Type | Description |
|---|---|---|
| `name` | string | Unique team name (1-50 characters) |
| `storageQuota` | number | Per-team storage limit in bytes (works without enterprise) |
| `retentionHours` | number | Auto-delete outputs after this many hours (requires `team_retention_overrides`, enterprise) |
| `legalHold` | boolean | Prevent automatic deletion of team members' files (requires `legal_hold`, enterprise) |
::: info
The `Default` team cannot be deleted. Teams that still have members cannot be deleted. Reassign members first.
:::
## API keys
Users can generate API keys for programmatic access. Each key uses the `si_` prefix and is shown only once at creation time.
### Scoped permissions
API keys can optionally carry a `permissions` array. When set, the effective permissions for a request are the **intersection** of the user's role permissions and the key's scoped permissions. This means an API key can never escalate beyond the user's own permissions.
```bash
curl -X POST http://localhost:13490/api/v1/api-keys \
-H "Authorization: Bearer si_..."\
-H "Content-Type: application/json"\
-d '{
"name": "CI pipeline key",
"permissions": ["tools:use", "files:own"],
"expiresAt": "2027-01-01T00:00:00Z"
}'
```
### Expiration
Keys accept an optional `expiresAt` timestamp. Expired keys are rejected at authentication time.
## Audit log
SnapOtter records security-relevant events in a structured audit log stored in the `audit_log` database table.
### Viewing the audit log
```
GET /api/v1/audit-log?page=1&limit=50&action=LOGIN_FAILED&from=2026-01-01T00:00:00Z&to=2026-12-31T23:59:59Z
```
Requires the `audit:read` permission. Supports pagination (`page`, `limit`) and filters (`action`, `ip`, `from`, `to`).
### Tool operation auditing
::: warning
`TOOL_EXECUTED` events are **not** logged by default. They are opt-in through either of two paths:
1. Set the `auditToolOperations` admin setting to `true`.
2. Hold an active license with the `audit_export` feature (available on both team and enterprise plans).
Without one of these, individual tool executions are not recorded in the audit log.
:::
### Exporting
```
GET /api/v1/enterprise/audit/export?format=csv&from=2026-01-01T00:00:00Z
```
Requires the `audit:read` permission and the `audit_export` enterprise feature (available on both team and enterprise plans). Supports CSV and JSON formats, filtered by `action`, `actorId`, `targetType`, `targetId`, `from`, and `to`.
### Tamper-resistant signing
When enabled, each audit log entry is signed with an HMAC derived from `DATA_ENCRYPTION_KEY`. This requires:
1. Setting `DATA_ENCRYPTION_KEY` in your environment.
2. Enabling the `tamperResistantAudit` admin setting.
3. An enterprise license with the `tamper_resistant_audit` feature.
### Retention
Set `AUDIT_RETENTION_DAYS` to automatically purge old entries. The default is `0`, which means entries are kept indefinitely.