# auth.md

The Meaning of Numbers publishes this file at https://themeaningofnumbers.com/auth.md so an agent can
read how authentication actually works on this origin. This origin is
not an OAuth authorization server for agents. There is **no** agent registration,
**no** ID-JAG / identity_assertion flow, and **no** API key you can mint.

Resource host: https://themeaningofnumbers.com
Authorization server metadata lives on this same origin so a walkthrough can
follow PRM to AS metadata without a dead link. The AS does **not** mint tokens.
`identity_types_supported` is empty. `register_uri`, `claim_uri`, and
`revocation_uri` return **401** with `WWW-Authenticate`.

Treat the Protected Resource Metadata as authoritative if this file and the
JSON ever disagree.

## Discover

1. This file (`agent_auth.skill`): [https://themeaningofnumbers.com/auth.md](https://themeaningofnumbers.com/auth.md)
2. RFC 9728 Protected Resource Metadata: [https://themeaningofnumbers.com/.well-known/oauth-protected-resource](https://themeaningofnumbers.com/.well-known/oauth-protected-resource)
3. RFC 8414 authorization-server metadata: [https://themeaningofnumbers.com/.well-known/oauth-authorization-server](https://themeaningofnumbers.com/.well-known/oauth-authorization-server)
4. MCP resource metadata: [https://themeaningofnumbers.com/.well-known/oauth-protected-resource/mcp](https://themeaningofnumbers.com/.well-known/oauth-protected-resource/mcp)

`agent_auth.register_uri`: [https://themeaningofnumbers.com/agent/auth](https://themeaningofnumbers.com/agent/auth)
`agent_auth.claim_uri`: [https://themeaningofnumbers.com/agent/auth/claim](https://themeaningofnumbers.com/agent/auth/claim)
`agent_auth.revocation_uri`: [https://themeaningofnumbers.com/agent/auth/revoke](https://themeaningofnumbers.com/agent/auth/revoke)

## Pick a method

The only honest method is **none for agents**. Public machine surfaces are
unauthenticated. Humans use a browser magic link. There is no
`identity_assertion`, `service_auth`, or `anonymous` registration tree.
`identity_types_supported` is an empty array on purpose.

## Register

`register_uri` is live: [https://themeaningofnumbers.com/agent/auth](https://themeaningofnumbers.com/agent/auth).
GET or POST returns **401** `application/problem+json` plus
`WWW-Authenticate: Bearer resource_metadata="https://themeaningofnumbers.com/.well-known/oauth-protected-resource"`.
OPTIONS is not 404. No client_id is minted. No ID-JAG is accepted.

## Claim ceremony

`claim_uri` is live: [https://themeaningofnumbers.com/agent/auth/claim](https://themeaningofnumbers.com/agent/auth/claim)
(401, no OTP). Humans who want an account open
[https://themeaningofnumbers.com/account/sign-in](https://themeaningofnumbers.com/account/sign-in) in a browser.

## Exchange

There is no JWT-bearer grant. `GET /api/v1/session` and `GET /agent/auth`
always return **401**. They do not mint a session.

## Use the access token

There is no access token. Call public read URLs without an Authorization
header.

## Errors

Failed credential-shaped calls return RFC 9457 `application/problem+json`
with `code`, `message`, and `resolution`. A 401 also sends
`WWW-Authenticate` (see the walkthrough). A missing paid reading session
returns **402**.

## Revocation

`revocation_uri` is live: [https://themeaningofnumbers.com/agent/auth/revoke](https://themeaningofnumbers.com/agent/auth/revoke)
(401, nothing to revoke). Humans cancel a subscription in the Stripe
Customer Portal (`POST /api/portal`, signed-in browser).

## Walkthrough simulation

A dry run. No token is minted and no card is charged. Replay the numbered
requests against themeaningofnumbers.com. Each URL below is live.

1. Fetch this file.

```http
GET /auth.md HTTP/1.1
Host: themeaningofnumbers.com
Accept: text/markdown
```

```
GET https://themeaningofnumbers.com/auth.md
```

Expected: 200 `text/markdown` starting with `# auth.md`.

2. Fetch RFC 9728 Protected Resource Metadata.

```http
GET /.well-known/oauth-protected-resource HTTP/1.1
Host: themeaningofnumbers.com
Accept: application/json
```

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

Expected: 200 JSON. `authorization_servers` lists this origin so the
walkthrough can fetch AS metadata. `bearer_methods_supported` is empty.
`unauthenticated_access` is true. Public reads still need no token.

3. Confirm the human sign-in page exists (magic link, browser only).

```http
GET /account/sign-in HTTP/1.1
Host: themeaningofnumbers.com
Accept: text/html
```

```
GET https://themeaningofnumbers.com/account/sign-in
```

Expected: 200 HTML. Agents should not scrape the session cookie.

4. Call the public machine index (no Authorization header).

```http
GET /api/v1 HTTP/1.1
Host: themeaningofnumbers.com
Accept: application/json
```

```
GET https://themeaningofnumbers.com/api/v1
```

Expected: 200 JSON. No token required.

5. Fetch authorization-server metadata.

```http
GET /.well-known/oauth-authorization-server HTTP/1.1
Host: themeaningofnumbers.com
Accept: application/json
```

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

Expected: 200 JSON. `agent_auth.register_uri` is
`https://themeaningofnumbers.com/agent/auth`. `identity_types_supported` is empty.

6. Probe register_uri. No credential is minted.

```http
GET /agent/auth HTTP/1.1
Host: themeaningofnumbers.com
Accept: application/json
```

```
GET https://themeaningofnumbers.com/agent/auth
```

Expected: **401** `application/problem+json` plus
`WWW-Authenticate: Bearer resource_metadata="https://themeaningofnumbers.com/.well-known/oauth-protected-resource"`.

7. Probe the session slot.

```http
GET /api/v1/session HTTP/1.1
Host: themeaningofnumbers.com
Accept: application/json
```

```
GET https://themeaningofnumbers.com/api/v1/session
```

Expected: **401** with the same `WWW-Authenticate` header.

## Public, no credentials

These need no login:

- HTML pages and their `.md` twins (`Accept: text/markdown` or append `.md`)
- [https://themeaningofnumbers.com/llms.txt](https://themeaningofnumbers.com/llms.txt)
- [https://themeaningofnumbers.com/openapi.json](https://themeaningofnumbers.com/openapi.json)
- [https://themeaningofnumbers.com/docs](https://themeaningofnumbers.com/docs)
- [https://themeaningofnumbers.com/api/v1](https://themeaningofnumbers.com/api/v1) and [https://themeaningofnumbers.com/api/v1/pages](https://themeaningofnumbers.com/api/v1/pages)
- [https://themeaningofnumbers.com/.well-known/ai-catalog.json](https://themeaningofnumbers.com/.well-known/ai-catalog.json)
- [https://themeaningofnumbers.com/mcp](https://themeaningofnumbers.com/mcp) (read-only Streamable HTTP MCP)
- [https://themeaningofnumbers.com/server.json](https://themeaningofnumbers.com/server.json)
- [https://themeaningofnumbers.com/sandbox](https://themeaningofnumbers.com/sandbox) (never charges)
- Free calculators in the browser

## Humans: magic link

Signed-in account (Personal Month subscription, billing portal, saved birth date):

1. Open [https://themeaningofnumbers.com/account/sign-in](https://themeaningofnumbers.com/account/sign-in).
2. Enter an email. Supabase sends a magic link.
3. The link returns through `https://themeaningofnumbers.com/auth/callback`.
4. Session cookies are first-party, for browsers. Agents should not scrape them.

There is no password grant and no third-party social login.

## Humans: one-time reading

1. Complete a calculator form.
2. `POST https://themeaningofnumbers.com/api/checkout` returns a Stripe Checkout URL.
3. The human pays on checkout.stripe.com.
4. Success lands on `/reading/{slug}?session_id=...`.
5. `POST https://themeaningofnumbers.com/api/reading` with that `sessionId` streams the paid text.

A missing or unpaid session returns **402** `application/problem+json`.
Agents cannot substitute a card or session they do not own.

## Signed-in HTTP (browser session)

| Endpoint | Who | Credential |
|---|---|---|
| `POST /api/subscribe/checkout` | signed-in human | session cookie |
| `POST /api/portal` | signed-in subscriber | session cookie |
| `POST /api/account/profile` | signed-in human | session cookie |

Unauthenticated calls return **401** `application/problem+json` with a
`WWW-Authenticate` header whose `resource_metadata` points at the RFC 9728
document. That document lists this origin as the issuer so a walkthrough can
fetch AS metadata. The AS does not mint tokens.

## Machine credentials we actually use

| Caller | Header | Purpose |
|---|---|---|
| Stripe | `stripe-signature` | `POST /api/webhooks/stripe` |
| Vercel Cron | `Authorization: Bearer CRON_SECRET` | `GET /api/cron/monthly-readings` |

Those secrets are not issued to third parties.

## Pricing and terms

- [https://themeaningofnumbers.com/docs](https://themeaningofnumbers.com/docs)
- [https://themeaningofnumbers.com/pricing.md](https://themeaningofnumbers.com/pricing.md)
- [https://themeaningofnumbers.com/terms](https://themeaningofnumbers.com/terms)
- [https://themeaningofnumbers.com/privacy](https://themeaningofnumbers.com/privacy)
- [https://themeaningofnumbers.com/refunds](https://themeaningofnumbers.com/refunds)

Support: info@themeaningofnumbers.com
