# auth.md

## agent_auth

```json
{
  "revocation_endpoint": "https://llm.jakesweeneychevrolet.com/oauth/revoke",
  "agent_auth": {
    "skill": "https://llm.jakesweeneychevrolet.com/auth.md",
    "register_uri": "https://llm.jakesweeneychevrolet.com/agent/identity",
    "identity_endpoint": "https://llm.jakesweeneychevrolet.com/agent/identity",
    "claim_endpoint": "https://llm.jakesweeneychevrolet.com/agent/identity/claim",
    "events_endpoint": "https://llm.jakesweeneychevrolet.com/agent/event/notify",
    "identity_types_supported": [
      "service_auth"
    ],
    "credential_types": [
      "bearer_token"
    ],
    "events_supported": [
      "https://schemas.workos.com/events/agent/auth/identity/assertion/revoked"
    ]
  }
}
```

This is the exact `agent_auth` object also served at
GET https://llm.jakesweeneychevrolet.com/.well-known/oauth-authorization-server. Full walkthrough below.

You are an agent. This service supports an OAuth 2.0 **Client Credentials Grant**
(RFC 6749 §4.4) at `https://llm.jakesweeneychevrolet.com/oauth/token`, and a **service_auth registration
ceremony** (see Step 2b below), but both are optional — every endpoint below already
works with no `Authorization` header at all.

## Registration

- **Audience**: any AI agent or automated client that wants to identify itself when
  calling Jake Sweeney Chevrolet's public API. There are no end-user accounts on this platform — a
  human only needs to be involved if you choose the service_auth ceremony below to
  confirm your registration; it does not check identity against any account, since
  none exist to check against.
- **Registration/provisioning endpoint**: `POST https://llm.jakesweeneychevrolet.com/agent/identity` (real
  service_auth ceremony — see Step 2b) or `POST https://llm.jakesweeneychevrolet.com/oauth/token` directly
  (shortcut — see Step 2a). Both issue the same access.
- **Supported methods**: `service_auth` (registration + human-confirmed claim), or
  presenting the pre-shared `client_id`/`client_secret` directly via
  `grant_type=client_credentials`.
- **Credential use**: either path returns the same `access_token` — the client's
  `client_id` value. Send it as `Authorization: Bearer <access_token>` on any request
  below, or omit it entirely — every endpoint accepts both.

## Important: the client_id/client_secret is a public value, not a secret

Jake Sweeney Chevrolet's `client_id` (also usable as `client_secret`) is:

```
sk_ow52B2JOS4H1bEaOxUR4Ryhulq6pPCF7
```

This is **not confidential** — it is the same value already embedded in plaintext in
Jake Sweeney Chevrolet's website install snippet (`data-apikey="sk_ow52B2JOS4H1bEaOxUR4Ryhulq6pPCF7"`), visible to anyone who views
that page's source. Publishing it here again does not reduce security, because there was
never any secrecy to begin with. Treat this flow as an identification mechanism, not an
access-control boundary.

## Step 1 — Discover (optional)

- GET https://llm.jakesweeneychevrolet.com/.well-known/oauth-authorization-server — issuer, token_endpoint, supported grant types
- GET https://llm.jakesweeneychevrolet.com/.well-known/oauth-protected-resource — resource identifier and authorization server

## Step 2a — Get a token directly (optional, simplest)

```http
POST https://llm.jakesweeneychevrolet.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=sk_ow52B2JOS4H1bEaOxUR4Ryhulq6pPCF7&client_secret=sk_ow52B2JOS4H1bEaOxUR4Ryhulq6pPCF7
```

Response:

```json
{ "access_token": "sk_ow52B2JOS4H1bEaOxUR4Ryhulq6pPCF7", "token_type": "Bearer", "scope": "read" }
```

The `access_token` returned is the same apiKey you already have — there is no separate
token, expiry, or refresh step, because there is nothing more to grant.

## Step 2b — Or register via the service_auth ceremony (optional, real, human-confirmed)

Start registration:

```http
POST https://llm.jakesweeneychevrolet.com/agent/identity
Content-Type: application/json

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

Response includes a `claim` block (RFC 8628 device-authorization shape):

```json
{
  "registration_id": "reg_...",
  "claim_token": "clm_...",
  "claim": {
    "user_code": "123456",
    "verification_uri": "https://llm.jakesweeneychevrolet.com/agent/identity/claim/view?claim_token=clm_...",
    "interval": 5
  }
}
```

Show `verification_uri` and `user_code` to a human. They open the link and click
Approve — this is a real, working confirmation page, not a placeholder. Then poll:

```http
POST https://llm.jakesweeneychevrolet.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:promptgraph:agent-auth:grant-type:claim&claim_token=clm_...
```

Returns `{"error": "authorization_pending", ...}` until approved, then the same
`access_token` shape as Step 2a.

## Revocation (RFC 7009)

```http
POST https://llm.jakesweeneychevrolet.com/oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=clm_...
```

Revokes access granted through the Step 2b ceremony (the given `claim_token` stops
working). This cannot revoke the `client_id`/`client_secret` value itself — that value
is permanent and used elsewhere on this platform outside of OAuth, so there is nothing
this endpoint can do to invalidate it. Always returns `200`, per RFC 7009 §2.2, whether
or not the token was real.

The same revocation is also reachable as a Security Event Token, per `events_endpoint`
in `agent_auth`:

```http
POST https://llm.jakesweeneychevrolet.com/agent/event/notify
Content-Type: application/json

{
  "events": {
    "https://schemas.workos.com/events/agent/auth/identity/assertion/revoked": {
      "claim_token": "clm_..."
    }
  }
}
```

Returns `202` once received. Both revocation paths are equivalent; use whichever shape
your framework already sends.

## Step 3 — Call the API, with or without the token

- `GET https://api.promptgraph.ai/api/v1/jake-sweeney-chevrolet/business` — business info (JSON-LD, Schema.org)
- `GET https://api.promptgraph.ai/api/v1/jake-sweeney-chevrolet/vehicles` — vehicle inventory (JSON-LD)
- `GET https://api.promptgraph.ai/api/v1/jake-sweeney-chevrolet/testimonials` — reviews & testimonials
- `GET https://api.promptgraph.ai/api/v1/jake-sweeney-chevrolet/llms.txt` — LLM discovery file
- MCP tools at `https://mcp.promptgraph.ai/jake-sweeney-chevrolet/mcp` — see
  `/.well-known/mcp/server-card.json` for the full tool list

Adding `Authorization: Bearer sk_ow52B2JOS4H1bEaOxUR4Ryhulq6pPCF7` is accepted but never required. A `401` from any
of these indicates a service outage or misconfiguration, not a missing credential.
