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

# Authentication Reference

All authentication and session endpoints. For the conceptual overview, see [Authentication](../concepts/authentication).

**Base path:** `/v3/auth/`

Most endpoints in this section require no credentials themselves (they produce credentials); `/v3/auth/me` is the exception.

## POST /v3/auth/login

Initiate an OAuth login flow with ScaiKey. Returns the authorization URL the browser should redirect to.

**Request:**

```json
{"email": "you@example.com"}
```

| Field | Type | Required | Notes |
|-------|------|---------|-------|
| `email` | string | No | Optional login hint |

**Response (200):**

```json
{
  "authorization_url": "https://scaikey.scailabs.ai/oauth/authorize?...",
  "state": "opaque-state-string"
}
```

The `state` must be passed back to `/v3/auth/callback`. Store it (session, cookie) for CSRF verification.

## POST /v3/auth/callback

Exchange an OAuth authorization code for tokens.

**Request:**

```json
{"code": "authorization-code-from-oauth-redirect", "state": "opaque-state-string"}
```

**Response (200):**

```json
{
  "access_token": "eyJhbGc...",
  "refresh_token": "rtk_...",
  "expires_in": 3600,
  "user": {
    "id": "usr_01HXYZ",
    "email": "you@example.com",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "display_name": "Ada Lovelace",
    "tenant_id": "tnt_acme"
  }
}
```

**Errors:** 400 if `code` is invalid or expired, 401 if `state` mismatch.

## POST /v3/auth/refresh

Exchange a refresh token for a fresh access token.

**Request:**

```json
{"refresh_token": "rtk_..."}
```

**Response (200):**

```json
{
  "access_token": "eyJhbGc...",
  "refresh_token": "rtk_...",
  "expires_in": 3600
}
```

A new refresh token may be returned (rotation). If so, replace the old one.

**Errors:** 401 if refresh token is invalid, expired, or revoked.

## POST /v3/auth/logout

Logout is stateless — the server has no session to destroy. The client is expected to discard its tokens.

**Response (200):**

```json
{"status": "ok"}
```

## GET /v3/auth/me

Return the current user's profile and effective permissions. Requires a valid JWT.

**Response (200):**

```json
{
  "data": {
    "id": "usr_01HXYZ",
    "email": "you@example.com",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "display_name": "Ada Lovelace",
    "name": "Ada Lovelace",
    "status": "active",
    "tenant_id": "tnt_acme",
    "permissions": ["mail.send", "templates.read", "stats.read"],
    "role": "developer"
  }
}
```

`permissions` is the union of permissions granted by every role the user holds (direct role assignments + group-mapped roles + nested group inheritance). Use this to render UI affordances conditionally.

**Errors:** 401 if no JWT or JWT invalid.

## Authorization header format

Every authenticated request uses:

```
Authorization: Bearer <credential>
```

Where `<credential>` is either an API key (`sg_live_*` / `sg_test_*`) or a ScaiKey-issued JWT. ScaiSend determines which by the prefix.

## Related

- [Authentication (guide)](../concepts/authentication)
- [API Keys Reference](api-keys)
- [Roles and Permissions](../concepts/roles-and-permissions)
