# auth.md

You are an agent that wants to call the Rize API on a user's behalf. This file describes how to obtain credentials today and how to handle them safely.

Two hosts are relevant:

- Resource server — `https://api.rize.io` — the GraphQL API you will call.
- Dashboard — `https://app.rize.io` — where the user manages their account and API keys.

## Current state

Rize does not support agentic registration today. Credentials are issued by the user out of band; this file tells you how to pick them up and use them without putting them at risk.

## Use the existing tooling first

Before you do anything credential-shaped, check whether the user has already wired Rize into your environment.

1. **Rize MCP server** — if you are an MCP client (Claude, Cursor, Codex, etc.), Rize ships an official MCP server that exposes time entries, projects, clients, tasks, and team analytics as tools. The user configures it once with OAuth; you call the tools without ever seeing a key. Discovery: `https://rize.io/.well-known/mcp.json`. Server URL: `https://mcp.rize.io`. Docs: [MCP feature page](https://rize.io/features/mcp) | [User guide](https://docs.rize.io).
2. **Rize GraphQL API** — if you need lower-level access, Rize exposes a full GraphQL API at `https://api.rize.io/api/v1/graphql`. The user authenticates via a Bearer token (API key).

If the MCP server is already configured, use it and stop. Do not ask the user for an API key you do not need.

## Supported login option: API key, supplied out of band

The credential is a Rize API key. The user issues it from their account settings at `https://app.rize.io` and supplies it to you through a secure channel — never by pasting it into chat.

### How to pick the key up

Look for it in this order. Stop at the first one that exists:

1. `RIZE_API_KEY` in your process environment.
2. A project `.env` file the user has told you to read.
3. The MCP server's OAuth session, if you are calling through it.

If none of the above is set and you genuinely need a key, do not ask the user to paste it into the conversation. Instead, tell them to:

- Generate an API key from their Rize account settings at `https://app.rize.io`.
- Put it in `RIZE_API_KEY` in their shell, `.env`, or MCP client config — whichever matches how they invoke you.
- Resume the task once it is set.

This keeps the key out of your transcript, out of any logs the user shares, and out of the model provider's training data.

### How to use the key

Present it as a bearer token:

```http
POST /api/v1/graphql HTTP/1.1
Host: api.rize.io
Authorization: Bearer $RIZE_API_KEY
Content-Type: application/json

{"query": "{ me { id name email } }"}
```

Read it from the environment at the moment of the call. Do not copy it into variables you log, do not echo it back to the user, do not include it in commit messages, PR descriptions, error reports, or screenshots.

The key does not expire on its own. Treat a `401` on a previously-working key as revocation: drop it from memory and ask the user to refresh whichever source you read it from.

## OAuth 2.0 (MCP transport)

For MCP-based access, Rize uses OAuth 2.0:

- Authorization: `https://api.rize.io/oauth/authorize`
- Token: `https://api.rize.io/oauth/token`
- Scopes: `read`, `write`

Agents connecting via MCP should follow the standard OAuth 2.0 flow. The MCP server handles token management automatically.

### Errors

| Status | Meaning | What to do |
| --- | --- | --- |
| `401` on first use | Key is malformed, revoked, or missing. | Ask the user to confirm the value in their `RIZE_API_KEY` / config is current and active. |
| `401` on a previously-working key | Revoked or rotated. | Drop the cached value and ask the user to refresh it from their secret store, not from chat. |
| `403` | Key lacks permission for this resource. | Ask the user to verify their account has the required plan level or permissions. |
| `429` | Rate limited. | Back off and retry. Honor `Retry-After` if present. |

## Revocation

The user revokes API keys from their account settings at `https://app.rize.io`. You will discover revocation as a `401` on a previously-working credential — drop it and re-read from the same source you loaded it from.
