# auth.md — how agents authenticate with RankSage

RankSage's programmatic surface is a read-only [MCP server](https://www.ranksage.com/.well-known/mcp/server-card.json)
(Model Context Protocol, Streamable HTTP) at `https://web-production-a039f.up.railway.app/api/v1/mcp`, described by the
[OpenAPI spec](https://www.ranksage.com/openapi.json). Every request needs a Bearer token. This
file walks through getting one.

## Discover

Machine-readable discovery documents:

- RFC 8414 authorization server metadata: `https://web-production-a039f.up.railway.app/.well-known/oauth-authorization-server`
  (authoritative) and a consistent mirror at `https://www.ranksage.com/.well-known/oauth-authorization-server`.
- RFC 9728 protected resource metadata: `https://web-production-a039f.up.railway.app/.well-known/oauth-protected-resource`
  (authoritative) and a mirror at `https://www.ranksage.com/.well-known/oauth-protected-resource`.
- MCP server card: `https://www.ranksage.com/.well-known/mcp/server-card.json`.

The metadata declares `code_challenge_methods_supported: ["S256"]` — PKCE is
mandatory — and a `registration_endpoint` (the register_uri for dynamic client
registration), so no human has to issue you credentials.

## Pick a method

Two supported identity types:

1. **OAuth 2.0 authorization-code with PKCE** — for agents acting on behalf of a
   RankSage user who can complete a browser consent step once. MCP clients such as
   Claude, Claude Code and Cursor do this automatically from the discovery metadata.
2. **Personal access token (PAT)** — for headless use. A RankSage user creates the
   token in the app (Settings → MCP) and hands it to the agent. Tokens are scoped at
   creation and stored hashed server-side.

Anonymous access is not supported: every MCP tool reads a specific customer's
data, so there is nothing meaningful to serve without an identity.

## Scopes

Request the least privilege that does the job:

- `mcp` — Read-only access to every core RankSage MCP tool: visibility, content, competitors, behaviour, traffic and the action queue. No write operations exist on this surface.
- `conversations` — Read stored RankSage assistant conversations. Grantable only to personal access tokens created in the RankSage app with explicit consent — OAuth grants cannot carry this scope.

## Register (OAuth path)

POST `https://web-production-a039f.up.railway.app/api/v1/oauth/register` (RFC 7591) with your
`client_name` and `redirect_uris`. The response contains your `client_id`.
No client secret is issued — the token endpoint uses `token_endpoint_auth_method: none`
with PKCE carrying the proof.

## Claim the credential

1. Send the user to `https://web-production-a039f.up.railway.app/oauth/authorize` with
   `response_type=code`, your `client_id`, a `redirect_uri` you registered,
   `scope=mcp`, and a `code_challenge` (`code_challenge_method=S256`).
2. The user signs in and approves the consent screen.
3. Exchange the returned code at `https://web-production-a039f.up.railway.app/api/v1/oauth/token` with
   `grant_type=authorization_code` and your `code_verifier`.

You receive an access token (1-hour lifetime) and a refresh token (90 days,
single-use, rotated on every refresh).

For the PAT path there is nothing to claim programmatically: the user creates the
token in the RankSage app and configures it in your MCP client.

## Use the credential

Send it as `Authorization: Bearer <token>` on POST `https://web-production-a039f.up.railway.app/api/v1/mcp`,
then speak MCP: `initialize`, `tools/list`, `tools/call`. 17 read-only
tools are available; the server card lists them all. All data access is
tenant-bound server-side — no request parameter can name another customer.

## Errors

- `401` with a JSON-RPC error body — missing or invalid Bearer token. Note the
  response is a JSON-RPC envelope, not (yet) a `WWW-Authenticate` challenge header.
- `403` naming a scope — the tool needs a scope your token does not carry
  (e.g. `conversations`). PATs can be re-created with the scope; OAuth grants
  cannot carry `conversations` at all, by design.
- `429` — rate limited; back off and retry.

## Revocation

- OAuth tokens: POST the token to `https://web-production-a039f.up.railway.app/api/v1/oauth/revoke`.
  Refresh tokens also die on rotation misuse.
- PATs: the user deletes the token in the RankSage app; it is invalid immediately.

Questions: hello@ranksage.com · Human docs: https://www.ranksage.com/developers
