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

# SMS, JWT, and API key authentication

> Profy authentication explained: SMS plus JWT login for end users, API keys for programmatic access, and Redis-backed single-device sessions.

# Authentication

Profy uses a dual authentication system: **SMS + JWT** for end users and **API Keys** for programmatic access. All sessions are backed by Redis with single-device enforcement.

## Overview

```mermaid theme={null}
flowchart TB
    subgraph "User Authentication"
        SMS[SMS Code] --> JWT[JWT Token]
        JWT --> Session[Redis Session]
    end

    subgraph "API Authentication"
        Key["API Key (sk_*)"] --> OpenAPI["/openapi/* routes"]
    end

    subgraph "Middleware"
        Filter[Auth Filter]
    end

    Session --> Filter
    Key --> Filter
    Filter --> Routes[Protected Routes]
```

## SMS Login Flow

Users authenticate by verifying ownership of a phone number via SMS verification code.

```mermaid theme={null}
sequenceDiagram
    participant U as User
    participant W as Web (Next.js)
    participant C as Core (Hono)
    participant R as Redis
    participant S as SMS Provider

    U->>W: Enter phone number
    W->>C: POST /api/auth/sms/sendCode
    C->>R: Check sms:rate-limit:{phone}
    alt Rate limited
        C-->>W: 429 Too Many Requests
    else OK
        C->>R: Store sms:code:{phone} (5 min TTL)
        C->>S: Dispatch SMS (Aliyun / Volcengine)
        C->>R: Set sms:rate-limit:{phone} (60s TTL)
        C-->>W: Code sent
    end

    U->>W: Enter verification code
    W->>C: POST /api/auth/login {phone, code}
    C->>R: Verify sms:code:{phone}
    alt Code matches
        C->>C: Create or load user
        C->>C: Sign JWT (HS256, 7d expiry)
        C->>R: Store dual session keys
        C-->>W: {token, newUser}
    else Invalid code
        C-->>W: 401 Unauthorized
    end
```

### SMS Providers

| Provider   | Use Case             | Configuration                                              |
| ---------- | -------------------- | ---------------------------------------------------------- |
| Aliyun SMS | Primary provider     | `ALIYUN_SMS_ACCESS_KEY_ID`, `ALIYUN_SMS_ACCESS_KEY_SECRET` |
| Volcengine | Alternative provider | `VOLCENGINE_SMS_*` env vars                                |

An optional Aliyun CAPTCHA challenge can be required before sending SMS to prevent abuse.

## JWT Token System

Tokens are signed using the **jose** library with HS256 algorithm.

### Token Structure

```typescript theme={null}
interface JWTPayload {
  userId: string;
  phone: string;
  iat: number;
  exp: number;   // 7 days from issuance
}
```

### Redis Session Keys

Each login creates two Redis entries for bidirectional lookup:

| Key Pattern                | Value             | TTL                  | Purpose                             |
| -------------------------- | ----------------- | -------------------- | ----------------------------------- |
| `auth:token:{token}`       | User JSON payload | 24h (auto-refreshed) | Token → user lookup                 |
| `auth:user-token:{userId}` | Token string      | 24h                  | User → token lookup (single-device) |

### Single-Device Enforcement

When a user logs in from a new device, the previous session is invalidated:

1. Look up existing token via `auth:user-token:{userId}`
2. Delete old `auth:token:{oldToken}` entry
3. Store new token in both keys

This ensures only one active session per user at any time.

## Auth Middleware

The auth filter runs on every request and applies route-level access control.

### Whitelisted Routes (No Auth Required)

| Route                    | Reason                      |
| ------------------------ | --------------------------- |
| `/api/auth/login`        | Login endpoint              |
| `/api/auth/sms/sendCode` | SMS dispatch                |
| `/api/health`            | Health check                |
| `/api/market/*`          | Public marketplace browsing |
| `/api/payment/notify/*`  | Payment provider callbacks  |

### Middleware Flow

```mermaid theme={null}
flowchart TD
    Req[Incoming Request] --> WL{Whitelisted?}
    WL -->|Yes| Pass[Pass through]
    WL -->|No| Extract[Extract token]
    Extract --> Redis{Token in Redis?}
    Redis -->|Yes| Refresh[Refresh TTL 24h]
    Redis -->|No| Verify{JWT verify}
    Verify -->|Valid| Cache[Cache in Redis]
    Verify -->|Invalid| Reject[401 Unauthorized]
    Refresh --> Inject[Inject user context]
    Cache --> Inject
    Inject --> Handler[Route handler]
```

The middleware extracts tokens from either:

* `Authorization: Bearer <token>` header
* `Cookie: token=<token>` cookie

## API Key System

API Keys provide programmatic access to the `/openapi/*` endpoints, used primarily by the Profy agent engine for credit consumption.

### Key Format

All API keys use the `sk_` prefix followed by a cryptographically random string.

### API Key Endpoints

| Method | Endpoint                  | Description            |
| ------ | ------------------------- | ---------------------- |
| `POST` | `/api/user/apiKey/create` | Generate a new API key |
| `POST` | `/api/user/apiKey/list`   | List user's API keys   |
| `POST` | `/api/user/apiKey/delete` | Revoke an API key      |

### Key Storage

API keys are stored in Redis under `openapi:key:{key}` with the associated user payload. Validation is a simple Redis lookup — no JWT verification needed.

### OpenAPI Endpoints (API Key Auth)

| Method | Endpoint                   | Description                     |
| ------ | -------------------------- | ------------------------------- |
| `POST` | `/openapi/credit/consume`  | Consume credits (used by Profy) |
| `POST` | `/openapi/credit/preCheck` | Pre-validate consumption        |
| `GET`  | `/openapi/credit/balance`  | Query credit balance            |

## Security Considerations

| Concern            | Mitigation                                                   |
| ------------------ | ------------------------------------------------------------ |
| SMS abuse          | Rate limiting (60s cooldown per phone), optional CAPTCHA     |
| Token leakage      | 24h Redis TTL, single-device enforcement                     |
| Replay attacks     | JWT expiry (7d), Redis-backed session invalidation           |
| API Key exposure   | Revocable keys, `sk_` prefix for easy scanning               |
| Internal endpoints | `/internal/*` routes restricted to private network via Nginx |

## Token Refresh

The platform provides a token refresh endpoint at `GET /api/token/refresh` that issues a new JWT before the current one expires, maintaining seamless session continuity.

## Related Pages

<CardGroup cols={2}>
  <Card title="Architecture" icon="sitemap" href="/en/documentation/architecture/overview">
    See how auth fits into the request lifecycle
  </Card>

  <Card title="Agent Platform" icon="robot" href="/en/documentation/agent">
    API Keys power the Profy credit consumption bridge
  </Card>
</CardGroup>
