# Lakefront Agent Registration (auth.md)

Lakefront is a cloud-agnostic deploy platform. Agents can register to act **on behalf of a Lakefront
user**. An agent never exceeds the permissions of the user it acts for, and every action it takes is
attributed and independently revocable.

## Step 1: Discovery

Fetch the protected-resource metadata:

```
GET https://dev.lakefront.sh/.well-known/oauth-protected-resource
```

The `agent_auth` block lists the supported flows, scopes, and endpoint URLs. Unauthenticated API calls
also return `401` with `WWW-Authenticate: Bearer resource_metadata="https://dev.lakefront.sh/.well-known/oauth-protected-resource"`.

## Step 2: Choose a registration method

- **identity_assertion** (agent-verified): you are a trusted agent provider and can present a signed
  ID-JAG (`typ: oauth-id-jag+jwt`) asserting a verified user. Synchronous, no human step.
- **user_claimed**: no provider integration. You register with the user's email; a human approves the
  agent in the Lakefront dashboard, then you poll for the credential.

## Step 3: Register

```
POST https://dev.lakefront.sh/api/agent-auth
Content-Type: application/json
```

Agent-verified:

```json
{ "type": "identity_assertion", "idjag": "<JWT>", "requested_scopes": ["deployments:read"] }
```

The ID-JAG must be signed by a registered trusted provider, have `aud: "https://dev.lakefront.sh/"`, `typ:
oauth-id-jag+jwt`, and assert `email_verified: true`. Response (`200`):

```json
{ "credential": "lf_agent_…", "credential_type": "api_key", "expires_at": null, "scopes": ["deployments:read"], "agent_id": "…" }
```

User-claimed:

```json
{ "type": "user_claimed", "email": "user@example.com", "label": "My Agent", "requested_scopes": ["deployments:read"] }
```

Response (`201`):

```json
{ "status": "pending_claim", "claim_token": "…", "claim_url": "https://dev.lakefront.sh/settings/agents", "agent_id": "…" }
```

## Step 4: Claim ceremony (user_claimed only)

Direct the user to `https://dev.lakefront.sh/settings/agents` to approve the pending agent and confirm its scopes. Then
poll:

```
POST https://dev.lakefront.sh/api/agent-auth/claim/complete
{ "claim_token": "…" }
```

`202 { "status": "pending_claim" }` until approved; `200` with the `credential` once approved (returned
exactly once). `403` if the request was denied.

## Step 5: Use the credential

Send it as a bearer token on API calls:

```
Authorization: Bearer lf_agent_…
```

The credential authenticates you as the bound user, capped to your granted scopes.

### Scopes

- `projects:read`: View projects
- `environments:read`: View environments
- `services:read`: View services
- `services:write`: Create & update services
- `deployments:read`: View deployments & status
- `deployments:write`: Trigger deploys, rollbacks & scaling
- `logs:read`: View build & deployment logs
- `connections:read`: View cloud connections
- `secrets:read`: Read & reveal secrets
- `secrets:write`: Create, update & rotate secrets
- `databases:read`: View managed databases & connection info
- `databases:write`: Provision, bind & delete managed databases
- `storage:read`: View managed storage, browse objects & connection info
- `storage:write`: Provision, bind & delete managed storage
- `metrics:read`: View runtime metrics (CPU, memory, requests, latency)
- `alerts:read`: View alert rules & alert history
- `alerts:write`: Create, update & delete alert rules
- `domains:read`: View custom domains & their DNS status
- `domains:write`: Add, verify & remove custom domains

Governance actions (managing members, roles, billing, or writing cloud connections) are never available
to agents.

## Errors

Errors return `{ "error": "…", "error_description": "…" }`. Common codes: `invalid_request`,
`invalid_grant`, `untrusted_issuer`, `unverified_user`, `user_not_found`, `access_denied`.

## Revocation

A user can revoke an agent anytime from `https://dev.lakefront.sh/settings/agents`. You (or your provider) may also
revoke a credential:

```
POST https://dev.lakefront.sh/api/agent-auth/revoke
{ "credential": "lf_agent_…" }
```

After revocation, API calls return `401`. Re-register to recover.
