X-GRK ID

Вход через X-GRK ID

Подключите авторизацию к своему сайту или приложению. Пользователь вводит почту и пароль только на X-GRK ID. Вам приходит код, вы меняете его на токен на своём сервере.

Что нужно

Запросите у X-GRK регистрацию приложения. Вам выдадут:

  • app_name — публичный идентификатор клиента (client_id)
  • app_secret — секрет только для вашего бэкенда (client_secret)
  • белый список redirect_uri — адреса, на которые можно вернуть пользователя

Секрет не кладите в JavaScript, мобильное приложение и публичный репозиторий. Храните в переменных окружения сервера. Чужой redirect_uri сервер отклонит.

Базовый URL (issuer): https://id.x-grk.com
Discovery: /.well-known/openid-configuration

Как это работает

  1. Пользователь нажимает «Войти через X-GRK ID» на вашем сайте.
  2. Браузер уходит на X-GRK ID, входит или регистрируется, подтверждает доступ.
  3. Вас возвращают на redirect_uri?code=...&state=....
  4. Ваш сервер проверяет state и обменивает code на токены, предъявляя app_secret.
  5. По access-токену запрашиваете профиль.

Пароль, капча и двухфакторка остаются на стороне X-GRK ID. Вам этого реализовывать не нужно.

Кнопка входа

Сгенерируйте случайный state, сохраните его в своей сессии, затем редирект:

https://id.x-grk.com/oauth/authorize
  ?response_type=code
  &client_id=ВАШ_APP_NAME
  &redirect_uri=https://ваш.сайт/callback
  &scope=openid%20profile%20email
  &state=случайная-строка

Или SDK (секрет сюда не передаётся):

<script src="https://id.x-grk.com/static/sdk/xgrk-id.js"></script>
<div id="xgrk-login"></div>
<script>
  XGrkID.init({
    issuer: "https://id.x-grk.com",
    appName: "ВАШ_APP_NAME",
    redirectUri: "https://ваш.сайт/callback",
    display: "redirect" // или "popup"
  }).renderButton("#xgrk-login");
</script>

Для popup страница callback должна закрыть окно и обновить window.opener.

Параметры authorize:

ПараметрНужен
response_typeдатолько code
client_idдаваш app_name
redirect_uriдаточно как в заявке, байт в байт
scopeнетпо умолчанию openid profile email
stateдазащита от CSRF, вернётся как есть
nonceнетпопадёт в id_token
displayнетpage или popup

Scope: openid — идентификатор, profile — имя и аватар, email — почта.

Обмен кода

Только с вашего сервера на сервер X-GRK ID.

POST https://id.x-grk.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=...
&redirect_uri=https://ваш.сайт/callback
&client_id=ВАШ_APP_NAME
&client_secret=ВАШ_APP_SECRET

Можно те же поля как app_name / app_secret. redirect_uri должен совпасть с тем, что уходил в authorize.

Ответ:

{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "eyJ...",
  "id_token": "eyJ...",
  "scope": "openid profile email"
}

Код одноразовый и живёт несколько минут. Повторный обмен того же кода не пройдёт.

Профиль

GET https://id.x-grk.com/oauth/userinfo
Authorization: Bearer ACCESS_TOKEN
{
  "sub": "XGRK-7K3N2P9Q1M",
  "name": "Анна",
  "preferred_username": "XGRK-7K3N2P9Q1M",
  "picture": "https://id.x-grk.com/avatar/XGRK-7K3N2P9Q1M",
  "email": "user@mail.test",
  "email_verified": false
}

Стабильный ключ пользователя — sub (X-GRK ID). Почта не подтверждается. picture и name есть при scope profile.

Минимальный Flask-колбэк:

@app.get("/callback")
def callback():
    if request.args.get("state") != session.get("state"):
        abort(400)
    token = exchange_code(request.args["code"])  # POST /oauth/token с app_secret
    profile = userinfo(token["access_token"])    # GET /oauth/userinfo
    session["user"] = profile["sub"]
    return redirect("/")

Обновление и отзыв

POST /oauth/token
grant_type=refresh_token
&refresh_token=...
&client_id=...
&client_secret=...

Старый refresh при этом отзывается. Access живёт 1 час, refresh — 30 дней либо до отзыва пользователем в кабинете.

POST /oauth/revoke
token=...
client_id=...
client_secret=...

Ошибки

На redirect: access_denied (пользователь отказал), invalid_scope, unsupported_response_type.

На токене: 401 invalid_client (неверный app_name/secret), 400 invalid_grant (код истёк, уже использован, не совпал redirect_uri).

Неизвестный клиент или чужой redirect не уводят браузер на ваш домен — это защита от open redirect.

PKCE

Для SPA или мобильного клиента добавьте code_challenge (S256) в authorize и code_verifier в token. Если challenge был задан, без верного verifier обмен не пройдёт.

Публичный клиент всё равно не должен держать app_secret в браузере: обмен кода делайте через свой бэкенд.