# Screenery auth.md

How an agent gets credentials for Screenery (`https://app.screenery.dev`).

Every credential Screenery issues belongs to a person, or to a project a person
owns. There is no anonymous sign-up and no way for an agent to create an
account on its own. In every flow below, a signed-in person approves the agent
once, in the console. Your job as the agent is to start the flow and show that
person where to click.

## 1. MCP host: OAuth 2.1 with dynamic client registration

Use this when you reach Screenery through its remote MCP server,
`https://app.screenery.dev/mcp`. Most MCP hosts do every step for you.

1. Call `/mcp` with no token. The `401` response carries
   `WWW-Authenticate: Bearer resource_metadata="…"`.
2. Fetch that document (RFC 9728). It names the authorization server,
   `https://app.screenery.dev`.
3. Fetch `https://app.screenery.dev/.well-known/oauth-authorization-server`
   (RFC 8414).
4. Register as a public client: `POST /v1/oauth/register` (RFC 7591). No client
   secret is issued, and the token endpoint takes `none` as its auth method.
5. Send the person to `/v1/oauth/authorize` with PKCE (`S256`) and the scopes
   you need. They sign in with GitHub and approve on a consent screen.
6. Exchange the code at `POST /v1/oauth/token`. Send the access token as
   `Authorization: Bearer …` on every MCP request.

Scopes:

| Scope | What it allows |
| --- | --- |
| `screenery` | Act as the person: create projects, push screenshots, mint tokens, and everything below. The default when no scope is sent. |
| `builds:read` | Read projects, builds, and screenshot diffs between channels. |
| `reviews:write` | Approve or reject a screenshot channel for the person. |
| `comments:write` | Comment on a screenshot channel for the person. |

Ask for the smallest set that does the job. A `builds:read` grant cannot
onboard a repository.

## 2. Local agent or CLI: device sign-in

Use this when you run on the person's machine, through `npx -y screenery mcp`
or the `screenery` CLI.

1. Run `npx -y screenery login`, or call the local MCP server's `screenery_login` tool. It
   prints a URL (`https://app.screenery.dev/device`) and a short code.
2. Give both to the person. They open the URL, sign in with GitHub, and confirm
   the code.
3. The CLI polls until they confirm, then saves the session on that machine.

The code expires. If it does, start again.

## 3. CI: no stored secret

A GitHub Actions job that publishes screenshots does not need a credential
from you. `screenery/push@v1` trades the job's GitHub OIDC token at
`POST /v1/oidc/exchange` for a short-lived publish token. The job needs
`permissions: id-token: write`, and the Screenery GitHub App must be installed
on the repository.

Where OIDC is not available, a person can mint a project publish token in the
console, under the project's Access screen, and store it as the
`SCREENERY_TOKEN` secret.

## Revoking access

A person revokes a session or a token in the console. After that, requests
with it get `401`, and the agent has to start its flow again.

## More

- The whole onboarding guide for agents: `https://app.screenery.dev/llms-full.txt`
- Error codes and what to do about each one: `https://app.screenery.dev/errors/`
