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

# Authentication

> Authentication endpoints, JWT tokens, and subscription management

## Overview

Conformly.ai uses **Supabase JWT tokens** for authentication. All API requests (except payment endpoints) require a valid token in the Authorization header.

## Base URL

**Production:**

```
https://beta-api.conformly.ai/api/v1
```

**Local Development:**

```
http://localhost:8000/api/v1
```

## Authentication Header

```
Authorization: Bearer <supabase_jwt_token>
```

## Endpoints

### Get Current User Profile

Returns the authenticated user's profile including subscription status.

```bash theme={null}
curl -X GET "http://localhost:8000/api/v1/auth/me" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response:**

```json theme={null}
{
  "id": "f2427d3d-96c6-41a3-8a5d-9e0bd3fe4031",
  "email": "user@example.com",
  "name": "John Doe",
  "organization": "Acme Corp",
  "role": "engineer",
  "created_at": "2026-01-15T10:30:00Z",
  "last_login": "2026-03-03T14:00:00Z",
  "subscription_status": "active",
  "subscription_plan": "free"
}
```

| Field                 | Type   | Description                                 |
| --------------------- | ------ | ------------------------------------------- |
| `id`                  | UUID   | User ID (matches Supabase auth.users)       |
| `email`               | string | User email                                  |
| `name`                | string | Display name                                |
| `organization`        | string | Company/organization                        |
| `role`                | enum   | `admin`, `engineer`, `manager`, or `viewer` |
| `subscription_status` | string | `active` or `inactive`                      |
| `subscription_plan`   | string | `free`, `pro`, `consultant`, or `null`      |

### Sync User Profile

Called by the frontend on every session load. Handles two scenarios:

1. **Pending subscription**: If the user paid via Stripe before signing up, migrates the `pending_subscription` into their profile.
2. **No subscription**: Activates the **free plan** automatically (sets `subscription_status = 'active'`, `subscription_plan = 'free'`).

```bash theme={null}
curl -X POST "http://localhost:8000/api/v1/auth/sync" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id": "user-uuid", "email": "user@example.com", "name": "John Doe"}'
```

**Response:**

```json theme={null}
{
  "success": true,
  "message": "Profile synced successfully",
  "user_id": "f2427d3d-96c6-41a3-8a5d-9e0bd3fe4031",
  "email": "user@example.com",
  "subscription_migrated": false,
  "subscription_plan": "free"
}
```

### Refresh JWT Token

```bash theme={null}
curl -X POST "http://localhost:8000/api/v1/auth/refresh" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response:**

```json theme={null}
{
  "access_token": "new_jwt_token",
  "token_type": "bearer",
  "expires_in": 3600
}
```

## Subscription Flow

```mermaid theme={null}
flowchart TD
    A[User signs up] --> B["Supabase creates auth.users row"]
    B --> C["handle_new_user trigger creates profile\n(subscription_status = inactive)"]
    C --> D["Frontend calls POST /auth/sync"]
    D --> E{Pending subscription?}
    E -->|Yes| F["Migrate paid plan to profile"]
    E -->|No| G{Already active?}
    G -->|No| H["Activate free plan"]
    G -->|Yes| I["No change"]
    F --> J["Frontend calls GET /auth/me"]
    H --> J
    I --> J
    J --> K{subscription_status === active?}
    K -->|Yes| L["Allow access to app"]
    K -->|No| M["Redirect to /subscribe"]
```

## Error Responses

**401 Unauthorized:**

```json theme={null}
{
  "error": {
    "code": "AUTHENTICATION_ERROR",
    "message": "Could not validate credentials",
    "details": {"reason": "Invalid token or token expired"},
    "timestamp": "2026-01-15T10:30:00Z",
    "request_id": "req_123456789"
  }
}
```

**402 Payment Required** (when using `check_active_subscription` dependency):

```json theme={null}
{
  "detail": "Active subscription required"
}
```

## Frontend Integration

The `ProtectedRoute` component handles the full auth + subscription flow:

```typescript theme={null}
// 1. On page load, checkSession() runs:
//    - Calls POST /auth/sync (activates free plan if needed)
//    - Calls GET /auth/me (reads subscription_status)
//    - Sets authState to "authenticated" or "no-subscription"

// 2. On explicit sign-in (SIGNED_IN event):
//    - Defers sync + check via setTimeout to avoid Supabase deadlock
//    - Same flow as above

// 3. On sign-out:
//    - Clears session and redirects to /login
```

<Warning>
  Never call `supabase.auth.getSession()` or `refreshSession()` from inside an `onAuthStateChange` callback. The Supabase client holds an internal lock during event dispatch, and nested calls will deadlock.
</Warning>
