# auth.md

Agent authentication for **uploads.sh** — device sign-in and workspace bearer
tokens.

## Audience

Coding agents, CLI automation, and the hosted MCP server. Humans use the same
flow via `uploads login`. Routine agents never receive `ADMIN_TOKEN`.

## How agents get credentials

1. Someone with workspace access (see "Getting workspace access" below) runs:

```bash
npm install --global @buildinternet/uploads
uploads login
```

2. `uploads login` opens a browser device-authorization flow (GitHub or
   magic-link sign-in) and prints the URL/code too, for headless machines
   where the auto-opened browser isn't the one you'll approve in. Approve the
   sign-in, and the CLI mints and saves a workspace token.
3. If the account can access more than one workspace, pass
   `--workspace <name>`.

```bash
uploads login --workspace acme
```

On success the CLI writes `UPLOADS_API_URL`, `UPLOADS_WORKSPACE`, and
`UPLOADS_TOKEN` to the shared buildinternet config and runs `uploads doctor`.
The raw token is not printed.

Details: [enrollment docs](https://github.com/buildinternet/uploads/blob/main/docs/enrollment.md).

## Getting workspace access

Two paths, then `uploads login` as above:

- **Create your own.** Sign in (GitHub or magic link) at
  <https://uploads.sh/account/workspaces/new> and create a workspace. This
  requires a linked GitHub account and is capped at three self-serve
  workspaces per account.
- **Be invited.** A workspace admin invites your email from the workspace People tab or with `uploads invite create`. Accept the invitation (GitHub or magic-link sign-in).

## Using the credential

Send the workspace token on every protected request:

```http
Authorization: Bearer up_<workspace>_…
```

| Scope          | Default on login | Use                                    |
| -------------- | ---------------- | -------------------------------------- |
| `files:read`   | yes              | list, metadata, usage                  |
| `files:write`  | yes              | upload, reconcile                      |
| `files:delete` | yes              | delete / purge. Narrow with `--scopes` |

Workspace service tokens, which workspace admins mint for CI and bots, use
`ups_<workspace>_…` instead. They are sent the same way.

Tokens default to a 90-day lifetime. Hosted MCP at
`https://agents.uploads.sh/mcp` uses the same bearer scheme (workspace is
inferred from the `up_<workspace>_…` or `ups_<workspace>_…` token form).

## Discovery documents

| Resource               | URL                                                              |
| ---------------------- | ---------------------------------------------------------------- |
| This file              | https://uploads.sh/auth.md                                       |
| Agent summary          | https://uploads.sh/llms.txt                                      |
| Full agent guide       | https://uploads.sh/llms-full.txt                                 |
| Repo agent entrypoint  | https://github.com/buildinternet/uploads/blob/main/llms.txt      |
| Integration surfaces   | https://uploads.sh/.well-known/integrations.json                 |
| API catalog (RFC 9727) | https://uploads.sh/.well-known/api-catalog                       |
| OpenAPI (summary)      | https://uploads.sh/.well-known/openapi.json (also /openapi.json) |
| MCP server card        | https://uploads.sh/.well-known/mcp/server-card.json              |
| MCP Registry auth      | https://uploads.sh/.well-known/mcp-registry-auth                 |
| Agent skills index     | https://uploads.sh/.well-known/agent-skills/index.json           |
| Narrative API docs     | https://github.com/buildinternet/uploads/blob/main/docs/api.md   |
| API health             | https://api.uploads.sh/health                                    |
| MCP health             | https://agents.uploads.sh/health                                 |

## OAuth for the hosted MCP

`https://agents.uploads.sh/mcp` also accepts OAuth 2.1 bearer tokens issued by
our authorization server at `https://uploads.sh` (issuer
`https://uploads.sh/api/auth`). It supports PKCE and self-service client
registration, no manual setup — preferably via Client ID Metadata Documents
(CIMD, per MCP spec 2026-07-28: use an HTTPS URL that serves your client
metadata JSON as the `client_id`; the metadata must include `client_name` and
`redirect_uris`, and `redirect_uri` must exactly match a listed entry).
Dynamic client registration (RFC 7591) remains supported for older clients.
A metadata document may list extra `grant_types` (`device_code`, `jwt-bearer`):
the AS keeps `authorization_code` and `refresh_token` and ignores the rest.
Authorize `scope=` may include extras (`openid`, `admin`): the AS downscopes to
the client's registered `files:*` list instead of failing the whole request.
Authorize `resource=` may be `https://agents.uploads.sh` or
`https://agents.uploads.sh/mcp` (same pair for `mcp.uploads.sh`). Discovery
(advertises `client_id_metadata_document_supported`):

```bash
curl -s https://uploads.sh/.well-known/oauth-authorization-server
```

(There is no OIDC surface — `/.well-known/openid-configuration` intentionally
returns 404.)

The old `auth.uploads.sh` origin still serves the same discovery document as a
deprecated alias, and tokens minted under the old issuer are still accepted
for a migration window. New clients should discover and mint against
`uploads.sh`.

Scopes are the same three as the workspace-token table above: `files:read`,
`files:write`, `files:delete`. A human authorizing a client signs in and
grants scopes at `https://uploads.sh/oauth/consent`. Each grant is scoped to
ONE workspace: accounts with several pick it on the consent screen (the
choice sticks for that client until changed, which re-prompts consent), and
the token's `workspace` claim carries the result. An account with no
workspace yet is walked through creating one before it can approve; a token
minted without one is refused by the MCP with a `workspace_required` error.
This is the auth surface for third-party OAuth clients against the hosted
MCP; `uploads login`'s device flow (above) is unrelated and still the way to
mint a long-lived `up_<workspace>_…` workspace token for CLI/agent use.

`api.uploads.sh` does not accept OAuth tokens in v1 — only the hosted MCP
does.

## Operator note

`ADMIN_TOKEN` is a break-glass ops/CI credential, not the routine way to
invite people or mint tokens — see [admin-tokens](https://github.com/buildinternet/uploads/blob/main/docs/admin-tokens.md).
Never place it in agent configs, prompts, or shared issue comments.
