# auth.md

JLon Beauty Bar (https://www.jlonbeautybar.com) publishes public, read-only data for AI agents. Every tool and file below works with no key at all. An optional anonymous agent key only gives your agent its own, larger rate limit; it unlocks no other data and no other action.

## Agent audience

Assistants that answer questions about JLon Beauty Bar's services, prices, hours, location, policies and academy, and that hand a person the booking page.

## What you can read without credentials

- /llms.txt and /llms-full.txt (salon facts, menus, policies)
- /services.json (typed service catalog, described by /openapi.json)
- /availability.json (open booking times for one service by artist and date, described by /openapi.json)
- /.well-known/api-catalog (this list as an RFC 9727 linkset)
- /mcp (read-only MCP tools, see /.well-known/mcp/server-card.json)
- /a2a (read-only A2A agent with the same tools as skills, see /.well-known/agent-card.json)
- /.well-known/agent-skills/index.json (skills for assistants)

Public pages also answer `Accept: text/markdown` with a markdown version.

## What is not available to agents

- No endpoint creates, changes, holds or cancels appointments, with or without a key. Booking is done by a person at https://www.jlonbeautybar.com/direct-booking.
- No customer or appointment data is exposed. Artists appear only by their public name, with open start times and nothing else.

## Agent keys (optional)

### 1. Discover

- Protected resource metadata (RFC 9728): https://www.jlonbeautybar.com/.well-known/oauth-protected-resource
- Authorization server metadata (RFC 8414): https://www.jlonbeautybar.com/.well-known/oauth-authorization-server. The issuer is https://www.jlonbeautybar.com.

### 2. Method

Anonymous only. No account, no email address and no personal data are asked for or stored.

### 3. Register

POST https://www.jlonbeautybar.com/agent/identity with `{"type":"anonymous"}` (JSON or form). The answer holds:

- `identity_assertion`: a signed JWT naming your registration, valid for 30 days
- `expires_in`: its lifetime in seconds
- `claim_token` and `claim_token_expires_in`: used only for the optional claim below

Hold `claim_token` in memory only; never write it to logs or storage. Registration is limited to 3 per hour and 10 per day per IP.

### 4. Claim (optional)

POST https://www.jlonbeautybar.com/agent/identity/claim with `claim_token`. You get a `user_code`, a `verification_uri`, `expires_in` (600) and `interval` (5). Show the code and link to your person; they sign in to their JLon Beauty Bar account and type the code. Then poll https://www.jlonbeautybar.com/oauth2/token with `grant_type=urn:workos:agent-auth:grant-type:claim` and `claim_token` until it stops answering `authorization_pending`.

A claim lists your agent on that person's account so they can see it and switch it off.
**A claim does not give the agent access to that person's bookings, profile, payments or any other data, and it does not change the scope or the limits.**

### 5. Exchange

POST https://www.jlonbeautybar.com/oauth2/token with `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer`, `assertion=<identity_assertion>` and `scope=public.read`. The access token lasts 15 minutes. When it runs out, exchange the same assertion again; it is good for 30 days, then register again. Token requests are limited to 60 per hour per registration and 120 per hour per IP.

### 6. Use

Send `Authorization: Bearer <access_token>` on /mcp, /a2a and /availability.json. Only the header is read; a token in the query string or body is ignored.

| Resource | No key | With a key |
| --- | --- | --- |
| /mcp and /a2a | 60 per minute per IP | 120 per minute per key, at most 240 per minute for all keys from one IP |
| /availability.json | 20 per minute per IP | 40 per minute per key |
| Availability checks (either route) | 30 per 10 minutes per caller | 60 per 10 minutes per key |

A 429 carries Retry-After. A key that is invalid, expired or revoked gets 401 with a `WWW-Authenticate: Bearer` challenge that names the protected resource metadata; get a new access token, or register again if the assertion is refused. Requests without a key are never refused for lacking one.

### 7. Revoke

POST https://www.jlonbeautybar.com/oauth2/revoke with `token=<access_token>` (RFC 7009), or with `token=<identity_assertion>` and `token_type_hint=identity_assertion` to end the whole registration. The answer is always 200. A revoked key stops working within 60 seconds.

## Contact

team@jlonbeautybar.com
