> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zeus.agentspro.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Zeus Inter-Service JWT Authentication

# JWT Service Authentication

## Overview

Zeus uses a **dual-layer authentication architecture**:

* **User Authentication**: Better Auth (Session-based) — See [Web Authentication](/en/platforms/web/auth)
* **Service Authentication**: JWT + JWKS (Stateless)

## Authentication Architecture

```mermaid theme={null}
sequenceDiagram
    participant User as User (Browser)
    participant Web as Web - Next.js
    participant Backend as ai-backend - Python

    User->>Web: 1. Email/password or OAuth login
    Web->>Web: Better Auth verifies identity, creates Session
    User->>Web: 2. Initiates AI request
    Web->>Web: Call /api/auth/token to get JWT
    Web->>Backend: 3. HTTP + Authorization: Bearer JWT
    Backend->>Backend: Verify Token via JWKS, extract user info
    Backend-->>User: Response
```

## Why Dual-Layer Authentication

**Problem with user auth only**:

```
User → Web → ai-backend
              ↑
              Anyone can call directly!
```

**User auth + Service auth**:

```
User → Web (User Auth) → ai-backend (Service Auth)
                         ↑
                         Only accepts requests from Web
```

## How JWT Works

### Token Acquisition Flow

1. User logs in → Better Auth creates Session
2. Call `/api/auth/token` → Better Auth issues JWT
3. Web API uses JWT → calls ai-backend
4. ai-backend verifies JWT → validates signature via JWKS

### Token Structure

```
eyJhbGciOiJFZERTQSJ9.eyJ1c2VySWQiOiJ1c2VyX2FiYzEyMyJ9.signature
│                    │                                    │
│                    │                                    └─ Signature (EdDSA)
│                    └─ Payload (User Data)
└─ Header (Algorithm Info)
```

### JWKS Verification Flow

1. **Extract Token**: Extract from `Authorization: Bearer <token>` header
2. **Fetch JWKS**: Get public key from `/api/auth/jwks` (with caching)
3. **Find Key**: Look up corresponding public key using `kid` from Token Header
4. **Verify Signature**: Use public key to verify Token has not been tampered with
5. **Check Expiration**: Verify Token has not expired
6. **Return User Info**: Extract `userId`, `email`, `name`

## Protected APIs

### Require JWT Authentication

| Module  | Endpoint            | Description        |
| ------- | ------------------- | ------------------ |
| Chat    | `/api/agent/invoke` | Agent mode         |
| Sandbox | `/api/sandbox/*`    | Sandbox operations |
| MCP     | `/api/mcp/*`        | MCP management     |
| Skills  | `/api/skills/*`     | Skills management  |

### Do Not Require JWT Authentication

| Endpoint  | Description  |
| --------- | ------------ |
| `/`       | Root path    |
| `/health` | Health check |

## Security Best Practices

### 1. Asymmetric Encryption

Uses **EdDSA (Ed25519)**:

* Backend does not need shared secrets
* Private key exists only on the Web side
* Supports key rotation

### 2. Key Rotation

* Rotation period: 30 days
* Old keys retained: 30 days

### 3. Token Validity (Dual Token System)

| Token Type            | Validity | Purpose                           |
| --------------------- | -------- | --------------------------------- |
| accessToken (JWT)     | 1 hour   | Bearer token for each API call    |
| refreshToken (opaque) | 30 days  | Silently obtain a new accessToken |

Desktop/iOS/Android native clients use a dual-token mechanism:

* accessToken is automatically refreshed 5 minutes before expiry
* If refresh fails (refreshToken expired), the user is automatically logged out
* refreshToken is stored as SHA-256 hash in the database

### Token Refresh Flow

```mermaid theme={null}
sequenceDiagram
    participant Client as Desktop / iOS / Android
    participant Web as Next.js (Web API)
    participant DB as PostgreSQL

    Client->>Client: Check accessToken exp < 5min
    Client->>Web: POST /api/auth/refresh {refreshToken}
    Web->>Web: SHA-256(refreshToken) → tokenHash
    Web->>DB: Find tokenHash + verify not expired
    DB-->>Web: User info
    Web->>Web: Sign new JWT with JWKS private key
    Web-->>Client: {accessToken, expiresIn: 3600}
    Client->>Client: Update local storage, continue API calls
```

### Refresh Token Security

* **Hash storage**: Database stores only SHA-256 hashes; even if leaked, raw tokens cannot be used
* **Cascade deletion**: All refresh tokens are automatically cleaned up when a user is deleted
* **Bulk revocation**: All refresh tokens can be revoked by user ID

### 4. JWKS Caching

* Cache duration: 1 hour
* Auto-refreshes during key rotation

### 5. Transport Security

* Production must use HTTPS
* Token is only transmitted in HTTP Header
* Never pass Token in URLs
