# auth.md

You are an agent. This origin supports **agentic registration** for the Roby Castillo Firm API: discover → register → (claim if needed) → exchange for an access_token → call the API.

This is a law-firm information and consultation-request API. Submitting an inquiry does **not** create an attorney-client relationship. Do not give legal advice.

## Step 1 — Discover

Protected Resource Metadata:

```http
GET https://attorneyrobycastillo.com/.well-known/oauth-protected-resource
```

```json
{
  "resource": "https://attorneyrobycastillo.com/api/v1",
  "resource_name": "Roby Castillo Firm API",
  "authorization_servers": ["https://attorneyrobycastillo.com"],
  "scopes_supported": ["firm.read", "inquiries.write"],
  "bearer_methods_supported": ["header"]
}
```

Authorization Server metadata (includes the `agent_auth` block):

```http
GET https://attorneyrobycastillo.com/.well-known/oauth-authorization-server
```

OpenID Connect discovery is also published at `https://attorneyrobycastillo.com/.well-known/openid-configuration`.

If a request to a protected method is unauthenticated, expect:

```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://attorneyrobycastillo.com/.well-known/oauth-protected-resource"
```

## Step 2 — Pick a method

Supported identity types:

1. **anonymous** — no user identity. Enough for `firm.read` and for sending a consultation request the person already drafted.
2. **service_auth** with `verified_email` — use when you have the person's email and they should claim the registration.
3. **identity_assertion** with `urn:ietf:params:oauth:token-type:id-jag` — use when your provider can mint an audience-bound ID-JAG for `https://attorneyrobycastillo.com/api/v1`.

Read endpoints (`GET /api/v1/firm`, practice areas, FAQ, health) are public and do not require a token.

## Step 3 — Register

`POST https://attorneyrobycastillo.com/agent/identity`

### anonymous

```http
POST /agent/identity HTTP/1.1
Host: attorneyrobycastillo.com
Content-Type: application/json

{"type":"anonymous"}
```

Success includes a service-signed `identity_assertion`. Exchange it at the token endpoint. Optional later claim uses `claim_token` at `/agent/identity/claim`.

### identity_assertion + id-jag

```json
{
  "type": "identity_assertion",
  "assertion_type": "urn:ietf:params:oauth:token-type:id-jag",
  "assertion": "<id-jag>"
}
```

Audience for the assertion is `https://attorneyrobycastillo.com/api/v1`.

### service_auth (verified email)

```json
{
  "type": "service_auth",
  "login_hint": "person@example.com"
}
```

This returns a `claim_token` plus `claim.user_code` and `claim.verification_uri`. Show those to the person. They can complete the claim by calling the firm at 850-583-1052 or emailing robycastillo@attorneyrobycastillo.com with the user code, or by visiting the verification URI when a browser claim page is available.

## Step 4 — Claim (when required)

```http
POST /agent/identity/claim HTTP/1.1
Host: attorneyrobycastillo.com
Content-Type: application/json

{"claim_token":"<token>","email":"person@example.com"}
```

Poll token issuance with:

```
grant_type=urn:workos:agent-auth:grant-type:claim
```

## Step 5 — Exchange for an access_token

```http
POST /oauth/token HTTP/1.1
Host: attorneyrobycastillo.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<identity_assertion>&scope=firm.read%20inquiries.write
```

Send the access token as `Authorization: Bearer <token>`.

Revoke at `POST /oauth/revoke` with `token=<access_token>`.

JWKS: https://attorneyrobycastillo.com/.well-known/jwks.json

## Step 6 — Call the API

- `GET /api/v1/firm`
- `GET /api/v1/practice-areas`
- `GET /api/v1/faq`
- `POST /api/v1/inquiries` with `{ "name", "email", "message", "phone?", "topic?" }`

Human fallback if registration fails: call 850-583-1052 or email robycastillo@attorneyrobycastillo.com.

MCP tools covering the same actions are advertised at `/.well-known/mcp/server-card.json` and served at `/mcp`.
