Getting started
Read this page as MarkdownIn this section: OAuth app
OAuth app
Register a client, send a user through consent, and call Miles on their behalf: the full OAuth 2.1 sequence, with every request and response.
Before you start
There is no app dashboard. Registration is Dynamic Client Registration (RFC 7591) against the MCP server's issuer, one request per client, and the client is public: no client secret is issued and none is accepted. What you register is what you get back; there is no console to edit it later, so re-register if a redirect URI changes.
Every token belongs to the Miles user who approved it, not to your app. Miles never sees a password; consent happens on askmiles.ai where the user's session already is.
1. Discover the issuer
Fetch the authorization server metadata once and read the endpoints from it rather than hardcoding them.
curl https://mcp.askmiles.ai/.well-known/oauth-authorization-serverThe document names registration_endpoint, authorization_endpoint, token_endpoint, revocation_endpoint, the supported scopes, and S256 as the only PKCE method.
2. Register the client
curl https://mcp.askmiles.ai/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "Trip planner",
"redirect_uris": ["https://example.com/oauth/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none",
"scope": "miles:read miles:chat"
}'The response repeats what you sent plus a client_id. Keep it; it is the only credential your app holds.
Redirect URIs must be https, except loopback http://127.0.0.1 and http://localhost for a native or command-line client. At most ten per client. client_name is what the consent screen shows, cut at 40 characters; a logo URI is ignored.
The registration endpoint is rate limited per IP, 20 requests a minute, and the body is capped. Register once and store the result.
3. Send the user to authorize
Generate a PKCE verifier and its S256 challenge, then open:
https://mcp.askmiles.ai/authorize
?response_type=code
&client_id=CLIENT_ID
&redirect_uri=https://example.com/oauth/callback
&scope=miles:read%20miles:chat
&code_challenge=CHALLENGE
&code_challenge_method=S256
&state=RANDOM
&resource=https://mcp.askmiles.ai/mcpThe user lands on a consent page at askmiles.ai listing exactly what your app will be able to see. Read access is on; miles:write is a separate toggle on that screen, off unless the user turns it on, and a token never carries it otherwise. On approval the browser returns to your redirect URI with code and your state.
resource (RFC 8707) names the server the token is for. Leave it at the MCP server URL. A request naming a different resource keeps only the scopes that server serves, and a request that keeps none is refused with invalid_scope rather than silently falling back to miles:read.
4. Exchange the code
curl https://mcp.askmiles.ai/token \
-d grant_type=authorization_code \
-d client_id=CLIENT_ID \
-d code=CODE \
-d redirect_uri=https://example.com/oauth/callback \
-d code_verifier=VERIFIER{
"access_token": "miles_at_…",
"refresh_token": "miles_rt_…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "miles:read miles:chat"
}Access tokens live one hour. Refresh tokens live thirty days and rotate: each refresh returns a new pair and retires the old refresh token. Every token is prefixed (miles_at_, miles_rt_, miles_ac_ for a code) so a leak is recognisable in a log.
5. Call Miles
With miles:read or miles:write, connect to the MCP server as a client and call tools; see the MCP overview. With miles:chat, call the Chat API exactly as a personal key would:
curl https://askmiles.ai/v1/chat/completions \
-H "Authorization: Bearer miles_at_…" \
-H "Content-Type: application/json" \
-d '{"model": "miles", "messages": [{"role": "user", "content": "Which of my cards earns most on dining?"}]}'6. Refresh and revoke
curl https://mcp.askmiles.ai/token \
-d grant_type=refresh_token \
-d client_id=CLIENT_ID \
-d refresh_token=miles_rt_…To end a grant from your side, post the token to the revocation endpoint. The user can end it from theirs at any time at Settings → Connected AI Apps, where your client_name appears with a Disconnect control; a paused account keeps its tokens but refuses every call with connections_paused until the user resumes.
Scopes you can request
| Scope | What it reaches | Default |
|---|---|---|
miles:read | Every read tool on the MCP server | Requested when you send no scope |
miles:write | The sixteen write tools; ten also need the user to be a Member | Off until the user toggles it on |
miles:chat | /v1/chat/completions and /v1/models | Off |
stub:read, stub:write, stub:suggest | Trips on Stub, a separate product that accepts Miles tokens | Off |
Other scopes exist for Miles' own apps and are refused to a registered client.