Portal deweloperski
Eksperymentalne Platforma botów i aplikacji jest aktywnie rozwijana. Obsługa serwerów hostowanych samodzielnie pojawiła się 13.08.2026 i ma mniej funkcji niż chmura. Zobacz, co jest obsługiwane.
← Dokumentacja

Logowanie przez GameVox

Pozwól użytkownikom logować się do twojej witryny lub aplikacji ich kontem GameVox. To standardowy przepływ OAuth2 z kodem autoryzacji (authorization code), zbudowany tak jak na Discordzie, i nie wymaga bota: twoja aplikacja prosi o dostęp do części konta użytkownika, użytkownik się zgadza, a twój serwer dostaje token.

Do czego to służy

  • Logowanie i łączenie kont. Dowiesz się, kim jest użytkownik (stały identyfikator użytkownika GameVox, nazwa użytkownika, awatar), a za jego zgodą także poznasz jego zweryfikowany adres e-mail.
  • Wybór serwera i panele. Z zakresem guilds widzisz, na jakich serwerach jest użytkownik i gdzie może zarządzać ustawieniami.
  • Nie służy do działania w imieniu użytkownika. Token użytkownika nie może wysyłać wiadomości, dołączać do kanałów głosowych ani niczego zmieniać w GameVox. Do wszystkiego, co działa wewnątrz GameVox, potrzebny jest bot.

Zanim zaczniesz

  1. Utwórz aplikację na developers.gamevox.com. Client ID z jej karty OAuth2 to twój client_id.
  2. W zakładce OAuth2 dodaj wszystkie URI przekierowania, których będzie używać twoja aplikacja (maksymalnie 10). Muszą zaczynać się od https:// (podczas developmentu także http://localhost / http://127.0.0.1) i nie mogą zawierać #fragment. Wysyłany przez ciebie redirect_uri musi dokładnie pasować do jednego z nich, łącznie z parametrami zapytania.
  3. Skopiuj client secret. Jest pokazywany raz: przy tworzeniu aplikacji lub resetowaniu sekretu. Trzymaj go na swoim serwerze: wymaga go każde żądanie tokena.

Endpointy

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

Zachowaj ukośnik na końcu /oauth2/authorize/. Endpointy tokenów i użytkownika odpowiadają też pod /api/v10/, więc biblioteki, które dodają wersję do ścieżki, działają bez zmian. Połączenia ról (role connections) działają pod api.gamevox.com, a nie app-api.

1. Przekieruj użytkownika do GameVox

Przekieruj przeglądarkę na URL autoryzacji (zwykłą nawigacją, nie w wyskakującym oknie ani w iframe):

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
ParametrWymaganyOpis
response_type Tak Zawsze code.
client_id Tak Client ID z karty OAuth2 twojej aplikacji.
scope Tak Rozdzielone spacjami (w URL zakodowanymi jako %20 lub +). Zobacz Zakresy. Pomiń bot: z bot ten URL staje się instalacją na serwerze.
redirect_uri Tak Jeden z twoich zarejestrowanych URI przekierowania, dokładnie w tej samej postaci.
state Nie Niemożliwa do odgadnięcia wartość powiązana z sesją użytkownika (do 1024 znaków). Wraca bez zmian; sprawdzaj ją, aby chronić się przed fałszowaniem żądań między witrynami (CSRF).
code_challenge Nie Opcjonalny challenge PKCE, od 43 do 128 znaków.
code_challenge_method Nie S256, gdy wysyłasz challenge. plain jest odrzucane.
prompt Nie none pomija ekran zgody, jeśli użytkownik już zatwierdził twoją aplikację dla wszystkich tych zakresów. Jeśli prosisz o coś nowego, ekran i tak się pojawi.

Co widzi użytkownik

  • Ekran zgody na gamevox.com z nazwą, ikoną i opisem twojej aplikacji, kontem, na które użytkownik jest zalogowany, zrozumiałą listą danych, do których dostaniesz dostęp, oraz witryną, na którą zostanie przekierowany.
  • Jeśli użytkownik nie jest zalogowany, przycisk „Log in” prowadzi go przez aplikację webową GameVox i od razu z powrotem na ten sam ekran.
  • Linki do twojego regulaminu i polityki prywatności pojawiają się pod przyciskami, jeśli ustawisz je w zakładce Informacje ogólne.

2. Obsłuż callback

Gdy użytkownik kliknie „Authorize”, GameVox przekieruje go na twój URI przekierowania z kodem:

https://yourapp.example.com/auth/gamevox?code=3vR0b...&state=Zx81kq0vT2

Jeśli zamiast tego kliknie „Cancel”:

https://yourapp.example.com/auth/gamevox?error=access_denied
  &error_description=The+user+denied+the+request&state=Zx81kq0vT2
  • Odrzuć callback, jeśli state nie zgadza się z wartością wydaną dla tej przeglądarki.
  • Kod wygasa po 10 minutach i działa tylko raz. Wymień go od razu, ze swojego serwera.

3. Wymień kod na tokeny

Ze swojego serwera wyślij POST z treścią zakodowaną jako formularz (application/x-www-form-urlencoded, nie JSON) na endpoint tokenów:

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"
}
  • Uwierzytelnij się przez HTTP Basic (client_id:client_secret) jak powyżej albo wyślij client_id i client_secret jako pola formularza.
  • redirect_uri musi mieć tę samą wartość, którą wysłano w kroku 1. Jeśli używasz PKCE, dodaj code_verifier.
  • Odpowiedzi zawierają Cache-Control: no-store. Nigdy nie umieszczaj client secret ani tokenów w kodzie działającym w przeglądarce ani w adresach URL.

4. Wywołuj API

Wysyłaj token dostępu jako Authorization: Bearer. GET /users/@me wymaga zakresu identify:

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
}
  • id to stały identyfikator użytkownika w GameVox. Wiąż z nim rekordy kont, bo nazwy użytkowników mogą się zmieniać. gamevox_id to ten sam użytkownik w natywnej postaci UUID GameVox.
  • email i verified są obecne tylko z zakresem email i tylko wtedy, gdy użytkownik ma zapisany adres e-mail. GameVox przechowuje wyłącznie zweryfikowane adresy, więc verified ma zawsze wartość true, gdy ustawiony jest email.
  • avatar ma zawsze wartość null (biblioteki Discorda zbudowałyby z niego link do CDN Discorda). Używaj gamevox_avatar_url; to pole jest pomijane, gdy użytkownik nie ma zdjęcia profilowego.

Serwery użytkownika

GET /users/@me/guilds wymaga zakresu guilds:

[
  { "id": "1557445672742031360", "name": "Raid Night", "icon": null,
    "owner": true,  "permissions": "2251799813685247", "features": [] },
  { "id": "1557445672742031361", "name": "Guild Hall", "icon": null,
    "owner": false, "permissions": "1056", "features": [] }
]
  • permissions to podsumowanie do wybierania serwera, a nie pełne wyliczenie: wszystkie bity (łącznie z ADMINISTRATOR) dla właściciela i administratorów, MANAGE_GUILD (32) plus VIEW_CHANNEL (1024) tam, gdzie użytkownik może edytować ustawienia serwera, i VIEW_CHANNEL dla wszystkich pozostałych.
  • Do limit serwerów na odpowiedź (od 1 do 200, domyślnie 200), od najstarszego. Stronicuj, ustawiając after lub before na id serwera z poprzedniej strony, tak jak na Discordzie.

Bieżąca autoryzacja

GET /oauth2/@me działa z dowolnym zakresem i mówi, do której aplikacji należy token, co mu przyznano i kiedy wygasa. user jest dołączany przy zakresie identify.

{
  "application": { "id": "123456789012345678", "name": "RaidPlanner", ... },
  "scopes": ["identify", "email"],
  "expires": "2026-10-15T15:03:20Z",
  "user": { "id": "1557709980780474368", "username": "alice", ... }
}

Połączone role

Z zakresem role_connections.write możesz zapisać, jakie konto użytkownik ma po twojej stronie. Zwróć uwagę na 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": {}}'

Użytkownik widzi to w Settings > Authorized Apps jako „Linked as ShadowMage on RaidPlanner”. Klucze metadata muszą pochodzić z metadanych połączeń ról zdefiniowanych w twojej aplikacji. GET na ten sam URL odczytuje zapisane dane.

Odświeżanie

Tokeny dostępu są ważne przez 7 dni (expires_in jest podawane w sekundach). Nową parę uzyskasz za pomocą tokena odświeżania:

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...
  • Tokeny odświeżania są rotowane. Odpowiedź zawiera nowy token odświeżania, a stary token odświeżania i jego token dostępu natychmiast przestają działać, więc zapisz nową parę, zanim jej użyjesz.
  • Możesz wysłać scope, aby zawęzić nowy token do mniejszej liczby zakresów. Prośba o zakres, którego użytkownik nigdy nie przyznał, kończy się błędem invalid_scope.
  • Nieużywany token odświeżania wygasa po 90 dniach. Każdy użytkownik może mieć najwyżej 25 aktywnych par tokenów na aplikację; utworzenie 26. pary usuwa najstarszą.

Unieważnianie (wylogowanie)

Unieważnij tokeny, gdy użytkownik wyloguje się z twojej aplikacji. Dowolny z dwóch tokenów pary unieważnia całą parę. Dla prawidłowego klienta endpoint zawsze odpowiada 200, niezależnie od tego, czy token istniał.

curl -X POST https://app-api.gamevox.com/api/oauth2/token/revoke \
  -u "123456789012345678:CS.your-client-secret" \
  -d token=GVO.mJ4c...

PKCE

Opcjonalne, ale zalecane, jeśli URL autoryzacji może powstawać w miejscu, gdzie ktoś inny mógłby go zobaczyć. GameVox obsługuje tylko S256, a żądanie tokena nadal wymaga client secret: nie ma klientów publicznych bez sekretu.

// 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)

Zakresy

ZakresCo umożliwia twojej aplikacji
identify Odczyt identyfikatora, nazwy i awatara użytkownika: GET /users/@me oraz user w GET /oauth2/@me.
email Dodaje zweryfikowany adres e-mail użytkownika do /users/@me.
guilds Odczyt listy serwerów użytkownika: GET /users/@me/guilds.
role_connections.write Odczyt i zapis danych połączonej roli użytkownika dla twojej aplikacji.

Każdy inny zakres, w tym connections, guilds.join i applications.commands bez bot, jest odrzucany na ekranie zgody z odpowiednim komunikatem.

Błędy

Endpointy tokenów i unieważniania zwracają błędy w standardowym formacie OAuth2, {"error": "...", "error_description": "..."}, więc biblioteki OAuth odczytują je bez dodatkowej obsługi:

errorHTTPZnaczenie
invalid_client 401 Nieprawidłowy client ID lub secret, usunięta aplikacja albo zawieszone konto właściciela aplikacji.
invalid_grant 400 Kod lub token odświeżania jest nieznany, wygasł, został już użyty, został wydany innej aplikacji albo nie zgadza się jego redirect_uri lub code_verifier. Zwracany także po tym, jak użytkownik cofnie autoryzację twojej aplikacji.
invalid_request 400 Brakuje wymaganego pola albo treść nie jest zakodowana jako formularz.
invalid_scope 400 Odświeżenie prosi o zakres, którego nie obejmuje pierwotny grant.
unsupported_grant_type 400 Obsługiwane są tylko authorization_code i refresh_token.
slow_down 429 Zbyt wiele nieudanych uwierzytelnień klienta z twojego IP (30 na minutę). Odczekaj minutę.

Wywołania API ze złym, wygasłym lub unieważnionym tokenem dostają 401; token bez potrzebnego zakresu dostaje 403 (50001 Missing Access). Odpowiedzi zawierają zwykłe nagłówki X-RateLimit-*, liczone osobno dla każdego użytkownika w każdej aplikacji.

Kiedy dostęp się kończy

Token może przestać działać przed upływem ważności. Dzieje się tak, gdy:

  • użytkownik kliknie Deauthorize w Settings > Authorized Apps (wszystkie twoje tokeny tego użytkownika od razu przestają działać, a twój wpis połączonej roli dla niego zostaje usunięty)
  • konto użytkownika zostanie wyłączone
  • twoja aplikacja zostanie usunięta
  • twoje konto dewelopera zostanie zawieszone

Traktuj 401 lub invalid_grant jako „wylogowanie” i przeprowadź użytkownika ponownie przez krok 1.

Pełny przykład (Node.js + Express)

Logowanie ze sprawdzaniem state, wymiana kodu i odczyt danych użytkownika. Wbudowany fetch wymaga Node 18+.

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);

Różnice względem Discorda

  • Tylko grant authorization code. Brak grantu implicit (response_type=token) i brak client_credentials.
  • Brak klientów publicznych: każde żądanie tokena wymaga client secret, z PKCE lub bez.
  • Instalacje dla użytkownika (applications.commands bez bot, integration_type=1) nie są jeszcze dostępne.
  • Brak zakresów connections, guilds.join, guilds.members.read i rpc.
  • W /users/@me/guilds pole permissions to podsumowanie do wybierania serwera, a nie pełne wyliczenie (patrz wyżej).

← Powrót do dokumentacji