Skip to content

Admin Settings

OxiCloud exposes an admin API for runtime configuration, dashboard stats, and user administration. All routes live under /api/admin and require an authenticated admin JWT.

Settings Endpoints

MethodPathDescription
GET/api/admin/settings/oidcRead current OIDC settings
PUT/api/admin/settings/oidcSave OIDC settings
POST/api/admin/settings/oidc/testTest provider connectivity
GET/api/admin/settings/generalRead general server settings

The OIDC runtime UI complements the base configuration described in OIDC / SSO and the provider samples in OIDC Config Examples.

Dashboard Endpoint

MethodPathDescription
GET/api/admin/dashboardRead server statistics and feature state

Typical dashboard fields include:

  • server version
  • whether auth and OIDC are enabled
  • whether quotas are enabled
  • total, active, and admin user counts
  • quota usage totals and percentage

User Management Endpoints

MethodPathDescription
GET/api/admin/usersList users
GET/api/admin/users/{id}Get one user
DELETE/api/admin/users/{id}Delete a user
PUT/api/admin/users/{id}/roleChange role
PUT/api/admin/users/{id}/activeActivate or deactivate a user
PUT/api/admin/users/{id}/quotaUpdate a storage quota

Built-in safety guards

  • Admins cannot delete their own account
  • Admins cannot change their own role
  • Admins cannot deactivate themselves

OIDC Settings Priority

When the same setting exists in multiple places, OxiCloud resolves it in this order:

  1. Environment variables such as OXICLOUD_OIDC_*
  2. Values stored in the admin settings table
  3. Built-in defaults

If a value is overridden by environment variables, the admin API can expose that in the response so operators know why a saved value is not taking effect.

Test Connection Example

json
{
  "issuer_url": "https://keycloak.example.com/realms/main"
}

Successful responses include discovered endpoints such as the authorization endpoint, token endpoint, and userinfo endpoint.

Storage & Migration

The admin storage tab operates on the named storage entries declared in .env (see Storage Entries). The set of entries is immutable per-deploy — adding or removing one requires a server restart. Runtime behaviour is driven by a single DB row that names which entry is currently active.

Endpoints

MethodPathDescription
GET/api/admin/settings/storageList entries + active pointer + read-only flag + basic stats
POST/api/admin/settings/storage/testReachability + round-trip test against the currently-effective backend
POST/api/admin/storage/migration/startTrigger a cross-entry migration. Body: {"target_name": "<entry>"}
POST/api/admin/storage/migration/pauseCooperative cancel — handler yields at the next batch boundary
POST/api/admin/storage/migration/resumeResume a paused run (target read from params.target_name, no body needed)
GET/api/admin/storage/migrationPoll the current run's progress

Runs are recoverable — status, cursor, and per-blob failure findings all live in jobs.recoverable_runs / jobs.run_findings. The same run history is browsable via GET /api/admin/jobs/backend_migration/runs.

Cutover flow (moving the active pointer)

  1. Declare the target entry in .env and restart so OXICLOUD_STORAGE_ENTRIES picks it up.
  2. Admin storage tab → pick the target from the dropdown → Start migration. The server engages global read-only mode (writes refused across the whole app; reads keep working), then copies blobs from source → target.
  3. On Completed, the server writes admin_settings.storage.active_backend_name = <target>. Read-only stays ON — writes on the OLD backend would strand data now that the pointer says the new one is active.
  4. Operator restarts the server. Boot picks the new active entry, and the boot-clear rule drops the read-only flag (no in-flight run + booted-entry matches DB pointer). Server writable again, on the new backend.

Repair flag — pointer / entry drift

If an entry is renamed or removed from .env while the DB pointer still names the old one, boot aborts with a clear error pointing at:

oxicloud storage select <name>

This one-shot repair command re-runs the same env-parse the server does at boot, verifies <name> is declared in OXICLOUD_STORAGE_ENTRIES, updates admin_settings.storage.active_backend_name in the DB, and exits. Operator then restarts normally. See Environment Variables — Storage Entries for the model, and oxicloud --help for the full flag list.

Auditing entries other than the active one

backend_consistency (a recoverable job on the Jobs tab) accepts ?storage=<name> to audit any declared entry — not just the live one. Use this to verify a migration target before cutover, or to audit an old backend after cutover but before decommissioning:

POST /api/admin/jobs/backend_consistency/trigger?storage=<name>

Add ?deep=true to also read every blob back and re-hash it, which catches silent bit-rot. That is a full read of the entry and can take hours.

blobs_consistency does not accept ?storage=<name>: it only reads the database, so there is no entry for it to scope.

Unknown names 400 at the HTTP layer.

Data Storage

Runtime settings are stored in auth.admin_settings.

sql
CREATE TABLE IF NOT EXISTS auth.admin_settings (
    key        TEXT PRIMARY KEY,
    value      TEXT NOT NULL,
    category   TEXT NOT NULL,
    is_secret  BOOLEAN DEFAULT FALSE,
    updated_by VARCHAR(36),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

Released under the MIT License.