alexec0de ID
В дашборд
OAuth 2.0 · OpenID Connect

Документация alexec0de ID

Добавьте кнопку «Войти через alexec0de ID» на свой сайт за пару минут. Единственный поддерживаемый флоу — Authorization Code + PKCE (S256).

Введение

alexec0de ID — провайдер входа на базе OAuth 2.0 и OpenID Connect. Реализован только Authorization Code Grant с PKCE; методS256 обязателен. Небезопасные потоки (Implicit, Resource Owner Password) не поддерживаются намеренно.

RS256

JWT-подпись, ключи в JWKS

15 мин

жизнь access-токена

ротация

refresh с детекцией повтора

Быстрый старт

От нуля до рабочей кнопки за 3 шага

  1. 1Создайте приложение в дашборде — укажите название, redirect_uri и scopes.
  2. 2Сохраните client_id и client_secret (секрет показывается один раз).
  3. 3Вставьте виджет кнопки на сайт — см. раздел «Кнопка входа».

Эндпоинты

Базовый URL: https://id.alexec0de.lol

GET/oauth/authorizeвход + согласие, редирект с code
POST/oauth/tokenобмен code / refresh на токены
GET/oauth/userinfoпрофиль по access-токену
POST/oauth/revokeотзыв токена (RFC 7009)
POST/oauth/introspectпроверка токена (RFC 7662)
GET/.well-known/openid-configurationdiscovery
GET/.well-known/jwks.jsonпубличные ключи RS256

Scopes

ScopeДоступClaims
openidИдентификация (id_token)sub
profileНикнейм и аватарnickname, preferred_username, picture
emailЭлектронная почтаemail, email_verified

Умная кнопка входа

npm-пакет @alexec0de/id-widget — vanilla, React и Vue

Кнопка — отдельный npm-пакет @alexec0de/id-widget: чистый JS/TS, компоненты React и Vue 3, а также бандл для вставки через <script>. Она тихо проверяет сессию через скрытый iframe: если пользователь уже давал доступ вашему приложению, кнопка превращается в «Продолжить как @nickname», и вход происходит мгновенно (prompt=none), без экрана согласия.

Установка

bash
npm i @alexec0de/id-widget

React

tsx
import { AxidLoginButton } from "@alexec0de/id-widget/react";

<AxidLoginButton
  clientId="axid_ВАШ_CLIENT_ID"
  baseUrl="https://id.alexec0de.lol"
  redirectUri="https://your.app/callback"
  scope="openid profile email"
/>

Vue 3

vue
import { AxidLoginButton } from "@alexec0de/id-widget/vue";

<AxidLoginButton
  client-id="axid_ВАШ_CLIENT_ID"
  base-url="https://id.alexec0de.lol"
  redirect-uri="https://your.app/callback"
  scope="openid profile email"
/>

Чистый HTML (без сборки)

html
<div id="alexec0de-id-button"></div>
<script src="https://unpkg.com/@alexec0de/id-widget/dist/axid-widget.global.js"
        data-client-id="axid_ВАШ_CLIENT_ID"
        data-base-url="https://id.alexec0de.lol"
        data-redirect-uri="https://your.app/callback"
        data-scope="openid profile email"></script>

На странице callback

ts
import { readCallback } from "@alexec0de/id-widget";

const r = readCallback();          // проверит state и достанет verifier
if (r.ok) {
  await fetch("/api/oauth/exchange", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ code: r.code, codeVerifier: r.codeVerifier }),
  });
}

PKCE (S256) генерируется в браузере; code_verifier и state кладутся в sessionStorage. Опции: theme (dark/light), variant (button/icon), authorizeUrl (серверный старт флоу). Обмен кода на токены делайте на своём бэкенде — см. «Флоу вручную».

Флоу вручную

Если нужен полный контроль

1. Отправьте пользователя на авторизацию

js
const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)));
const challenge = base64url(await crypto.subtle.digest(
  "SHA-256", new TextEncoder().encode(verifier)));

location.href = "https://id.alexec0de.lol/oauth/authorize?" + new URLSearchParams({
  response_type: "code",
  client_id: "axid_ВАШ_CLIENT_ID",
  redirect_uri: "https://your.app/auth/callback",
  scope: "openid profile email",
  state: randomState,
  code_challenge: challenge,
  code_challenge_method: "S256",
});

2. Обменяйте code на токены (с сервера)

bash
curl -X POST https://id.alexec0de.lol/oauth/token \
  -u "axid_ВАШ_CLIENT_ID:axsec_ВАШ_SECRET" \
  -d grant_type=authorization_code \
  -d code=ПОЛУЧЕННЫЙ_CODE \
  -d redirect_uri=https://your.app/auth/callback \
  -d code_verifier=СОХРАНЁННЫЙ_VERIFIER
json
{
  "access_token": "eyJ...",     // JWT RS256, 15 минут
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_token": "axrt_...",  // ротируется при каждом обновлении
  "scope": "openid profile email",
  "id_token": "eyJ..."          // при scope openid
}

3. Получите профиль

bash
curl https://id.alexec0de.lol/oauth/userinfo -H "Authorization: Bearer ACCESS_TOKEN"

4. Обновляйте токены (важно: ротация)

bash
curl -X POST https://id.alexec0de.lol/oauth/token \
  -u "axid_ВАШ_CLIENT_ID:axsec_ВАШ_SECRET" \
  -d grant_type=refresh_token -d refresh_token=axrt_...

Каждый refresh возвращает новый refresh_token, старый гаснет. Повторное предъявление погашенного токена считается компрометацией — вся цепочка токенов пары пользователь+клиент отзывается.

Passkeys (2FA / вход без пароля)

Отпечаток, Face ID или аппаратный ключ вместо пароля

Пользователи могут привязать passkey в разделе Профиль и затем входить по нему одним касанием — без пароля. Реализовано по стандарту WebAuthn: приватный ключ никогда не покидает устройство, сервер хранит только публичный ключ и счётчик подписи (защита от клонирования).

На экране входа появляется кнопка «Войти по passkey». Это надёжная замена паролю и одновременно второй фактор: доступ подтверждается биометрией или PIN устройства.

Безопасность и детали

  • redirect_uri сравнивается побайтово: без вайлдкардов, слэш в конце имеет значение.
  • code живёт 60 секунд, одноразовый; повторный обмен отзывает выданные токены.
  • PKCE: поддерживается только S256, метод plain отклоняется.
  • Авторизация клиента: client_secret_basic или client_secret_post.
  • Rate limiting: /oauth/token — 30 запросов/мин, /oauth/authorize — 60/мин с одного IP.
  • prompt=none возвращает login_required / consent_required без показа UI.
  • Подпись токенов — RS256; проверяйте по /.well-known/jwks.json (kid в заголовке JWT).
  • Заблокированные модератором аккаунты и сервисы не могут проходить авторизацию, их токены отзываются.

Готовы начать?

Создать приложение →