Log in with GameVox
Hayaang mag-sign in ang mga tao sa website o app mo gamit ang GameVox account nila. Ito ang standard na OAuth2 authorization-code flow, kahugis ng sa Discord, at hindi ito nangangailangan ng bot: humihingi ang app mo ng ilang bahagi ng account ng user, inaaprubahan ito ng user, at nakakakuha ng token ang backend mo.
Para saan ito
- Sign-in at account linking. Alamin kung sino ang user (isang stable na GameVox user ID, username, avatar) at, kung papayag sila, ang verified email nila.
- Server pickers at dashboards. Gamit ang
guilds, makikita mo kung aling servers kasali ang user at kung saan nila puwedeng i-manage ang settings. - Hindi ito para kumilos bilang user. Hindi makakapagpadala ng messages, makakasali sa voice, o makakapagbago ng kahit ano sa GameVox ang isang user token. Kailangan ng bot para sa anumang kumikilos sa loob ng GameVox.
Bago ka magsimula
- Gumawa ng application sa developers.gamevox.com. Ang Client ID sa OAuth2 tab nito ang
client_idmo. - Sa OAuth2 tab, idagdag ang bawat redirect URI na gagamitin ng app mo (hanggang 10). Dapat
https://ang mga ito, ohttp://localhost/http://127.0.0.1para sa development, at walang#fragment. Dapat eksaktong tugma ang ipapadala mongredirect_urisa isa sa mga ito, kasama ang query string. - Kopyahin ang client secret. Isang beses lang ito ipinapakita, kapag ginawa ang app o ni-reset ang secret. Itago ito sa backend mo: kailangan ito ng bawat token request.
Endpoints
GET https://gamevox.com/oauth2/authorize/
POST https://app-api.gamevox.com/api/oauth2/token
POST https://app-api.gamevox.com/api/oauth2/token/revoke
GET https://app-api.gamevox.com/api/users/@me
GET https://app-api.gamevox.com/api/users/@me/guilds
GET https://app-api.gamevox.com/api/oauth2/@me
PUT https://api.gamevox.com/api/users/@me/applications/{application.id}/role-connection Huwag tanggalin ang trailing slash sa /oauth2/authorize/. Sumasagot din ang token at user endpoints sa ilalim ng /api/v10/, kaya gumagana nang walang binabago ang mga library na naglalagay ng version sa path. Nasa api.gamevox.com ang role connections, hindi sa app-api.
1. Ipadala ang user sa GameVox
I-redirect ang browser (normal na navigation, hindi popup o iframe) sa authorize URL:
https://gamevox.com/oauth2/authorize/
?response_type=code
&client_id=123456789012345678
&scope=identify%20email
&redirect_uri=https%3A%2F%2Fyourapp.example.com%2Fauth%2Fgamevox
&state=Zx81kq0vT2 | Parameter | Kailangan | Paglalarawan |
|---|---|---|
response_type | Oo | Palaging code. |
client_id | Oo | Ang Client ID sa OAuth2 tab ng app mo. |
scope | Oo | Hiwalay sa space (URL-encoded bilang %20 o +). Tingnan ang Scopes. Huwag isama ang bot: kapag may bot, nagiging server install ang URL na ito. |
redirect_uri | Oo | Isa sa registered redirect URIs mo, eksaktong pareho. |
state | Hindi | Isang value na hindi mahuhulaan at nakatali sa session ng user (hanggang 1024 characters). Bumabalik ito nang walang pagbabago; i-check ito para mapigilan ang cross-site request forgery. |
code_challenge | Hindi | Optional na PKCE challenge, 43 hanggang 128 characters. |
code_challenge_method | Hindi | S256 kapag nagpapadala ka ng challenge. Tinatanggihan ang plain. |
prompt | Hindi | Nilalaktawan ng none ang consent screen kapag naaprubahan na ng user ang app mo para sa lahat ng scopes na ito. Itatanong pa rin ang anumang bago. |
Ang nakikita ng user
- Isang consent screen sa gamevox.com na may pangalan, icon at paglalarawan ng app mo, ang account na naka-sign in sila, isang simpleng listahan ng mga makikita mo, at ang site na pupuntahan nila.
- Kung naka-sign out sila, dadalhin sila ng Log in sa GameVox web app at diretsong ibabalik sa parehong screen.
- Lalabas sa ilalim ng mga button ang Terms of Service at Privacy Policy links mo kapag na-set mo ang mga ito sa Pangkalahatang Impormasyon tab.
2. I-handle ang callback
Pagka-click ng user sa Authorize, ipapadala sila ng GameVox sa redirect URI mo kasama ang isang code:
https://yourapp.example.com/auth/gamevox?code=3vR0b...&state=Zx81kq0vT2 Kung Cancel ang i-click nila:
https://yourapp.example.com/auth/gamevox?error=access_denied
&error_description=The+user+denied+the+request&state=Zx81kq0vT2 - I-reject ang callback kung hindi tugma ang
statesa in-issue mo para sa browser na ito. - Nag-e-expire ang code pagkalipas ng 10 minuto at isang beses lang ito gumagana. I-exchange ito agad, mula sa backend mo.
3. I-exchange ang code para sa tokens
Mula sa backend mo, mag-POST ng form-encoded na body (application/x-www-form-urlencoded, hindi JSON) sa token endpoint:
curl -X POST https://app-api.gamevox.com/api/oauth2/token \
-u "123456789012345678:CS.your-client-secret" \
-d grant_type=authorization_code \
-d code=3vR0b... \
-d redirect_uri=https://yourapp.example.com/auth/gamevox {
"access_token": "GVO.mJ4c...",
"token_type": "Bearer",
"expires_in": 604800,
"refresh_token": "GVR.9tQe...",
"scope": "identify email"
} - Mag-authenticate gamit ang HTTP Basic (
client_id:client_secret) gaya sa itaas, o ipadala angclient_idatclient_secretbilang form fields. - Dapat pareho ang
redirect_urisa value na ipinadala mo sa step 1. Idagdag angcode_verifierkung gumamit ka ng PKCE. - May
Cache-Control: no-storeang mga response. Huwag kailanman ilagay ang client secret o tokens sa browser code o sa URLs.
4. Tawagin ang API
Ipadala ang access token bilang Authorization: Bearer. Kailangan ng GET /users/@me ang identify scope:
curl https://app-api.gamevox.com/api/users/@me \
-H "Authorization: Bearer GVO.mJ4c..." {
"id": "1557709980780474368",
"gamevox_id": "edf412bc-a7b8-4f2a-a810-8b9eb8c02462",
"username": "alice",
"discriminator": "0",
"global_name": "alice",
"avatar": null,
"gamevox_avatar_url": "https://...",
"email": "alice@example.com",
"verified": true
} - Ang
iday ang stable na GameVox ID ng user. Dito i-key ang account records mo; puwedeng magbago ang usernames. Anggamevox_iday ang parehong user sa native UUID form ng GameVox. - Kasama lang ang
emailatverifiedkapag mayemailscope, at kung may email na naka-file ang user. Verified addresses lang ang sine-save ng GameVox, kaya palagingtrueangverifiedkapag naka-set angemail. - Palaging
nullangavatar(gagawa kasi ng Discord CDN link mula rito ang Discord libraries). Gamitin anggamevox_avatar_url, na wala sa response kapag walang picture ang user.
Ang servers ng user
Kailangan ng GET /users/@me/guilds ang guilds scope:
[
{ "id": "1557445672742031360", "name": "Raid Night", "icon": null,
"owner": true, "permissions": "2251799813685247", "features": [] },
{ "id": "1557445672742031361", "name": "Guild Hall", "icon": null,
"owner": false, "permissions": "1056", "features": [] }
] - Summary para sa pagpili ng server ang
permissions, hindi buong kalkulasyon: lahat ng bit (kasama angADMINISTRATOR) para sa owner at admins,MANAGE_GUILD(32) atVIEW_CHANNEL(1024) kung saan puwedeng i-edit ng user ang server settings, atVIEW_CHANNELpara sa lahat ng iba pa. - Hanggang
limitna server kada response (1 hanggang 200, default 200), pinakaluma muna. Mag-page gamit angafterobeforena naka-set saidng isang server mula sa naunang page, gaya sa Discord.
Ang kasalukuyang authorization
Gumagana ang GET /oauth2/@me sa kahit anong scope at sinasabi nito kung aling app ang may-ari ng token, ano ang ibinigay dito, at kailan ito mag-e-expire. Kasama ang user kapag may identify.
{
"application": { "id": "123456789012345678", "name": "RaidPlanner", ... },
"scopes": ["identify", "email"],
"expires": "2026-10-15T15:03:20Z",
"user": { "id": "1557709980780474368", "username": "alice", ... }
} Linked roles
Gamit ang role_connections.write, puwede mong i-record kung aling account ang meron ang user sa panig mo. Pansinin ang host: api.gamevox.com.
curl -X PUT \
https://api.gamevox.com/api/users/@me/applications/123456789012345678/role-connection \
-H "Authorization: Bearer GVO.mJ4c..." \
-H "Content-Type: application/json" \
-d '{"platform_name": "RaidPlanner", "platform_username": "ShadowMage", "metadata": {}}' Makikita ito ng user sa ilalim ng Settings > Authorized Apps bilang “Linked as ShadowMage on RaidPlanner”. Dapat ang metadata keys ay mga key na dinefine mo sa role-connection metadata ng app mo. Binabasa itong muli ng GET sa parehong URL.
Pag-refresh
Tumatagal nang 7 araw ang access tokens (in seconds ang expires_in). Kumuha ng bagong pair gamit ang refresh token:
curl -X POST https://app-api.gamevox.com/api/oauth2/token \
-u "123456789012345678:CS.your-client-secret" \
-d grant_type=refresh_token \
-d refresh_token=GVR.9tQe... - Nagro-rotate ang refresh tokens. May bagong refresh token sa response, at agad na hindi na gagana ang lumang refresh token at ang access token nito, kaya i-save muna ang bagong pair bago ito gamitin.
- Puwede kang magpadala ng
scopepara limitahan ang bagong token sa mas kaunting scopes. Kapag humingi ka ng scope na hindi kailanman ibinigay ng user, magfe-fail ito nang mayinvalid_scope. - Nag-e-expire ang hindi nagagamit na refresh token pagkalipas ng 90 araw. Hanggang 25 live token pairs lang kada app ang puwede sa bawat user; kapag gumawa ng ika-26, tatanggalin ang pinakaluma.
Pag-revoke (pag-log out)
Mag-revoke kapag nag-sign out ang user sa app mo. Nire-revoke ng alinmang token sa pair ang buong pair. Palaging sumasagot ng 200 ang endpoint para sa valid na client, umiiral man o hindi ang token.
curl -X POST https://app-api.gamevox.com/api/oauth2/token/revoke \
-u "123456789012345678:CS.your-client-secret" \
-d token=GVO.mJ4c... PKCE
Optional, at inirerekomenda kung puwedeng mabuo ang authorize URL sa lugar na makikita ng iba. S256 lang ang suportado ng GameVox, at kailangan pa rin ng token request ang client secret mo: walang public clients na walang secret.
// Before redirecting: keep the verifier with the user's pending login.
const verifier = base64url(crypto.randomBytes(32));
const challenge = base64url(crypto.createHash('sha256').update(verifier).digest());
// authorize URL: ...&code_challenge=CHALLENGE&code_challenge_method=S256
// token request: ...&code_verifier=VERIFIER (client secret still required) Scopes
| Scope | Ang puwedeng gawin ng app mo |
|---|---|
identify | Basahin ang ID, username at avatar ng user: GET /users/@me, at user sa GET /oauth2/@me. |
email | Idagdag ang verified email ng user sa /users/@me. |
guilds | Basahin ang server list ng user: GET /users/@me/guilds. |
role_connections.write | Basahin at isulat ang linked role details ng user para sa app mo. |
Ang anumang ibang scope, pati ang connections, guilds.join at applications.commands na walang bot, ay tinatanggihan sa consent screen na may mensaheng nagsasabi nito.
Errors
Sumasagot ang token at revoke endpoints ng errors sa standard na OAuth2 shape, {"error": "...", "error_description": "..."}, kaya nababasa ito ng OAuth libraries nang walang binabago:
| error | HTTP | Kahulugan |
|---|---|---|
invalid_client | 401 | Maling client ID o secret, na-delete na app, o naka-suspend ang account ng owner ng app. |
invalid_grant | 400 | Hindi kilala, expired, nagamit na, o ibinigay sa ibang app ang code o refresh token, o hindi tugma ang redirect_uri o code_verifier nito. Ibinabalik din ito pagkatapos i-deauthorize ng user ang app mo. |
invalid_request | 400 | May kulang na required field, o hindi form-encoded ang body. |
invalid_scope | 400 | Humingi ang refresh ng scope na wala sa orihinal na grant. |
unsupported_grant_type | 400 | authorization_code at refresh_token lang ang suportado. |
slow_down | 429 | Masyadong maraming failed na client authentication mula sa IP mo (30 kada minuto). Maghintay ng isang minuto. |
Nakakakuha ng 401 ang API calls na may mali, expired o na-revoke na token; 403 (50001 Missing Access) naman ang token na walang kinakailangang scope. May karaniwang X-RateLimit-* headers ang mga response, binibilang kada user kada app.
Kapag natapos ang access
Puwedeng tumigil gumana ang token bago pa ito mag-expire. Nangyayari ito kapag:
- na-click ng user ang Deauthorize sa ilalim ng Settings > Authorized Apps (sabay-sabay na titigil gumana ang lahat ng token na hawak mo para sa kanila, at buburahin ang linked-role entry mo para sa kanila)
- na-disable ang account ng user
- na-delete ang application mo
- na-suspend ang developer account mo
Ituring ang 401 o invalid_grant na “naka-sign out” at ipadaan ulit ang user sa step 1.
Kumpletong halimbawa (Node.js + Express)
Sign-in na may state checking, ang code exchange, at pagbasa sa user. Node 18+ para sa built-in na fetch.
import express from 'express';
import crypto from 'node:crypto';
const CLIENT_ID = process.env.GAMEVOX_CLIENT_ID;
const CLIENT_SECRET = process.env.GAMEVOX_CLIENT_SECRET;
const REDIRECT_URI = 'https://yourapp.example.com/auth/gamevox';
// state must be tied to THIS browser, or someone can hand a victim a callback
// URL carrying the attacker's own code and sign them in as the attacker.
// A short-lived HttpOnly cookie does that without a session store.
const STATE_COOKIE = 'gv_oauth_state';
const readCookie = (req, name) =>
(req.headers.cookie || '').split(';').map((c) => c.trim().split('='))
.find(([k]) => k === name)?.[1] || '';
const app = express();
app.get('/login', (req, res) => {
const state = crypto.randomBytes(16).toString('hex');
res.cookie(STATE_COOKIE, state, {
httpOnly: true, secure: true, sameSite: 'lax', maxAge: 10 * 60 * 1000, path: '/auth/gamevox',
});
const url = new URL('https://gamevox.com/oauth2/authorize/');
url.search = new URLSearchParams({
response_type: 'code',
client_id: CLIENT_ID,
scope: 'identify email',
redirect_uri: REDIRECT_URI,
state,
}).toString();
res.redirect(url.toString());
});
app.get('/auth/gamevox', async (req, res) => {
const { code, state, error } = req.query;
const expected = readCookie(req, STATE_COOKIE);
res.clearCookie(STATE_COOKIE, { path: '/auth/gamevox' });
if (!expected || typeof state !== 'string' || state !== expected) {
return res.status(400).send('Login expired or started in another browser');
}
if (error) return res.redirect('/?login=cancelled');
if (typeof code !== 'string') return res.status(400).send('Missing code');
const tokenRes = await fetch('https://app-api.gamevox.com/api/oauth2/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: 'Basic ' + Buffer.from(CLIENT_ID + ':' + CLIENT_SECRET).toString('base64'),
},
body: new URLSearchParams({ grant_type: 'authorization_code', code, redirect_uri: REDIRECT_URI }),
});
if (!tokenRes.ok) return res.status(502).send('GameVox login failed');
const tokens = await tokenRes.json();
const me = await fetch('https://app-api.gamevox.com/api/users/@me', {
headers: { Authorization: 'Bearer ' + tokens.access_token },
}).then((r) => r.json());
// me.id is the stable GameVox user id: key your account record on it.
// Store tokens.refresh_token server-side if you need access later.
res.send('Signed in as ' + me.username);
});
app.listen(3000); Mga pagkakaiba sa Discord
- Authorization-code grant lang. Walang implicit grant (
response_type=token) at walangclient_credentials. - Walang public clients: kailangan ng client secret sa bawat token request, may PKCE man o wala.
- Hindi pa available ang user installs (
applications.commandsna walangbot,integration_type=1). - Walang
connections,guilds.join,guilds.members.readorpcscopes. - Sa
/users/@me/guilds, summary para sa pagpili ng server angpermissions, hindi buong kalkulasyon (tingnan sa itaas).