OAuth2 endpoints
Moymo implements OAuth 2.0 (RFC 6749) with PKCE (RFC 7636) and token revocation (RFC 7009). The OAuth2 guide walks through it; this page is the reference.
| Authorisation | https://moymo.net/oauth2/authorize (a page, for the member's browser) |
| Token | POST https://moymo.net/api/v1/oauth2/token |
| Revoke | POST https://moymo.net/api/v1/oauth2/revoke |
| Supported grants | authorization_code, refresh_token |
| Supported response type | code |
| PKCE | S256 only |
| Token type | Bearer |
Authorisation request
GET https://moymo.net/oauth2/authorize
| Parameter | Required | |
|---|---|---|
client_id | yes | The application's id. |
redirect_uri | when there is not exactly one registered, unless the link only adds a bot | One of the registered addresses, compared exactly. A loopback address (http://localhost, http://127.0.0.1, http://[::1]) may use any port. |
response_type | no | code. |
scope | yes | Space-, +- or comma-separated scopes. |
state | recommended | Returned unchanged. |
code_challenge | for apps with no secret | The unpadded base64url SHA-256 of the verifier: 43 characters. |
code_challenge_method | with a challenge | S256. |
permissions | no | With bot: the sum of the requested permission bits. |
server_id | no | With bot: preselects a server. |
An authorisation link (on one line; broken here to be read)Text
text
https://moymo.net/oauth2/authorize
?client_id=0f6c1a52-3b9e-4c1c-9d1b-6e7d2a8f4b10
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
&response_type=code
&scope=identify+servers
&state=Zx3k9Qe1
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256Success: the browser is sent to redirect_uri?code=...&state=... (with server_id=... for a bot). Refusal or error: redirect_uri?error=...&error_description=...&state=....
A request that names no such application, or an address the application did not register, is answered on Moymo's page with an error and never redirected.
error | When |
|---|---|
access_denied | The member said no; the application is suspended; it is a draft or private and the member is not its owner or a tester; the bot cannot be added. |
invalid_scope | A scope that does not exist, is not available yet, or is first-party only; or bot for an application with no bot. |
invalid_request | A malformed challenge; plain PKCE; a missing required parameter. |
unsupported_response_type | response_type other than code. |
Token request
POST https://moymo.net/api/v1/oauth2/token, Content-Type: application/x-www-form-urlencoded
Client authentication: client_id and client_secret in the body, or HTTP Basic with client_id:client_secret (each part form-encoded). A public client (no secret) sends client_id only and has to use PKCE.
grant_type=authorization_code
| Parameter | |
|---|---|
code | The code from the redirect. One use, 5 minutes. |
redirect_uri | The same address the code was issued for. |
code_verifier | The PKCE verifier, if the code was issued with a challenge. |
grant_type=refresh_token
| Parameter | |
|---|---|
refresh_token | The refresh token. It works once. |
Example
The answer is not cacheable (Cache-Control: no-store). Access tokens last 3600 seconds, refresh tokens 30 days.
RequestPOST
/api/v1/oauth2/token bash
curl -X POST https://moymo.net/api/v1/oauth2/token \
-d grant_type=authorization_code \
-d code="$CODE" \
-d redirect_uri=https://example.com/callback \
-d code_verifier="$CODE_VERIFIER" \
-d client_id="$CLIENT_ID" \
-d client_secret="$CLIENT_SECRET"js
const response = await fetch('https://moymo.net/api/v1/oauth2/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: 'https://example.com/callback',
code_verifier: codeVerifier,
client_id: clientId,
client_secret: clientSecret
})
})
const tokens = await response.json()python
import requests
response = requests.post(
"https://moymo.net/api/v1/oauth2/token",
data={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": "https://example.com/callback",
"code_verifier": code_verifier,
"client_id": client_id,
"client_secret": client_secret,
},
)
tokens = response.json()Response200OKJSON
json
{
"access_token": "moymo_at_3kQ9vXn2LmT7pYw4RcB8dJ1hZfE5sUa6GoN0iVxKq2M",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "moymo_rt_7Hn4WbZ2eXk9QpLr6TcY1vJ8aMfD3sUoG5iNyKx0Rt",
"scope": "identify servers"
}To get a new access token, send the refresh token. It works once: the answer carries a new one.
RequestPOST
/api/v1/oauth2/token Shellbash
curl -X POST https://moymo.net/api/v1/oauth2/token \
-d grant_type=refresh_token \
-d refresh_token="$REFRESH_TOKEN" \
-d client_id="$CLIENT_ID" \
-d client_secret="$CLIENT_SECRET"Revoke
POST https://moymo.net/api/v1/oauth2/revoke, form-encoded, with client authentication as above.
| Parameter | |
|---|---|
token | An access token or a refresh token of this application. |
Answers 200 whether or not the token existed, as the standard asks. A token belonging to another application is not revoked.
Errors
At the token and revoke endpoints, errors are the standard's: {"error": "...", "error_description": "..."} with these statuses.
Response400Bad RequestJSON
json
{
"error": "invalid_grant",
"error_description": "That code is not valid any more."
}The error_description is a sentence for the person reading the log; branch on error.
| Status | error | When |
|---|---|---|
| 400 | invalid_request | A required parameter is missing. |
| 400 | invalid_grant | The code is expired, already used (this also revokes the tokens it made), was issued to another application or redirect address, or the verifier does not match; or the refresh token is not valid, was used, or belongs to another application. |
| 400 | unsupported_grant_type | Not authorization_code or refresh_token. |
| 401 | invalid_client | Unknown application, wrong secret, a suspended application, or malformed Basic credentials. Comes with WWW-Authenticate: Basic realm="moymo". |
Notes
- CORS is open for the token and revoke endpoints (no credentials are ever sent), so a browser app can call them.
- Token and revoke are rate limited per address; see Rate limits.
- Redirect addresses allowed:
https://...,http://localhost,http://127.0.0.1,http://[::1], and a native app's reversed-domain scheme such ascom.example.app:/callback. Not allowed: wildcards, fragments, credentials in the address.