---
title: Authentication Reference
path: reference/authentication
status: published
---

All authentication endpoints. For the conceptual guide, see [Authentication](/docs/scaidrive/getting-started/authentication).

**Base path:** `/api/v1/auth/`

## GET /api/v1/auth/config

Return OAuth configuration. No authentication.

Used by clients to discover the ScaiKey endpoints without hardcoding them.

**Response:**

```json
{
  "authorize_url": "https://scaikey.scailabs.ai/oauth2/authorize",
  "token_url": "https://scaidrive.scailabs.ai/api/v1/auth/token",
  "client_id": "scaidrive-desktop",
  "desktop_callback_url": "https://scaidrive.scailabs.ai/api/v1/auth/callback"
}
```

## GET /api/v1/auth/callback

OAuth authorization-code relay for desktop clients. No authentication.

Purpose: desktop clients listen on `http://localhost:<port>`. ScaiKey redirects here with the code; ScaiDrive serves an HTML page that redirects to the localhost callback with the same query parameters.

**Query parameters:**

| Param | Notes |
|-------|-------|
| `code` | Authorization code |
| `state` | Opaque state, format: `{original_state}|port={port}` |
| `error` | On failure |
| `error_description` | On failure |

**Response:** HTML with JavaScript redirect to `http://localhost:{port}/callback?code=...&state=...`.

## POST /api/v1/auth/token

Exchange an authorization code for tokens, or refresh. No authentication (the code is the authentication).

**Request** (form-encoded):

```text
grant_type=authorization_code
code=<code>
redirect_uri=<original_redirect_uri>
code_verifier=<PKCE_verifier>
```

Or:

```text
grant_type=refresh_token
refresh_token=<refresh_token>
```

**Response:**

```json
{
  "access_token": "eyJhbGc...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "rt_...",
  "id_token": "eyJhbGc..."
}
```

Errors from ScaiKey (invalid code, expired refresh token, etc.) are surfaced in the standard error envelope with `error.code` as `AUTH_TOKEN_INVALID`.

## Token scopes

ScaiKey-issued tokens carry application scopes in the `scope` claim:

| Scope | Grants |
|-------|--------|
| `files:read` | Read files, folders, shares, metadata |
| `files:write` | Create, update, delete files and folders |
| `tenant:admin` | Manage users, groups, quotas, connectors within tenant |
| `partner:admin` | Manage tenants owned by the caller's partner |
| `admin:*` | Full platform admin |
| `*` | Superuser (platform operators) |

OIDC scopes (`openid`, `profile`, `email`, `offline_access`, `address`, `phone`) are recognized but don't affect ScaiDrive authorization.

## Token claims used by ScaiDrive

| Claim | Used for |
|-------|----------|
| `sub` | User ID |
| `tenant_id` | Tenant scope |
| `partner_id` | Partner scope |
| `email` | JIT provisioning, audit |
| `name` | JIT provisioning |
| `groups` | Permission resolution |
| `scope` / `scopes` / `permissions` / `roles` | Authorization |
| `iss` | Verified against ScaiKey URL |
| `exp` | Expiration check |

## Validation errors

| Code | HTTP | Meaning |
|------|------|---------|
| `AUTH_TOKEN_MISSING` | 401 | No `Authorization` header |
| `AUTH_TOKEN_INVALID` | 401 | Signature, issuer, or structural problem |
| `AUTH_TOKEN_EXPIRED` | 401 | `exp` in the past |
| `AUTH_INSUFFICIENT_SCOPE` | 403 | Token lacks required scope |

## Related

- [Authentication Guide](/docs/scaidrive/getting-started/authentication)
- [Permissions and ACLs](/docs/scaidrive/core-concepts/permissions-and-acls)
- [Error Codes](/docs/scaidrive/reference/error-codes)