moymo,Docs
Skip to content
Continue with Moymo

OAuth2 guide: Continue with Moymo ​

Moymo is an OAuth 2.0 authorization server. Your application can send a member to Moymo, they decide what to share, and your application gets a token it can use for exactly that.

The Developer Portal itself signs you in this way: it is the first application to use the flow described here.

When to use it ​

  • Sign in to your site or app with Moymo. Ask for identify and you get the member's id, username, display name and picture.
  • Read something about the member that they agree to share: their e-mail (email), the servers they are in (servers).
  • Add your bot to a server they manage (bot). This is how a bot is installed.

The scopes are listed in Scopes.

The flow ​

It is the standard authorization code flow, with PKCE.

The six stepsText
text
 your app                     member's browser                      Moymo
    |  1. send to /oauth2/authorize ---------------------------------->|
    |                                  2. member signs in, reads the   |
    |                                     consent screen, says yes     |
    |<--- 3. redirect to your redirect_uri?code=...&state=... --------|
    |  4. POST /api/v1/oauth2/token  (code, verifier or secret) ------>|
    |<--- 5. access token + refresh token ----------------------------|
    |  6. GET /api/app/v1/users/@me  (Authorization: Bearer ...) ----->|

1. Register ​

In the Developer Portal, on your application's OAuth2 tab:

  • note the client id;
  • add every redirect address you will use. A redirect has to be exact, character for character. Allowed: https://...; http://localhost, http://127.0.0.1 or http://[::1] with any port (for development); or a native app's own scheme like com.example.app:/callback (a reversed domain, as RFC 8252 asks). No wildcards, no #fragment, no password in the address;
  • if your code runs on a server that can keep a secret, make a client secret. If it runs in a browser or on a phone, you use PKCE and have no secret.

2. Send the member to Moymo ​

The link to send the member to (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%20servers
  &state=9d3a7c...
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
Parameter
client_idYour application's id.
redirect_uriOne of the addresses you registered. May be left out if you registered exactly one.
response_typecode.
scopeThe scopes you want, separated by spaces (or +, or commas). Only scopes that exist.
stateA random value of yours. It comes back unchanged; check it: it is what stops somebody else's authorisation from being delivered to your session.
code_challenge, code_challenge_methodPKCE. S256 only. See below.

The member sees your application's name, picture and summary, who made it, its verified domain, and each scope in plain words, and chooses Authorise or Cancel. If they are not signed in to Moymo they sign in first and come back.

Drafts

A draft application can be authorised by its owner and its testers only. Anyone else gets access_denied. See Publishing.

3. Receive the code ​

Moymo sends the member's browser to your redirect address:

Where the member's browser landsText
text
https://example.com/callback?code=Qp2hY...&state=9d3a7c...

or, if they said no, with error=access_denied and the same state. A code works once, for 5 minutes, for this redirect address and no other.

4. Trade it for tokens ​

From your server (or, with PKCE and no secret, from your app):

RequestPOST/api/v1/oauth2/token
bash
curl https://moymo.net/api/v1/oauth2/token \
  -d grant_type=authorization_code \
  -d code=Qp2hY... \
  -d redirect_uri=https://example.com/callback \
  -d client_id=0f6c1a52-3b9e-4c1c-9d1b-6e7d2a8f4b10 \
  -d client_secret=$MOYMO_CLIENT_SECRET \
  -d code_verifier=$VERIFIER
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',
    client_id: '0f6c1a52-3b9e-4c1c-9d1b-6e7d2a8f4b10',
    client_secret: process.env.MOYMO_CLIENT_SECRET,
    code_verifier: verifier
  })
})
const tokens = await response.json()
python
import os
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",
        "client_id": "0f6c1a52-3b9e-4c1c-9d1b-6e7d2a8f4b10",
        "client_secret": os.environ["MOYMO_CLIENT_SECRET"],
        "code_verifier": verifier,
    },
)
tokens = response.json()

Either the client secret or the PKCE verifier has to prove the exchange; a code that was issued with a challenge needs the matching verifier, and a code issued without one needs the secret. You can send credentials in the body as above, or as HTTP Basic (client_id:client_secret, each form-encoded).

Response200OKJSON
json
{
  "access_token": "moymo_at_9x3...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "moymo_rt_Hk8...",
  "scope": "identify servers"
}

5. Call the API ​

RequestGET/users/@meShell
bash
curl https://moymo.net/api/app/v1/users/@me \
  -H "Authorization: Bearer moymo_at_9x3..."

6. Refresh ​

An access token lasts 1 hour. When it expires, trade the refresh token for a new pair:

RequestPOST/api/v1/oauth2/tokenShell
bash
curl https://moymo.net/api/v1/oauth2/token \
  -d grant_type=refresh_token \
  -d refresh_token=moymo_rt_Hk8... \
  -d client_id=0f6c1a52-3b9e-4c1c-9d1b-6e7d2a8f4b10 \
  -d client_secret=$MOYMO_CLIENT_SECRET

Each refresh token works once: the answer carries the next one, and the old one stops working. Keep the newest. A refresh token lasts 30 days.

PKCE ​

Proof Key for Code Exchange makes a stolen code worthless. Before you send the member away, make a random verifier and keep it; send only its hash, the challenge. When you trade the code, send the verifier; Moymo hashes it and compares.

Making a verifier and its challenge
js
import { createHash, randomBytes } from 'node:crypto'

const verifier = randomBytes(48).toString('base64url')                          // 64 characters
const challenge = createHash('sha256').update(verifier).digest('base64url')     // 43 characters
// send `challenge` (with code_challenge_method=S256) now; keep `verifier` until the code comes back
python
import base64
import hashlib
import secrets

verifier = secrets.token_urlsafe(48)                                             # 64 characters
digest = hashlib.sha256(verifier.encode("ascii")).digest()
challenge = base64.urlsafe_b64encode(digest).rstrip(b"=").decode("ascii")        # 43 characters
# send `challenge` (with code_challenge_method=S256) now; keep `verifier` until the code comes back

The verifier is 43 to 128 characters from A-Z a-z 0-9 - . _ ~. Only S256 is accepted: plain would send the verifier in the clear in the first request, which is exactly what PKCE is there to avoid.

An application with no client secret has to use PKCE. An application with a secret should too: it costs nothing.

Revoking ​

Your app can revoke a token it holds with the revoke endpoint. A member can take back everything they allowed an app in Settings > Connected apps, and every token it made stops working at once.

If a code is used twice ​

A code that is used a second time is treated as stolen: Moymo refuses it and revokes the tokens the first use made. If you see invalid_grant on a code you only used once, something else used it first.

Errors ​

Errors at the token endpoint follow the standard: {"error": "invalid_grant", "error_description": "..."}. They are in the OAuth2 reference. Errors in the consent step reach your app as query parameters on the redirect (?error=access_denied&error_description=...&state=...), or, when the request is wrong in a way that makes the redirect address untrustworthy (an unknown application, an unregistered address), are shown to the member on Moymo's page and not sent anywhere.

The wiki is for Moymo's members and developers. Something wrong or missing? Use "Suggest a change" on any page.