Exchange a code or refresh token for an access token
/oauth/token
Accepts `application/x-www-form-urlencoded` (RFC 6749) or `application/json`. Public clients authenticate with PKCE alone; confidential clients MUST present their secret, by HTTP Basic or `client_secret` in the body. `grant_type=authorization_code` requires `code`, `redirect_uri` and `code_verifier`. The redirect URI and the client must match those the code was issued to. `grant_type=refresh_token` requires `refresh_token`, and rotates it — the presented token is consumed and a new one returned. An optional `scope` may narrow the grant, never widen it; the grant row is the authority, not the copy on the presented token. Replay is treated as compromise, not as a plain error: presenting an authorization code or a refresh token twice REVOKES THE WHOLE GRANT (OAuth 2.1 §4.1.3 / §6.1), invalidating every token derived from it. The user must re-authorize from `GET /oauth/authorize`. Responses are `Cache-Control: no-store`. Rate limited per `client_id`.
Response Body
Bearer token for POST /mcp. Short-lived; re-check expires_in rather than assuming.
Access token lifetime in seconds.
Single-use — rotated on every refresh.
Space-delimited granted scopes.
Bearer
curl -X POST 'https://api.elaichi.ai/oauth/token' \
-H 'Content-Type: application/json'const response = await fetch('https://api.elaichi.ai/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
const data = await response.json();
console.log(data);import os
import requests
url = "https://api.elaichi.ai/oauth/token"
headers = {
"Content-Type": "application/json",
}
response = requests.post(url, headers=headers)
print(response.json())