[view as .md]

OAuth reference

modelux runs an OAuth 2.1 authorization server that issues tokens to MCP clients (Claude Desktop, Claude Code, ChatGPT, Cursor, and anything that speaks the MCP authorization spec). You do not need to call these endpoints by hand — your MCP client discovers and drives them automatically after you paste https://api.modelux.ai/api/mcp as the server URL. This page documents the surface for client developers and for anyone debugging a connection.

For the end-user setup walkthrough, see Connecting your AI (MCP).

Metadata

GET /.well-known/oauth-protected-resource

RFC 9728. Tells clients which authorization server mints tokens for /api/mcp.

{
  "resource": "https://api.modelux.ai/api/mcp",
  "authorization_servers": ["https://api.modelux.ai"],
  "scopes_supported": ["mcp:read", "mcp:write"],
  "bearer_methods_supported": ["header"]
}

GET /.well-known/oauth-authorization-server

RFC 8414. Advertises the authorization server’s endpoints and capabilities.

Highlights: code_challenge_methods_supported: ["S256"] (PKCE is required, plain is rejected), token_endpoint_auth_methods_supported: ["none"] (all clients are public), grant_types_supported: ["authorization_code", "refresh_token"].

Endpoints

POST /api/oauth/register — Dynamic Client Registration

RFC 7591. Register a new public client. JSON body; returns a client_id you use on subsequent authorize / token calls. Clients are public (no client_secret) and must use PKCE.

curl -sS https://api.modelux.ai/api/oauth/register \
  -H 'content-type: application/json' \
  -d '{
    "client_name": "My MCP Client",
    "redirect_uris": ["http://127.0.0.1:8787/callback"]
  }'

Redirect URIs must be HTTPS, except http://localhost and http://127.0.0.1 for loopback clients. Fragments are rejected.

GET /api/oauth/authorize — Authorization

User-facing browser endpoint. Your MCP client opens this URL with:

ParamRequiredNotes
client_idyesfrom /register (or a pre-registered slug)
redirect_uriyesmust exact-match a URI registered for the client
response_typeyesmust be code
code_challengeyesPKCE RFC 7636
code_challenge_methodyesmust be S256
scopeyesspace-separated subset of mcp:read mcp:write
staterecommendedechoed back on redirect
resourceyesmust be https://api.modelux.ai/api/mcp (RFC 8707)

Unauthenticated users are bounced to /login and returned here after sign-in. After consent, the browser is redirected to <redirect_uri>?code=<code>&state=<state>.

POST /api/oauth/token

Form-encoded body. Two grants:

authorization_code — exchange a code + PKCE verifier for an access token and refresh token.

curl -sS https://api.modelux.ai/api/oauth/token \
  -H 'content-type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code' \
  -d 'code=mlx_oac_...' \
  -d 'client_id=<your-client-id>' \
  -d 'redirect_uri=http://127.0.0.1:8787/callback' \
  -d 'code_verifier=<pkce-verifier>' \
  -d 'resource=https://api.modelux.ai/api/mcp'

refresh_token — rotate a refresh token.

curl -sS https://api.modelux.ai/api/oauth/token \
  -H 'content-type: application/x-www-form-urlencoded' \
  -d 'grant_type=refresh_token' \
  -d 'refresh_token=mlx_ort_...' \
  -d 'client_id=<your-client-id>'

Response:

{
  "access_token": "mlx_oat_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "mlx_ort_...",
  "scope": "mcp:read mcp:write"
}

Refresh tokens rotate on every use. Presenting a rotated (already-replaced) refresh token revokes the whole chain and returns invalid_grant — treat that as “re-run the authorize flow.”

POST /api/oauth/revoke

RFC 7009. Revoke either an access or refresh token. Unknown tokens return 200 per spec.

curl -sS -X POST https://api.modelux.ai/api/oauth/revoke \
  -H 'content-type: application/x-www-form-urlencoded' \
  -d 'token=mlx_oat_...'

Using a token against MCP

Every MCP JSON-RPC call presents the access token as a bearer:

POST /api/mcp
Authorization: Bearer mlx_oat_...

/api/mcp validates the audience (resource) binding, checks the token hasn’t expired or been revoked, and verifies the token owner is still a member of their org. Failures return 401 with a WWW-Authenticate header pointing at /.well-known/oauth-protected-resource so spec-compliant clients restart the auth dance without user intervention.

Token lifetimes

TokenTTLNotes
Authorization code10 minsingle-use
Access token1 hopaque, not JWT; revoke is instant
Refresh token30 drotates on every use; reuse detection revokes the chain

Scopes

  • mcp:read — list / get / describe tools only.
  • mcp:write — required for any mutating tool (create, update, delete, revoke, …).

Scope narrows the token; the underlying dashboard role still gates the action. A user whose dashboard role is viewer cannot escalate by requesting mcp:write.