Портал разработчиков
Экспериментально Платформа для ботов и приложений активно развивается. Поддержка собственных серверов вышла 13.08.2026, и функций там пока меньше, чем в облаке. Посмотрите, что поддерживается.
← Документация

Вход через GameVox

Позвольте людям входить на ваш сайт или в приложение со своим аккаунтом GameVox. Это стандартный процесс OAuth2 с кодом авторизации (authorization code), устроенный так же, как в Discord, и бот для него не нужен: ваше приложение запрашивает доступ к части данных аккаунта, пользователь соглашается, и ваш сервер получает токен.

Для чего это нужно

  • Вход и привязка аккаунтов. Узнайте, кто пользователь (постоянный ID пользователя GameVox, имя пользователя, аватар), а с его разрешения и его подтверждённый адрес электронной почты.
  • Выбор сервера и дашборды. Со скоупом guilds видно, на каких серверах состоит пользователь и где он может управлять настройками.
  • Не для действий от имени пользователя. Пользовательский токен не может отправлять сообщения, подключаться к голосовым каналам или что-либо менять в GameVox. Для любых действий внутри GameVox нужен бот.

Перед началом

  1. Создайте приложение на developers.gamevox.com. ID клиента на его вкладке OAuth2 и есть ваш client_id.
  2. На вкладке OAuth2 добавьте все URI перенаправления, которые будет использовать ваше приложение (до 10). Они должны начинаться с https:// (для разработки также http://localhost / http://127.0.0.1) и не содержать #fragment. Передаваемый вами redirect_uri должен точно совпадать с одним из них, включая строку запроса.
  3. Скопируйте секрет клиента. Он показывается один раз: при создании приложения или при сбросе секрета. Храните его на своём сервере: он нужен для каждого запроса токена.

Эндпоинты

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

Не убирайте завершающий слэш в /oauth2/authorize/. Эндпоинты токенов и пользователя также отвечают по пути с /api/v10/, поэтому библиотеки, которые добавляют версию в путь, работают без изменений. Связи ролей (role connections) находятся на api.gamevox.com, а не на app-api.

1. Отправьте пользователя в GameVox

Перенаправьте браузер на URL авторизации (обычным переходом, не во всплывающем окне и не в 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
ПараметрОбязательныйОписание
response_type Да Всегда code.
client_id Да ID клиента с вкладки OAuth2 вашего приложения.
scope Да Через пробел (в URL-кодировке %20 или +). См. Скоупы. Не указывайте bot: с bot этот URL превращается в установку на сервер.
redirect_uri Да Один из ваших зарегистрированных URI перенаправления, символ в символ.
state Нет Неугадываемое значение, привязанное к сессии пользователя (до 1024 символов). Оно возвращается без изменений; проверяйте его для защиты от подделки межсайтовых запросов (CSRF).
code_challenge Нет Необязательный challenge для PKCE, от 43 до 128 символов.
code_challenge_method Нет S256, если вы передаёте challenge. plain отклоняется.
prompt Нет none пропускает экран согласия, если пользователь уже одобрил ваше приложение для всех этих скоупов. Если запрошено что-то новое, экран всё равно появится.

Что видит пользователь

  • Экран согласия на gamevox.com: название, значок и описание вашего приложения, аккаунт, под которым пользователь вошёл, понятный список того, что вы сможете видеть, и сайт, на который его отправят.
  • Если пользователь не вошёл в аккаунт, кнопка «Log in» проведёт его через веб-приложение GameVox и сразу вернёт на тот же экран.
  • Ссылки на ваши Условия использования и Политику конфиденциальности появляются под кнопками, если вы указали их на вкладке Общая информация.

2. Обработайте возврат (callback)

Когда пользователь нажмёт «Authorize», GameVox отправит его на ваш URI перенаправления с кодом:

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

Если вместо этого он нажмёт «Cancel»:

https://yourapp.example.com/auth/gamevox?error=access_denied
  &error_description=The+user+denied+the+request&state=Zx81kq0vT2
  • Отклоняйте callback, если state не совпадает с тем, что вы выдали этому браузеру.
  • Код действует 10 минут и срабатывает только один раз. Обменяйте его сразу, со своего сервера.

3. Обменяйте код на токены

Со своего сервера отправьте POST с телом в формате формы (application/x-www-form-urlencoded, не JSON) на эндпоинт токенов:

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"
}
  • Аутентифицируйтесь через HTTP Basic (client_id:client_secret), как показано выше, или передайте client_id и client_secret полями формы.
  • redirect_uri должен совпадать со значением, которое вы отправили на шаге 1. Если вы используете PKCE, добавьте code_verifier.
  • Ответы содержат Cache-Control: no-store. Никогда не помещайте секрет клиента или токены в код, работающий в браузере, или в URL.

4. Вызывайте API

Передавайте токен доступа в заголовке Authorization: Bearer. Для GET /users/@me нужен скоуп 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 хранится постоянный ID пользователя GameVox. Привязывайте к нему записи аккаунтов: имена пользователей могут меняться. gamevox_id обозначает того же пользователя в собственном формате GameVox (UUID).
  • email и verified присутствуют только со скоупом email и только если у пользователя указан адрес электронной почты. GameVox хранит только подтверждённые адреса, поэтому verified всегда равно true, когда задан email.
  • avatar всегда равно null (библиотеки Discord построили бы из него ссылку на CDN Discord). Используйте gamevox_avatar_url; это поле отсутствует, если у пользователя нет аватара.

Серверы пользователя

Для GET /users/@me/guilds нужен скоуп 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 служит сводкой для выбора сервера, а не полным расчётом: все биты (включая ADMINISTRATOR) для владельца и администраторов, MANAGE_GUILD (32) плюс VIEW_CHANNEL (1024) там, где пользователь может менять настройки сервера, и VIEW_CHANNEL для всех остальных.
  • До limit серверов в одном ответе (от 1 до 200, по умолчанию 200), сначала самые старые. Для постраничной загрузки передайте в after или before id сервера из предыдущей страницы, как в Discord.

Текущая авторизация

GET /oauth2/@me работает с любым скоупом и сообщает, какому приложению принадлежит токен, что ему выдано и когда он истекает. user включается при наличии identify.

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

Связанные роли

Со скоупом role_connections.write вы можете записать, какой аккаунт есть у пользователя на вашей стороне. Обратите внимание на хост: 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": {}}'

Пользователь увидит это в Settings > Authorized Apps как «Linked as ShadowMage on RaidPlanner». Ключи metadata должны быть из тех, что вы определили в метаданных связей ролей своего приложения. GET по тому же URL возвращает сохранённые данные.

Обновление токенов

Токены доступа действуют 7 дней (expires_in указан в секундах). Новую пару можно получить с помощью токена обновления:

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...
  • Токены обновления ротируются. В ответе приходит новый токен обновления, а старый токен обновления и связанный с ним токен доступа сразу перестают работать, поэтому сохраните новую пару, прежде чем её использовать.
  • Можно передать scope, чтобы сузить новый токен до меньшего набора скоупов. Запрос скоупа, который пользователь никогда не выдавал, завершается ошибкой invalid_scope.
  • Неиспользованный токен обновления истекает через 90 дней. У каждого пользователя может быть не более 25 действующих пар токенов на приложение; при создании 26-й удаляется самая старая.

Отзыв (выход из аккаунта)

Отзывайте токены, когда пользователь выходит из вашего приложения. Любой из двух токенов пары отзывает всю пару. Для действительного клиента эндпоинт всегда отвечает 200, независимо от того, существовал ли токен.

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

PKCE

Необязательно, но рекомендуется, если URL авторизации формируется там, где его может увидеть кто-то посторонний. GameVox поддерживает только S256, и запросу токена всё равно нужен секрет клиента: публичных клиентов без секрета нет.

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

Скоупы

СкоупЧто разрешает приложению
identify Чтение ID, имени пользователя и аватара: GET /users/@me, а также user в GET /oauth2/@me.
email Добавляет подтверждённый адрес электронной почты пользователя в /users/@me.
guilds Чтение списка серверов пользователя: GET /users/@me/guilds.
role_connections.write Чтение и запись данных связанной роли пользователя для вашего приложения.

Любой другой скоуп, включая connections, guilds.join и applications.commands без bot, отклоняется на экране согласия с соответствующим сообщением.

Ошибки

Эндпоинты токенов и отзыва возвращают ошибки в стандартном для OAuth2 виде, {"error": "...", "error_description": "..."}, поэтому библиотеки OAuth понимают их без доработок:

errorHTTPЗначение
invalid_client 401 Неверный ID клиента или секрет, приложение удалено или аккаунт владельца приложения заблокирован.
invalid_grant 400 Код или токен обновления неизвестен, истёк, уже использован, выдан другому приложению, либо не совпадает его redirect_uri или code_verifier. Также возвращается после того, как пользователь отозвал авторизацию вашего приложения.
invalid_request 400 Отсутствует обязательное поле, или тело запроса не в формате формы.
invalid_scope 400 При обновлении запрошен скоуп, которого нет в исходном гранте.
unsupported_grant_type 400 Поддерживаются только authorization_code и refresh_token.
slow_down 429 Слишком много неудачных попыток аутентификации клиента с вашего IP (30 в минуту). Подождите минуту.

Вызовы API с неверным, истёкшим или отозванным токеном получают 401; токен без нужного скоупа получает 403 (50001 Missing Access). Ответы содержат обычные заголовки X-RateLimit-*, лимиты считаются отдельно для каждого пользователя в каждом приложении.

Когда доступ прекращается

Токен может перестать работать раньше срока. Это происходит, если:

  • пользователь нажал Deauthorize в Settings > Authorized Apps (все ваши токены для этого пользователя сразу перестают действовать, а ваша запись связанной роли для него удаляется)
  • аккаунт пользователя отключён
  • ваше приложение удалено
  • ваш аккаунт разработчика заблокирован

Считайте 401 или invalid_grant признаком того, что пользователь «вышел», и снова проведите его через шаг 1.

Полный пример (Node.js + Express)

Вход с проверкой state, обмен кода и получение данных пользователя. Для встроенного fetch нужен 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);

Отличия от Discord

  • Только грант authorization code. Нет implicit-гранта (response_type=token) и нет client_credentials.
  • Нет публичных клиентов: каждому запросу токена нужен секрет клиента, с PKCE или без.
  • Установки пользователю (applications.commands без bot, integration_type=1) пока недоступны.
  • Нет скоупов connections, guilds.join, guilds.members.read и rpc.
  • В /users/@me/guilds поле permissions служит сводкой для выбора сервера, а не полным расчётом (см. выше).

← Назад к документации