# redPIM — Agent Authentication

How an AI agent obtains and uses credentials to call the redPIM agent surface
(MCP server `https://mcp.redpim.de/` and the REST endpoints under
`https://app.redpim.de/api/ai/`). This document follows the emerging `auth.md`
convention (see https://workos.com/auth-md).

## Discover

The agent surface is OAuth 2.1-protected. An unauthenticated request returns
`401 Unauthorized` with a `WWW-Authenticate` hint, and the MCP server publishes
**protected-resource metadata** (RFC 9728) that points to the authorization
server `https://app.redpim.de/`. Machine-readable API surface:
https://redpim.de/openapi.json · MCP manifest:
https://redpim.de/.well-known/mcp.json.

## Pick a method

- **Agent / MCP surface (live):** **OAuth 2.1** — `authorization_code` with PKCE
  (S256) and refresh tokens. This is the path for AI agents and MCP clients.
- **Interactive REST API:** an authenticated session cookie (`REDPim.Cookie`)
  established at login — used by the redPIM web app, not by headless agents.

## Register

Clients register **programmatically** via **Dynamic Client Registration**
(RFC 7591):

```bash
curl -X POST https://app.redpim.de/connect/register \
     -H "Content-Type: application/json" \
     -d '{"client_name":"my-agent","redirect_uris":["https://my-agent.example/callback"]}'
```

You receive `client_id` (and, for confidential clients, `client_secret`). MCP
clients such as Claude and ChatGPT perform this step automatically — no email,
no manual onboarding for the client.

## Claim

Complete the `authorization_code` + PKCE exchange against the authorization
server:

- Authorization endpoint: `https://app.redpim.de/connect/authorize`
- Token endpoint: `https://app.redpim.de/connect/token`
- Scopes: `mcp`, `api`, `offline_access`
- Resource (RFC 8707): `https://mcp.redpim.de/`

A **redPIM user logs in and authorizes the client** at the authorization
endpoint; the issued access token then acts on that user's single company.
The authorizing account must be a single-company, non-admin user. Access tokens
are short-lived (~5 minutes); use the refresh token to renew.

## Use the credential

Send the access token as a Bearer header:

```bash
curl -H "Authorization: Bearer $REDPIM_TOKEN" \
     https://app.redpim.de/api/ai/GetStats
```

Or connect an MCP client to `https://mcp.redpim.de/` (Streamable HTTP) — the
OAuth handshake runs as part of the connection.

## Agent authentication flow (summary)

The end-to-end **agent auth flow**:

1. **Discover** — call the resource, receive `401` + `WWW-Authenticate`; read the protected-resource metadata (RFC 9728) → authorization server.
2. **Register** — Dynamic Client Registration (RFC 7591) at `/connect/register` → `client_id` (+ `client_secret` for confidential clients).
3. **Authorize** — `authorization_code` + PKCE (S256) at `/connect/authorize`; a redPIM user logs in and consents.
4. **Token** — exchange the code at `/connect/token` for an access token (+ a refresh token when `offline_access` is requested).
5. **Call** — send the Bearer token to the MCP server or `api/ai/*`.
6. **Refresh & revoke** — renew with the refresh token; access is revocable in real time (see below).

## Grant types, scopes & token lifetimes

| Aspect | Value |
|--------|-------|
| Grant types | `authorization_code` (+ PKCE / S256), `refresh_token` |
| Client authentication | `none` (public clients, e.g. native MCP apps) or `client_secret_post` (confidential) |
| Scopes | `mcp`, `api`, `offline_access` |
| Access-token lifetime | ~5 minutes |
| Refresh | via `refresh_token` (requires the `offline_access` scope) |
| Resource indicator (RFC 8707) | `https://mcp.redpim.de/` |

## Machine-to-machine (M2M) / client credentials

redPIM **does not** offer the `client_credentials` grant (app-only / M2M) — **by
design**. Every access token is **delegated**: it represents a specific redPIM
user and acts only on that user's single company. There is no anonymous or
app-only data access, and no shared service account.

For automated and headless agent use, use the **delegated agent flow** described
above (`authorization_code` + PKCE via Dynamic Client Registration): the client
self-registers once, a redPIM user authorizes it, and the resulting
**refresh token** lets the agent operate continuously until access is revoked.
This keeps every action attributable to a real user and instantly revocable —
which a static M2M client secret could not guarantee.

## Errors

- `401 Unauthorized` — missing/expired/revoked credential. Re-authenticate;
  honour the `WWW-Authenticate` hint.
- `403 Forbidden` — token lacks the required scope, or the account is not
  permitted to use the agent surface (e.g. admin / multi-company accounts).
- `429 Too Many Requests` — back off and retry. (Dynamic Client Registration is
  rate-limited per IP.)

Error bodies are JSON: `{"error":"<message>"}`.

## Revocation

Access is revocable in real time. A redPIM user changing their password, or an
admin revoking AI access, invalidates the user's security stamp; in-flight
tokens are rejected within seconds (a denylist is also pushed to the MCP server).
Revoked credentials immediately return `401`. Obtaining a redPIM account itself
is part of onboarding — me@redcomponents.de.
