# auth.md

Readplace publishes this file so AI agents can obtain delegated access to a
signed-in user's reading queue. Readplace is both the OAuth 2.0 authorization
server and the protected resource; its issuer is `https://readplace.com`.

## Audience

This recipe is for agents acting **on behalf of a Readplace user** — saving
links to, reading, and managing that user's queue. Readplace has no machine-only
or anonymous identity: every credential is bound to a human Readplace account
that explicitly authorizes the agent.

## 1. Discover

Fetch the two discovery documents:

- Protected resource metadata: `GET https://readplace.com/.well-known/oauth-protected-resource`
- Authorization server metadata: `GET https://readplace.com/.well-known/oauth-authorization-server`

The authorization server metadata carries an `agent_auth` block whose `skill`
points back at this file and whose `registration_methods` describe the flow
below.

## 2. Pick a method

Readplace supports a single registration method: **OAuth 2.0 Authorization Code
with PKCE** ([RFC 7636](https://www.rfc-editor.org/rfc/rfc7636)). The client is
public — there is no client secret. Readplace does not offer ID-JAG,
verified-email, or anonymous claim flows.

## 3. Get a client_id

Readplace does not yet offer self-service Dynamic Client Registration
([RFC 7591](https://www.rfc-editor.org/rfc/rfc7591)). Email
[readplace+agents@readplace.com](mailto:readplace+agents@readplace.com) with your
agent's name and redirect URI to register a `client_id`. (Readplace's own Firefox
and Chrome extensions are already registered.)

## 4. Authorize

Redirect the user to the authorization endpoint:

```
GET https://readplace.com/oauth/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=YOUR_REDIRECT_URI
  &code_challenge=BASE64URL(SHA256(code_verifier))
  &code_challenge_method=S256
  &state=OPAQUE_VALUE
  &scope=queue
```

`scope` is optional and makes no difference: Readplace does not sub-divide
access, so every token carries the same full read/write access to the user's
queue (see step 6). The discovery metadata labels that single access level
`queue`. The user signs in if needed and approves, then Readplace redirects to
`YOUR_REDIRECT_URI?code=AUTH_CODE&state=OPAQUE_VALUE`.

## 5. Exchange the code

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

grant_type=authorization_code&code=AUTH_CODE&redirect_uri=YOUR_REDIRECT_URI&client_id=YOUR_CLIENT_ID&code_verifier=CODE_VERIFIER
```

The response is JSON with `access_token`, `refresh_token`, and
`token_type: "Bearer"`.

## 6. Use the access_token

The queue API is a [Siren](https://github.com/kevinswiber/siren) hypermedia API.
Send the bearer token on every request, start at the entry point, and follow the
links and actions it returns:

```
GET https://readplace.com/queue
Authorization: Bearer ACCESS_TOKEN
Accept: application/vnd.siren+json
```

A Readplace access token carries full read/write access to the authenticated
user's reading queue — the single access level the discovery metadata labels
`queue`. Readplace does not sub-divide or separately enforce scopes. When the
access token expires, refresh it:

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

grant_type=refresh_token&refresh_token=REFRESH_TOKEN&client_id=YOUR_CLIENT_ID
```

## 7. Errors

| Response | Meaning |
| --- | --- |
| `400 invalid_request` | A required parameter is missing or malformed |
| `400 invalid_client` | The `client_id` is not registered |
| `401 access_denied` | The user is not signed in, or denied the request |
| `401` from the queue API | The bearer token is missing, expired, or revoked |

## 8. Revoke

Revoke an access or refresh token (revoking either drops the paired token):

```
POST https://readplace.com/oauth/revoke
Content-Type: application/json

{ "token": "ACCESS_OR_REFRESH_TOKEN" }
```

A user can also revoke an agent's access at any time from their Readplace
account.
