# auth.md

How an AI agent authenticates to PgBeam. PgBeam gives an agent a scoped Postgres login and a hosted MCP endpoint, both guarded by policy (read-only enforcement, table allowlists, PII masking, query budgets, kill-switch) with a full audit trail.

There are two distinct credential paths. Pick the one that matches who you are.

## 1. Agent credentials (`pba_`): the machine path

This is the credential an agent presents on every request. It is an opaque bearer token issued per agent, scoped to one project, revocable, and kill-switchable. It is **not** obtained through a browser OAuth flow.

This block is also published, as JSON, inside the `/.well-known/oauth-authorization-server` document (the `agent_auth` key), and the resource it protects is described by [`/.well-known/oauth-protected-resource`](https://pgbeam.com/.well-known/oauth-protected-resource) (RFC 9728).

```yaml
agent_auth:
  skill: https://pgbeam.com/.well-known/agent-skills/index.json
  docs: https://pgbeam.com/auth.md
  protected_resource: https://pgbeam.com/.well-known/oauth-protected-resource
  # A credential can represent an autonomous agent or a human operator.
  identity_types_supported: [agent, human]
  # One registration yields two coupled secrets:
  #   bearer        is the pba_ MCP token (Authorization: Bearer).
  #   scram-sha-256 is the scoped Postgres login (SCRAM wire auth).
  credential_types_supported: [bearer, scram-sha-256]
  credential_prefix: pba_
  # Provision a new agent identity (returns the pba_ token + scoped Postgres DSN, once).
  register_uri: https://api.pgbeam.com/v1/projects/{project_id}/agents
  register_method: POST
  register_auth:
    type: http
    scheme: bearer
    # Authenticate the registration call with an organization API key (pbo_…)
    # created in the dashboard at https://dash.pgbeam.com.
    credential_prefix: pbo_
  # Lifecycle.
  rotation_uri: https://api.pgbeam.com/v1/projects/{project_id}/agents/{agent_id}/rotate
  rotation_method: POST
  # Reversible kill-switch (PATCH status=disabled). DELETE revokes permanently.
  kill_switch_uri: https://api.pgbeam.com/v1/projects/{project_id}/agents/{agent_id}
  kill_switch_method: PATCH
  revocation_uri: https://api.pgbeam.com/v1/projects/{project_id}/agents/{agent_id}
  revocation_method: DELETE
```

### Register an agent

The agents endpoints ship behind the `agent-gateway` feature flag. The registration call is authenticated with an **organization API key** (`pbo_…`) that a human creates in the dashboard. Registration can create resources, so do not probe it during passive discovery.

`name` and `policy_profile_id` are required; `principal_type` defaults to `agent` (set `human` for a human operator) and an optional `expires_at` makes the credential self-expire.

```http
POST https://api.pgbeam.com/v1/projects/{project_id}/agents
Authorization: Bearer pbo_<organization-api-key>
Content-Type: application/json

{ "name": "my-agent", "policy_profile_id": "pol_…", "principal_type": "agent" }
```

The `201` response returns the secrets **once** (they cannot be retrieved again):

- `mcp_token`: the `pba_…` bearer token.
- `mcp_url`: the hosted MCP endpoint, `https://{project}.proxy.pgbeam.app/mcp`.
- `connection_string`: a scoped Postgres login (the proxy authenticates it with SCRAM-SHA-256) for direct wire access.

### Use the credential

PgBeam issues **two coupled credential types** from that one registration:

- **`pba_` bearer (MCP).** Present it as a bearer token to the hosted MCP endpoint:

  ```http
  POST https://{project}.proxy.pgbeam.app/mcp
  Authorization: Bearer pba_<agent-token>
  ```

- **SCRAM Postgres login (wire).** The `connection_string` is a scoped Postgres user the proxy authenticates with SCRAM-SHA-256 for direct SQL over the Postgres wire protocol.

Both are guarded by the same policy profile. Policy errors surface verbatim and are written to be LLM-readable so an agent can correct itself.

### Rotate / disable / revoke

- **Rotate:** `POST https://api.pgbeam.com/v1/projects/{project_id}/agents/{agent_id}/rotate` issues a new password and MCP token in place (same id and policy); live connections on the old secret drop within seconds.
- **Kill-switch (disable):** `PATCH https://api.pgbeam.com/v1/projects/{project_id}/agents/{agent_id}` with `{ "status": "disabled" }` reversibly suspends the credential; re-enable with `{ "status": "active" }`.
- **Revoke:** `DELETE https://api.pgbeam.com/v1/projects/{project_id}/agents/{agent_id}` permanently removes the credential and drops live connections.

## 2. OAuth 2.0 / OIDC: the human / interactive path

PgBeam runs a standards-based OAuth 2.0 Authorization Server (Better Auth) for interactive sign-in and for OAuth/MCP clients that perform an authorization-code flow with PKCE. Discover it via:

- Authorization Server metadata (RFC 8414): <https://pgbeam.com/.well-known/oauth-authorization-server>
- OpenID Connect Discovery alias: <https://pgbeam.com/.well-known/openid-configuration>
- Protected Resource metadata (RFC 9728): <https://pgbeam.com/.well-known/oauth-protected-resource>

Key facts from that metadata:

- **issuer:** `https://dash.pgbeam.com/api/auth`
- **authorization_endpoint:** `https://dash.pgbeam.com/api/auth/mcp/authorize`
- **token_endpoint:** `https://dash.pgbeam.com/api/auth/mcp/token`
- **jwks_uri:** `https://dash.pgbeam.com/api/auth/jwks`, the same key set the REST API (`https://api.pgbeam.com`) uses to verify JWTs.
- **registration_endpoint:** `https://dash.pgbeam.com/api/auth/mcp/register`, Dynamic Client Registration (RFC 7591) for OAuth **client apps**. This is for registering an OAuth client, not for minting agent identities; use the `pba_` path above for that.
- **grant_types:** `authorization_code`, `refresh_token`; PKCE `S256` required.
- **scopes:** `openid`, `profile`, `email`, `offline_access`.

Interactive users sign in at <https://dash.pgbeam.com> (email/password, social, passkeys, 2FA, and OIDC/SAML SSO on eligible plans).

## Which one do I use?

- You are an **autonomous agent** acting on a database → use a `pba_` agent credential (section 1).
- You are an **OAuth/MCP client** doing an interactive authorization-code flow on behalf of a human → use the OAuth server (section 2).
- You are calling the **REST API** (`https://api.pgbeam.com`) → pass a Better Auth JWT or an API key (`pbo_` org key) as `Authorization: Bearer <token>`. JWTs are verified against the `jwks_uri` above.

## Notes

- Always use official PgBeam domains: `pgbeam.com` (docs/discovery), `dash.pgbeam.com` (auth), `api.pgbeam.com` (REST API), `*.proxy.pgbeam.app` (MCP + Postgres wire).
- Never send a credential to any other host.
- Re-read this document periodically; treat the remote URL as the source of truth.
