> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vin.gs/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Bearer tokens, personal access tokens, OAuth discovery, and Vings scopes.

All `/api/v1/*` routes and `POST /api/mcp` require an `Authorization` header:

```http theme={null}
Authorization: Bearer <token>
```

The service validates the token and only returns data for the authenticated Vings user.

## Token types

### OAuth access tokens

User access tokens from the Vings OAuth flow or from a signed-in Vings session (for example, your app after the user signs in). Use the token value in the `Authorization` header.

### Vings personal access tokens (PAT)

Tokens prefixed with `vng_pat_`. Create and manage them in your Vings account settings. PATs include explicit Vings scopes and only access your data. Send the token in the `Authorization` header the same way as an OAuth access token.

Cookie-based auth across subdomains is **not** supported on this API in v1.

## OAuth protected-resource metadata

MCP and REST clients that support RFC 9728 discovery can read:

| URL                                                 | Resource          |
| --------------------------------------------------- | ----------------- |
| `GET /.well-known/oauth-protected-resource`         | MCP at `/api/mcp` |
| `GET /.well-known/oauth-protected-resource/mcp`     | MCP at `/api/mcp` |
| `GET /api/.well-known/oauth-protected-resource`     | REST API          |
| `GET /api/.well-known/oauth-protected-resource/mcp` | MCP at `/api/mcp` |

The metadata includes `authorization_servers` pointing at the external host (`https://external.vin.gs`), which publishes authorization-server discovery for sign-in, consent, and ChatGPT refresh tokens.

## Authorization-server metadata (refresh tokens)

ChatGPT and other MCP clients discover refresh-token support from the **authorization server**, not protected-resource metadata:

| URL                                           | Purpose                                                   |
| --------------------------------------------- | --------------------------------------------------------- |
| `GET /.well-known/oauth-authorization-server` | OAuth AS metadata with `offline_access`                   |
| `GET /.well-known/openid-configuration`       | OIDC discovery (same fields)                              |
| `GET /api/oauth/authorize`                    | Authorize proxy (strips `offline_access` before Supabase) |

`scopes_supported` on these documents includes `openid`, `email`, `profile`, and `offline_access`. Supabase still issues access and refresh tokens at `token_endpoint`; the proxy only adjusts the authorize redirect because Supabase rejects `offline_access` as an authorize scope today.

Protected-resource metadata and `WWW-Authenticate` challenges intentionally **omit** `offline_access` (per MCP SEP-2207).

After deploying discovery changes, **delete and recreate** your ChatGPT connector so it refetches metadata ([OpenAI help article](https://help.openai.com/en/articles/12584461-developer-mode-apps-and-full-mcp-connectors-in-chatgpt-beta)).

Unauthenticated `POST /api/mcp` requests return **401** with a `WWW-Authenticate` challenge pointing at the host-root MCP metadata URL.

**At Supabase authorize time**, clients (including ChatGPT) must request only standard OIDC scopes: `openid`, `email`, and `profile`. Protected-resource metadata, `WWW-Authenticate` challenges, and per-tool MCP `securitySchemes` from `tools/list` all advertise those OIDC scopes. Do **not** send Vings data scopes (for example `wallets:read`) in the authorize `scope` parameter — Supabase rejects them with `invalid_request`.

**Vings data scopes** are stored on the OAuth client when you create it in Vings settings and shown on the consent screen at [`/oauth/consent`](https://www.vin.gs/oauth/consent). After the user approves, scopes are saved in `external_authorization_grants` and enforced on REST routes and MCP tools by resolving the OAuth token's `client_id` claim to that grant.

## Vings scopes

For OAuth access tokens, the external API loads granted Vings scopes from the user's consent record (keyed by JWT `client_id`). If the token also includes `vings_scopes`, `scope`, or `scopes` claims with Vings values, enforcement uses the intersection of JWT claims and the consent grant. PATs always include scoped access directly on the token.

| Scope               | Access                 |
| ------------------- | ---------------------- |
| `profile:read`      | User profile           |
| `transactions:read` | Transactions           |
| `cashflow:read`     | Cashflow summaries     |
| `spending:read`     | Spending aggregates    |
| `budgets:read`      | Budgets                |
| `banks:read`        | Connected banks status |
| `wallets:read`      | Wallet-related data    |
| `portfolio:read`    | Portfolio              |
| `preferences:read`  | Preferences            |

## OpenAPI security

The live OpenAPI document defines `bearerAuth` (`http` + `bearer`). Use the API Reference playground: enter your token in the auth control, then call `GET /v1/me` to verify.

## Security practices

* Do not send tokens in query strings or logs.
* Financial responses are not cached (`Cache-Control: no-store`).
* Per-user rate limits apply to REST and MCP; transaction search and portfolio endpoints have stricter limits than aggregate routes.
* This API exposes only user-scoped read access—no admin or service credentials.
