# auth.md — FlightSeatMap You are an agent. This document tells you how to register, authenticate, and call FlightSeatMap on behalf of a user: **discover → register → authorize → use → handle errors**. Follow the steps in order. FlightSeatMap uses plain OAuth 2.1 with [Dynamic Client Registration (RFC 7591)](https://datatracker.ietf.org/doc/html/rfc7591) and PKCE. There is no proprietary agent-registration grant and no API-key signup form — if your client speaks MCP OAuth, you already speak this. Two hosts are involved: - `https://flightseatmap.com` — the website, the OpenAPI spec, and the docs. - `https://mcp.flightseatmap.com` — the MCP server, the authorization server, and the protected resource. **All OAuth happens here.** ## Step 1 — Discover An unauthenticated call to a protected tool returns: ```http HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer resource_metadata="https://mcp.flightseatmap.com/.well-known/oauth-protected-resource" ``` ### 1a. Protected Resource Metadata (RFC 9728) ```http GET https://mcp.flightseatmap.com/.well-known/oauth-protected-resource ``` ```json { "resource": "https://mcp.flightseatmap.com", "resource_name": "FlightSeatMap", "resource_documentation": "https://flightseatmap.com/auth.md", "authorization_servers": ["https://mcp.flightseatmap.com"], "scopes_supported": ["read", "write", "search"], "bearer_methods_supported": ["header"] } ``` ### 1b. Authorization Server Metadata (RFC 8414) ```http GET https://mcp.flightseatmap.com/.well-known/oauth-authorization-server ``` ```json { "issuer": "https://mcp.flightseatmap.com", "authorization_endpoint": "https://mcp.flightseatmap.com/oauth/authorize", "token_endpoint": "https://mcp.flightseatmap.com/oauth/token", "registration_endpoint": "https://mcp.flightseatmap.com/oauth/register", "revocation_endpoint": "https://mcp.flightseatmap.com/oauth/revoke", "response_types_supported": ["code"], "grant_types_supported": ["authorization_code", "refresh_token"], "code_challenge_methods_supported": ["S256"], "token_endpoint_auth_methods_supported": ["none"], "scopes_supported": ["read", "write", "search"], "agent_auth": { "skill": "https://flightseatmap.com/auth.md", "identity_types_supported": [], "register_uri": "https://mcp.flightseatmap.com/oauth/register", "registration_endpoint": "https://mcp.flightseatmap.com/oauth/register", "revocation_uri": "https://mcp.flightseatmap.com/oauth/revoke" } } ``` Read the endpoints from this document rather than hardcoding them. ### About the `agent_auth` block `agent_auth.skill` points back at this document. `agent_auth.register_uri` (aliased as `registration_endpoint`) is the RFC 7591 endpoint you'll use in Step 2, and `agent_auth.revocation_uri` is the RFC 7009 endpoint from the Errors section below. Both are real and callable. `identity_types_supported` is deliberately **empty**. FlightSeatMap does not implement the WorkOS agent-auth registration profile — there is no `/agent/identity`, no claim ceremony, and no `urn:ietf:params:oauth:grant-type:jwt-bearer` exchange here. If your client is looking for `anonymous`, `service_auth`, or `identity_assertion`, none are available: register with plain dynamic client registration and PKCE instead, exactly as Steps 2 and 3 describe. An empty list is the honest answer, not an oversight. ## Step 2 — Register Register yourself as a public client. No human involvement, no API key to copy, no approval queue. ```http POST /oauth/register Content-Type: application/json { "client_name": "Your Agent", "redirect_uris": ["https://your-agent.example.com/oauth/callback"], "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "token_endpoint_auth_method": "none" } ``` Response (201): ```json { "client_id": "…", "client_secret": "…", "client_name": "Your Agent", "redirect_uris": ["https://your-agent.example.com/oauth/callback"], "scope": "read search write", "grant_types": ["authorization_code"], "response_types": ["code"], "token_endpoint_auth_method": "none" } ``` Store `client_id`. Clients are registered as **public** clients (`token_endpoint_auth_method: "none"`), so authenticate with PKCE and ignore `client_secret`. Redirect URIs must be `https`, `http` on `localhost`/`127.0.0.1`, or the `urn:ietf:wg:oauth:2.0:oob` URN. Registration is rate limited to 5 per hour per IP — persist your `client_id` instead of registering on every run. ## Step 3 — Authorize (user consent) Generate a `code_verifier` (43–128 chars) and `code_challenge = BASE64URL(SHA256(verifier))`. Send the user to: ``` https://mcp.flightseatmap.com/oauth/authorize ?client_id= &redirect_uri= &response_type=code &scope=read+search+write &code_challenge= &code_challenge_method=S256 &state= ``` The user signs in (or signs up) at FlightSeatMap and approves. Surface the destination to them plainly — this is their only consent gate. You get `?code=…&state=…` back on your callback; verify `state` matches. Exchange the code: ```http POST /oauth/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code= &redirect_uri= &client_id= &code_verifier= ``` ```json { "access_token": "…", "token_type": "Bearer", "expires_in": 2592000, "refresh_token": "…", "scope": "read search write" } ``` Refresh with `grant_type=refresh_token` when `expires_in` elapses. Do not re-run Step 2 to refresh. ## Step 4 — Use it ```http POST https://mcp.flightseatmap.com/mcp Authorization: Bearer Content-Type: application/json ``` Streamable-HTTP MCP. Tools: | Tool | Auth | Notes | | --- | --- | --- | | `get_seatmap` | none | Cached seat map for a flight | | `find_best_seats` | none | Ranked seats for stated preferences | | `get_seat_info` | none | Detail for one seat | | `get_seat_reviews` | none | User-submitted reviews | | `interactive_seat_finder` | none | Renders an interactive seatmap app | | `search_flight` | **paid plan** | Live airline fetch, fresh availability | | `list_seat_alerts` / `create_seat_alert` / `delete_seat_alert` | **signed-in** | Email alerts on seat availability | The read-only seatmap tools work with **no token at all** — only reach for OAuth when you need live search or seat alerts. Other surfaces for the same data: - OpenAPI 3.1: - Agent skills: - A2A agent card: - MCP server card: - Human docs: ## Step 5 — Plans and payment Cached seatmap tools are free and unauthenticated. Live search and seat alerts need a paid plan. If a tool returns an upgrade prompt, send the user to — plans start at $3.99/mo, and a single flight can be unlocked for $1.99. Do not attempt to work around the gate; the tool response carries the checkout URL. ## Errors | Code | Where | What to do | | --- | --- | --- | | `invalid_client` | `/oauth/token` | `client_id` unknown or revoked. Re-run Step 2. | | `invalid_grant` | `/oauth/token` | Code or refresh token expired/replayed. Re-run Step 3. | | `invalid_request` | `/oauth/token` | Usually a missing or mismatched `code_verifier`. Fix and retry. | | `401` | `/mcp` | Token expired or revoked. Refresh once; if that fails, restart at Step 1. | | upgrade prompt | `/mcp` tool result | Plan gate. Send the user to the checkout URL in the response. | | `429` | any | Rate limited. Back off exponentially and retry. | | `5xx` | any | Retry the same request with exponential backoff. | Access tokens live 30 days and refresh silently. Revoke a token yourself ([RFC 7009](https://datatracker.ietf.org/doc/html/rfc7009)) when you're done with it: ```http POST https://mcp.flightseatmap.com/oauth/revoke Content-Type: application/x-www-form-urlencoded token= &client_id= ``` To retire a registered client entirely, email . ## Contact · Terms: