# Authenticating with MakeAIVideo

How an AI agent gets credentials to act for a MakeAIVideo user. Every path ends with a real, signed-in user approving the agent. Agents cannot create accounts. A new user signs up at https://app.makeaivideo.ai/signup first.

## Discover

- Authorization server metadata: https://app.makeaivideo.ai/.well-known/oauth-authorization-server (mirrored at https://makeaivideo.ai/.well-known/oauth-authorization-server)
- Protected resource metadata (MCP server): https://mcp.makeaivideo.ai/.well-known/oauth-protected-resource
- Issuer: `https://app.makeaivideo.ai`
- Scopes: `read`, `write`, `ai`

Pick one path:

| You are | Use |
|---|---|
| An MCP client with a browser redirect (Claude, ChatGPT, Cursor) | 1. OAuth authorization code + PKCE |
| A headless agent, CLI or script with no redirect URI | 2. Device authorization grant |
| An agent that knows the user's email | 3. auth.md service_auth |
| Server-side code the user configures | 4. API key |

Every path returns the same credential: a `mav_` bearer token that works on the hosted MCP server and the REST API, and shows up in the user's Settings, Advanced, API keys, where they can revoke it.

## 1. OAuth authorization code + PKCE

1. Register: `POST https://app.makeaivideo.ai/api/oauth/register` with JSON `{"client_name": "...", "redirect_uris": ["..."]}`. Returns a `client_id`. Public clients only, no secret.
2. Send the user to `https://app.makeaivideo.ai/api/oauth/authorize` with `response_type=code`, `client_id`, `redirect_uri`, `code_challenge` and `code_challenge_method=S256`.
3. Exchange the code at `POST https://app.makeaivideo.ai/api/oauth/token` with `grant_type=authorization_code`, `code`, `redirect_uri`, `client_id` and `code_verifier`.

An unauthenticated request to `https://mcp.makeaivideo.ai` returns `401` with `WWW-Authenticate: Bearer resource_metadata="..."`. Most MCP clients run this flow for you.

## 2. Device authorization grant (RFC 8628)

1. `POST https://app.makeaivideo.ai/api/oauth/device_authorization` (form or JSON). `client_name` is optional and is shown to the user on the approval page. `client_id` is optional; if sent, the code is bound to it. To register a device-only client, call the register endpoint with `"grant_types": ["urn:ietf:params:oauth:grant-type:device_code"]` and no `redirect_uris`.
2. The response has `device_code`, `user_code`, `verification_uri`, `verification_uri_complete`, `expires_in` (600) and `interval` (5).
3. Show the user `user_code` and `verification_uri` (https://app.makeaivideo.ai/device). They sign in, check which app is asking, and enter the code.
4. Poll `POST https://app.makeaivideo.ai/api/oauth/token` with `grant_type=urn:ietf:params:oauth:grant-type:device_code` and `device_code`, no faster than `interval` seconds.
   - `authorization_pending`: keep polling.
   - `slow_down`: wait longer between polls.
   - `expired_token`: start again.
   - `access_denied`: the user declined.
   - `invalid_grant`: unknown or already-used code.
5. On success: `{"access_token": "mav_...", "token_type": "Bearer", "expires_in": ..., "scope": "read write ai"}`.

## 3. auth.md service_auth (verified email)

1. Register: `POST https://app.makeaivideo.ai/agent/identity` with JSON `{"type": "service_auth", "login_hint": "user@example.com", "client_name": "..."}`. The response includes:
   - `claim_token`: starts `clm_`, shown once; keep it secret.
   - `claim_token_expires`: 24 hours.
   - `claim`: `user_code`, `verification_uri`, `expires_in` (600) and `interval` (5).
2. Tell the user to sign in at https://app.makeaivideo.ai/device **as the email you gave** and type the `user_code`. Approval is refused from any other account.
3. Poll `POST https://app.makeaivideo.ai/api/oauth/token` with `grant_type=urn:workos:agent-auth:grant-type:claim` and `claim_token`. The errors are the same as in path 2, and so is the success response.
4. If the `user_code` expires while the claim token is still valid, `POST https://app.makeaivideo.ai/agent/identity/claim` with `{"claim_token": "..."}` returns a fresh `user_code`. Its errors are `invalid_claim_token`, `claimed_or_in_flight` (409) and `claim_expired` (410).

`type: "anonymous"` returns `anonymous_not_enabled` and `type: "identity_assertion"` returns `issuer_not_enabled`. Only `service_auth` is supported.

## 4. API key

The user creates a key under Settings, Advanced, API keys (https://app.makeaivideo.ai/settings/advanced). Keys start with `mav_`. Headless setup: `export MAKEAIVIDEO_API_KEY=mav_...`. The CLI can also fetch one with `npx @makeaivideo/cli login`.

## Use

Send `Authorization: Bearer mav_...` to:
- the hosted MCP server at `https://mcp.makeaivideo.ai`;
- the REST API at `https://app.makeaivideo.ai/api/v1` (see https://makeaivideo.ai/openapi.json).

A request without the scope it needs returns `403`.

## Revoke

- The agent signs itself out with `POST https://app.makeaivideo.ai/api/oauth/revoke` and `token=mav_...` (RFC 7009). It always answers `200`.
- The user can revoke any key under Settings, Advanced, API keys.
- A revoked token gets `401`, and the agent must start a new authorization.

## Billing

Video creation spends the user's credits. Call `estimate_video_cost` (MCP) or `makeaivideo estimate` (CLI) first. Plans and prices are at https://makeaivideo.ai/pricing.json.

## More

- Docs: https://makeaivideo.ai/docs/authentication
- MCP server card: https://makeaivideo.ai/.well-known/mcp/server-card.json
- Agent skill: https://makeaivideo.ai/.well-known/agent-skills/index.json
