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

# Authentication

> Use organization-scoped API keys with Authorization: Bearer for the public API.

## Two auth modes

BlitzBoard uses **different credentials** for management vs integration:

| Use case                             | Credential                      | Header                              |
| ------------------------------------ | ------------------------------- | ----------------------------------- |
| Create / list / revoke / rotate keys | Blitz **admin** JWT (admin API) | `Authorization: Bearer <admin JWT>` |
| Call `/v1/blitz-api/...`             | Integration **API key**         | `Authorization: Bearer bb_live_...` |

Public routes only accept keys that start with `bb_live_`. A normal login JWT is rejected on the public API.

Public routes expect:

```bash theme={null}
Authorization: Bearer bb_live_<secret>
```

<Note>
  This is **not** the same as Stripe’s secret key. Stripe uses its own secrets and webhook signatures. BlitzBoard public auth is only for `/v1/blitz-api`.
</Note>

## Who can manage keys

Only a **BlitzBoard super admin** (`isSystemAdmin`) via the **admin backend**. Organization creators and organization admins cannot create or manage API keys.

## Generate an API key

A BlitzBoard super admin issues a key for an organization from the admin side (`POST /api-keys` on the admin API) with:

```json theme={null}
{
  "name": "Production Integration",
  "organizationId": "507f1f77bcf86cd799439011"
}
```

Copy the full `bb_live_...` value when it is shown — it is only displayed once.

Audit fields on the key:

| Field                         | Meaning                                          |
| ----------------------------- | ------------------------------------------------ |
| `createdBy`                   | Super admin who created the key                  |
| `lastRotatedBy` / `rotatedAt` | Super admin who last rotated the secret (if any) |

## Manage keys (admin API)

Key management lives on the **admin backend**, not the public/main app API.

### Create

`POST /api-keys`

Response includes `apiKey` once, plus `id`, `keyPrefix`, `organizationId`, `createdBy`, and `status`.

### List

`GET /api-keys?organizationId=<orgId>`

### Revoke

`DELETE /api-keys/:id`

### Rotate

`POST /api-keys/:id/rotate`

Returns a new plaintext `apiKey` once; the previous secret stops working. `createdBy` stays the original admin; `lastRotatedBy` / `rotatedAt` record who rotated.

## Organization scope

Every key is bound to one `organizationId`. On public requests:

1. `ApiKeyGuard` validates the Bearer key and loads the **organization creator** as the acting user (for team permissions), plus org context from the key.
2. Team create/list inject that org automatically.
3. Routes with `teamId` ensure the team belongs to the key’s organization.

A valid key for Org A cannot read or mutate Org B’s teams, players, or schedules.
