# Authentication

Your agent acts as you, with your permission. It signs in through OAuth: you approve the connection once in your browser, and your client keeps it working after that.

## How sign-in works

1. Your client calls `https://www.meetgravity.ai/api/mcp` without a token and gets `401 Unauthorized`. The response's `WWW-Authenticate` header points to Gravity's protected resource metadata.
2. The client reads that metadata, finds Gravity's authorization server, and registers itself.
3. Your browser opens Gravity's consent screen, signed in as you. You choose **Allow access**.
4. The client receives tokens and sends `Authorization: Bearer <access token>` with every request.

MCP clients that support authorization do all of this for you.

## Endpoints

| Document | URL |
| --- | --- |
| Protected resource metadata (RFC 9728) | `https://www.meetgravity.ai/.well-known/oauth-protected-resource/api/mcp` |
| Authorization server metadata (RFC 8414) | `https://www.meetgravity.ai/.well-known/oauth-authorization-server/api/oauth` |

| Property | Value |
| --- | --- |
| Issuer | `https://www.meetgravity.ai/api/oauth` |
| Resource (token audience) | `https://www.meetgravity.ai/api/mcp` |
| Grant types | `authorization_code`, `refresh_token` |
| PKCE | Required, `S256` only |
| `resource` parameter | Required when authorizing, and must equal the resource above |
| Client registration | Dynamic client registration. Native clients use loopback redirect URIs on `localhost`, `127.0.0.1`, or `[::1]`. |
| Access tokens | Opaque bearer tokens, valid for 1 hour, sent in the `Authorization` header |
| Refresh tokens | Issued with `offline_access`, valid until 90 days without use |
| `prompt` and `max_age` | `prompt=consent` is supported. `prompt=login`, `prompt=create`, `prompt=select_account`, and `max_age` aren't, because the connection uses your existing browser sign-in. |

## Permissions

| Scope | Required | What it allows |
| --- | --- | --- |
| `matching:manage` | Yes | Everything the tools do: reading your groups, rosters, goals, and matches, saving goals, and starting searches. |
| `offline_access` | No | Staying connected without signing in again every hour. |

There's no read-only connection yet. `matching:manage` covers reading and writing together, so a connected agent can save goals and start searches. Most MCP clients, including Claude Code, ask you before running a tool unless you've allowed it, so approve changes only when you meant to make them.

No permission lets an agent browse your Rolodex, see contact details for people found through other members, or contact anyone.

## The consent screen

The consent screen shows the app asking for access and the Gravity account you're signed in as, then lists what the connection allows. Choose **Allow access** to connect, or **Cancel** to refuse.

Only approve a connection you started yourself. The app name on the consent screen is the name the app gave itself.

## Staying connected

Access tokens last an hour. Your client refreshes them automatically, so you won't notice. If the refresh fails, for example after 90 days without use, your client asks you to sign in again.

Each request is checked on its own. Gravity confirms the token is active, was issued by Gravity for this server, carries `matching:manage`, and belongs to a current member. Your agent always acts as the account that approved it. Tool arguments can't change that.

## Disconnecting

- **Claude Code:** `claude mcp logout gravity` signs out. `claude mcp remove gravity` removes the server and its sign-in.
- **Codex and other clients:** remove the server or sign out in the client.

Signing out in a client deletes its tokens on that device. Gravity's revocation endpoint, `https://www.meetgravity.ai/api/oauth/oauth2/revoke`, revokes a token when the client calls it. You can't see or revoke connected agents from Gravity yet. A token that wasn't revoked stops working when it expires.

Leaving Gravity ends every agent's access immediately.

## Errors

| Response | Meaning | What to do |
| --- | --- | --- |
| `401` with `WWW-Authenticate` | No token, or the token expired or was revoked | Let your client refresh, or sign in again. |
| `403` with `error="insufficient_scope"` | The token doesn't include `matching:manage` | Sign in again and approve the connection. |
| `503` | Gravity's sign-in service is temporarily unavailable | Try again later. |
