Login with Voicaw
Your website can let people log in with their Voicaw account. It's Discord's OAuth2
authorisation code grant, so a site that logs people in with Discord works with Voicaw by
changing three addresses and its client id and secret. The only scope is
identify: the person's id, username, display name and picture.
Setting up
- Make an application in the Developer Portal (every application also has a bot; you don't have to use it).
- Under OAuth2, make a client secret and copy it: it's shown once. It belongs on your server only, never in a web page or an app.
- Add your redirects: the exact addresses people come back to after logging in. They must be
https(orhttp://localhost/127.0.0.1while testing), without a#fragment. Up to 10.
The addresses
| What | Discord's | Voicaw's |
|---|---|---|
| Authorise (people's browser) | https://discord.com/oauth2/authorize | https://app.voicaw.com/oauth2/authorize |
| Token (your server) | https://discord.com/api/oauth2/token | https://api.voicaw.com/api/v10/oauth2/token |
| Who logged in | https://discord.com/api/users/@me | https://api.voicaw.com/api/v10/users/@me |
| Pictures | https://cdn.discordapp.com/avatars/{id}/{avatar}.png | https://api.voicaw.com/api/cdn/avatars/{id}/{avatar}.png, or the user's avatar_url |
Note the /api/v10: Voicaw's API has no unversioned /api/users/@me.
The flow
1. Send the person to the authorise page:
https://app.voicaw.com/oauth2/authorize?client_id=123&response_type=code&scope=identify
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&state=RANDOM
They log in to Voicaw if they aren't already, see your application, what it will know
and where they'll go, and choose Authorise or Cancel.
redirect_uri must be one of your redirects exactly (you may leave it out
if you have only one). Make state a random value tied to the person's
session and check it when they come back. With prompt=none, someone who has
already let your application in goes straight back without being asked again.
2. They come back to your redirect with a code, or with error=access_denied if they cancelled:
https://example.com/callback?code=CODE&state=RANDOM
3. Your server trades the code for a token (a form, or JSON; the client id and secret in the body or as HTTP Basic):
POST /api/v10/oauth2/token
Content-Type: application/x-www-form-urlencoded
client_id=123&client_secret=SECRET&grant_type=authorization_code&code=CODE
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
{ "access_token": "…", "token_type": "Bearer", "expires_in": 604800, "refresh_token": "…", "scope": "identify" }
A code works once, within 10 minutes, for the application it was made for and with the same redirect_uri.
4. Ask who it is:
GET /api/v10/users/@me
Authorization: Bearer ACCESS_TOKEN
{ "id": "42", "username": "alice", "discriminator": "0", "global_name": "Alice", "avatar": "a1b2c3", "bot": false,
"avatar_url": "https://…/profile-pics/42/a1b2c3.webp", "mfa_enabled": false, "locale": "en-GB", … }
Ids are Voicaw's (decimal strings, not snowflakes). There's no email: Voicaw
doesn't have people's email addresses.
Tokens
| Endpoint | Notes |
|---|---|
POST /oauth2/token | grant_type=authorization_code (code, redirect_uri) or refresh_token (refresh_token). Every answer has a new refresh token; the old pair stops working. |
POST /oauth2/token/revoke | token (access or refresh): it and its pair stop working. |
GET /users/@me | With Bearer: the person (identify). |
GET /oauth2/@me | With Bearer: { application, scopes, expires, user }. |
Access tokens last 7 days. A refresh token works once, until it's revoked, or until 30 days after its access token ran out. A login token opens only the two endpoints above: everything else in the bot API wants a bot token. Tokens stop working when the person removes your application under Settings → Authorised apps, when their account is deleted or suspended, and when you delete the application. Resetting the client secret doesn't log anyone out.
Errors are OAuth2's, not the bot API's:
{ "error": "invalid_grant", "error_description": "Invalid \"code\" in request." }
invalid_client (401: wrong id or secret), invalid_grant (a
used, expired or someone else's code or refresh token), invalid_request,
unsupported_grant_type. The token endpoints take 30 requests a minute from
one address. Mistakes in the authorise link go back to your redirect as
error=invalid_scope or unsupported_response_type; an unknown
client or redirect is shown to the person instead, and they're never sent there.