Перейти к основному содержимому

KukurukuID — интеграция OAuth 2.0

KukurukuID — это сервер аутентификации OAuth 2.0 / OpenID Connect. Мерчанты могут добавить кнопку «Войти через KukurukuID» на свои сайты, позволяя пользователям Kukuruku аутентифицироваться без создания новых аккаунтов.

Предварительные требования

Свяжитесь с командой Kukuruku для получения OAuth 2.0 учётных данных:

Учётные данныеОписание
client_idИдентификатор OAuth 2.0 клиента
client_secretСекрет OAuth 2.0 клиента (для конфиденциальных клиентов)
redirect_uriОдобренный callback URL для вашего приложения

Эндпоинты

URL сервера аутентификации: https://auth.kukuruku.win

ЭндпоинтURLМетод
Авторизация/realms/public/protocol/openid-connect/authGET
Токен/realms/public/protocol/openid-connect/tokenPOST
Информация о пользователе/realms/public/protocol/openid-connect/userinfoGET
Выход/realms/public/protocol/openid-connect/logoutPOST
JWKS/realms/public/protocol/openid-connect/certsGET
Discovery/realms/public/.well-known/openid-configurationGET

Поддерживаемые flows

FlowПрименение
Authorization CodeСерверные приложения (рекомендуется)
Authorization Code + PKCEКлиентские / SPA приложения

Authorization Code Flow (конфиденциальные клиенты)

Для серверных приложений, которые могут безопасно хранить client_secret.

Шаг 1: Редирект на логин

GET {auth_url}/realms/public/protocol/openid-connect/auth

Перенаправьте пользователя на страницу входа KukurukuID. После аутентификации пользователь будет перенаправлен обратно на ваш redirect_uri с кодом авторизации.

Параметры запроса:

ПараметрТипОбязательныйОписание
client_idstringДаИдентификатор вашего клиента
redirect_uristringДаЗарегистрированный callback URL
response_typestringДаДолжен быть code
scopestringНетScope'ы через пробел. По умолчанию: openid
statestringРекомендуетсяСлучайная строка для защиты от CSRF

Пример:

https://auth.kukuruku.win/realms/public/protocol/openid-connect/auth
?client_id=your-client-id
&redirect_uri=https://your-site.com/callback
&response_type=code
&scope=openid profile email
&state=random-state-string

После успешной аутентификации пользователь перенаправляется на:

https://your-site.com/callback
?code=c2a6dbb6-0640-4358-a047-8f87bde1d0ab.69eaf4bf-...
&session_state=69eaf4bf-58da-45e7-8ae7-92e6155e1ff8
&iss=https://auth.kukuruku.win/realms/public
&state=random-state-string

Шаг 2: Обмен кода на токены

POST {auth_url}/realms/public/protocol/openid-connect/token

Обменяйте код авторизации на access и refresh токены.

ПолеТипОбязательноеОписание
client_idstringДаИдентификатор вашего клиента
client_secretstringДаСекрет вашего клиента
grant_typestringДаДолжен быть authorization_code
codestringДаКод авторизации из Шага 1
redirect_uristringДаТот же redirect_uri, что и в Шаге 1

Ответ 200:

ПолеТипОписание
access_tokenstringJWT access token (TTL 5 минут)
refresh_tokenstringТокен для получения нового access token
token_typestringВсегда Bearer
id_tokenstringOpenID Connect ID токен с claims пользователя
expires_inintegerВремя жизни access token в секундах
scopestringВыданные scope'ы

Authorization Code Flow с PKCE (публичные клиенты)

Для клиентских (SPA) приложений, где хранение client_secret невозможно.

Шаг 1: Генерация Code Verifier и Challenge

Перед редиректом сгенерируйте случайную строку (code verifier) и её SHA-256 хеш (code challenge):

// Генерация code_verifier (43-128 символов, URL-safe)
const array = new Uint8Array(32);
crypto.getRandomValues(array);
const codeVerifier = btoa(String.fromCharCode(...array))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');

// Генерация code_challenge (SHA-256 хеш verifier)
const digest = await crypto.subtle.digest('SHA-256',
new TextEncoder().encode(codeVerifier));
const codeChallenge = btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');

Шаг 2: Редирект на логин

GET {auth_url}/realms/public/protocol/openid-connect/auth

Параметры запроса:

ПараметрТипОбязательныйОписание
client_idstringДаИдентификатор клиента
redirect_uristringДаЗарегистрированный callback URL
response_typestringДаДолжен быть code
code_challenge_methodstringДаДолжен быть S256
code_challengestringДаSHA-256 хеш code verifier
scopestringНетScope'ы через пробел
statestringРекомендуетсяСлучайная строка для CSRF защиты

Шаг 3: Обмен кода на токены

POST {auth_url}/realms/public/protocol/openid-connect/token

ПолеТипОбязательноеОписание
client_idstringДаИдентификатор клиента
grant_typestringДаДолжен быть authorization_code
codestringДаКод авторизации из Шага 2
redirect_uristringДаТот же redirect_uri, что и в Шаге 2
code_verifierstringДаИсходная случайная строка из Шага 1
примечание

Для публичных клиентов client_secret не нужен — code_verifier подтверждает, что запрос токена исходит от того же приложения, которое инициировало авторизацию.

Формат ответа идентичен ответу для конфиденциальных клиентов.


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

POST {auth_url}/realms/public/protocol/openid-connect/token

Access токены истекают через 5 минут. Используйте refresh token для получения новых токенов без повторной аутентификации пользователя.


User Context API

Получить текущего пользователя

GET /api/v1/me

Возвращает информацию о профиле аутентифицированного пользователя. Этот эндпоинт находится на API Kukuruku (https://api.kukuruku.win), а не на сервере аутентификации.

Ответ 200:

Поля ответа

ПолеТипОписание
idstringУникальный идентификатор пользователя в Kukuruku
first_namestring|nullИмя
middle_namestring|nullОтчество
last_namestring|nullФамилия
without_middle_namebooleanПользователь без отчества
date_of_birthstring|nullДата рождения (YYYY-MM-DD)
place_of_birthstring|nullМесто рождения
default_currencystringВалюта по умолчанию (RUB, USD, USDT)

Claims в JWT токене

Access token — подписанный JWT (RS256) со следующими claims:

ClaimТипОписание
substringUUID пользователя в Keycloak
emailstringEmail пользователя
email_verifiedbooleanПодтверждён ли email
namestringПолное имя
given_namestringИмя
family_namestringФамилия
user_idstringИдентификатор в Kukuruku (числовой)
preferred_usernamestringИмя пользователя (обычно email)
issstringURL издателя
expintegerВремя истечения (Unix timestamp)
Валидация JWT

Вы можете проверить подпись JWT через JWKS эндпоинт: GET https://auth.kukuruku.win/realms/public/protocol/openid-connect/certs


Доступные scope'ы

ScopeВключённые claims
openidsub, auth_time
profilename, given_name, family_name
emailemail, email_verified
phonephone_number, phone_number_verified
offline_accessДолгоживущие refresh токены

Пример: интеграция на Node.js

const express = require('express');
const axios = require('axios');

const AUTH_URL = 'https://auth.kukuruku.win/realms/public';
const CLIENT_ID = 'your-client-id';
const CLIENT_SECRET = 'your-client-secret';
const REDIRECT_URI = 'https://your-site.com/callback';

const app = express();

// Шаг 1: Редирект на логин
app.get('/login', (req, res) => {
const state = crypto.randomUUID();
const url = `${AUTH_URL}/protocol/openid-connect/auth` +
`?client_id=${CLIENT_ID}` +
`&redirect_uri=${encodeURIComponent(REDIRECT_URI)}` +
`&response_type=code` +
`&scope=openid+profile+email` +
`&state=${state}`;
res.redirect(url);
});

// Шаг 2: Обмен кода на токены
app.get('/callback', async (req, res) => {
const { code } = req.query;

const tokenResponse = await axios.post(
`${AUTH_URL}/protocol/openid-connect/token`,
new URLSearchParams({
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
grant_type: 'authorization_code',
code,
redirect_uri: REDIRECT_URI,
}),
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
);

const { access_token } = tokenResponse.data;

// Шаг 3: Получение профиля пользователя
const userResponse = await axios.get(
'https://api.kukuruku.win/api/v1/me',
{ headers: { Authorization: `Bearer ${access_token}` } }
);

const user = userResponse.data.data;
// user.id, user.first_name, user.email и т.д.
// Найти или создать пользователя в вашей системе по user.id
});

Частые ошибки

ОшибкаПричинаРешение
invalid_grantКод авторизации истёк (>60 сек) или уже использованПовторно инициировать flow авторизации
invalid_clientНеверный client_secretПроверьте учётные данные
unauthorized_clientКлиент не настроен для этого grant typeОбратитесь к команде Kukuruku
invalid_redirect_uriredirect_uri не зарегистрированОбратитесь к команде Kukuruku для добавления URI