# Credicorp Hub — Agent / Partner API access (`auth.md`)

The Credicorp Hub exposes an **authenticated, read-only** Model Context Protocol (MCP) tier for
staff- and owner-tier agents. Access is via OAuth 2.0 **client credentials** — there is no end-user
login; a registered confidential client exchanges its `client_id` + `client_secret` for a
short-lived (5-minute) bearer token.

> **Read-only by contract.** Every tool on this tier is a pure read. There is no write, no money
> movement, no decisioning override. The token audience is `hub-partner`, which is structurally
> rejected by the hub's internal write plane.

## Endpoints

| Purpose | Method + URL |
|---|---|
| Authorization-server metadata (RFC 8414) | `GET https://hub.credicorp.co.uk/.well-known/oauth-authorization-server` |
| Protected-resource metadata (RFC 9728) | `GET https://hub.credicorp.co.uk/.well-known/oauth-protected-resource` |
| JWKS (token verification key, RFC 7517) | `GET https://hub.credicorp.co.uk/partner/v1/oauth/jwks` |
| Token endpoint (client_credentials) | `POST https://hub.credicorp.co.uk/partner/v1/oauth/token` |
| Token introspection (RFC 7662) | `POST https://hub.credicorp.co.uk/partner/v1/oauth/introspect` |
| Authenticated MCP (JSON-RPC 2.0) | `POST https://hub.credicorp.co.uk/partner/v1/mcp` |

## Getting a client

Clients are provisioned by the Credicorp operator out-of-band (the registry is environment/DB-backed;
secrets are stored **hashed**, never in source control). To request a client, contact the operator
with the agent name and the **least** scope tier you need. You will receive a `client_id` and a
one-time `client_secret`.

## Requesting a token

```
POST https://hub.credicorp.co.uk/partner/v1/oauth/token
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&scope=mcp.read ops.read
```

The `scope` parameter is optional — omit it for your client's full grant, or pass a space-delimited
subset for least privilege. The response:

```
{ "access_token": "<EdDSA JWS>", "token_type": "Bearer", "expires_in": 300, "scope": "mcp.read ops.read" }
```

Call the MCP tier with `Authorization: Bearer <access_token>`. Tokens last 5 minutes; re-request on
demand (there is no refresh token in the client_credentials flow).

## Scopes (READ-ONLY)

| Scope | What it grants |
|---|---|
| `mcp.read` | Floor scope. List/initialise the authed MCP and call the non-PII data tools (ops aggregate, deterministic decision explanation, platform metrics, config snapshot). |
| `account.read` | PII reads — customer / application / loan summaries. Staff-tier; every call is written to the audit chain. |
| `ops.read` | Operational queue depth + health aggregate counts (non-PII). |
| `owner.read` | Owner-tier reads — platform-wide metrics, portfolio overview, config snapshot. The strongest standing partner grant. |

A token may never carry a write scope; the token endpoint refuses to mint one and the resource
verifies the read-only allow-list again before dispatch.

## Errors

`401 invalid_client` — bad/missing client credentials. `400 invalid_scope` — a requested scope is
unknown or not permitted for your client. `403 insufficient_scope` — the tool you called needs a
scope your token does not carry (see the `WWW-Authenticate` header). `503` — the token service is
temporarily unavailable (retry).