Интеграция автоматического входа (кнопка «Играть»)
Когда пользователь нажимает кнопку «Играть» на карточке мерчанта в Kukuruku, система автоматически создаёт и оплачивает ордер, затем перенаправляет пользователя на платформу мерчанта с параметрами аутентификации. Это обеспечивает бесшовный опыт в один клик.
Предварительные требования
Для поддержки автоматического входа необходимо настроить:
- Платёжную интеграцию (для получения callback'ов)
- KukurukuID OAuth 2.0 (для аутентификации пользователей)
Как это работает
Пользователь нажимает «Играть» на Kukuruku
|
v
Kukuruku создаёт ордер (POST /api/v1/orders/payins)
|
v
Kukuruku оплачивает ордер из баланса KukuPay пользователя
|
v
Пользователь перенаправляется на вашу платформу с параметрами:
https://your-site.com/?auto_login=true&custom4=...&order_id=...
|
v
Ваша платформа обнаруживает auto_login=true
|
v
Ваша платформа инициирует OAuth вход через issuer из custom4
|
v
Пользователь аутентифицирован, баланс зачислен через callback
Параметры редиректа
При перенаправлении пользователя на вашу платформу URL включает следующие параметры:
Параметры аутентификации
| Параметр | Значение | Описание |
|---|---|---|
auto_login | true | Указывает, что это автоматический вход |
joker_login | true | Подтверждает, что редирект от Kukuruku |
custom4 | https://auth.kukuruku.win/realms/public | URL издателя KukurukuID — используйте для OAuth аутентификации |
Параметры ордера
| Параметр | Значение | Описание |
|---|---|---|
order_id | UUID | Идентификатор ордера в KukuPay |
custom2 | UUID | То же, что order_id (дубликат для совместимости) |
Параметры трекинга
| Параметр | Описание |
|---|---|
sub_id1 | Идентификатор аффилиата |
sub_id2 | Источник трафика |
sub_id3 | Идентификатор ссылки |
sub_id4 | Идентификатор креатива |
sub_id5 | UUID пользователя |
aff_click_id | Идентификатор клика аффилиата |
custom1 | Тестовый флаг |
custom3 | Всегда true |
Пример URL
https://your-site.com/login?
auto_login=true&
joker_login=true&
custom3=true&
custom4=https%3A%2F%2Fauth.kukuruku.win%2Frealms%2Fpublic&
order_id=550e8400-e29b-41d4-a716-446655440000&
custom2=550e8400-e29b-41d4-a716-446655440000&
sub_id5=7e77c7af-50a1-411d-8e3c-5eeda15891fc
Руководство по реализации
Шаг 1: Обнаружение автовхода
Проверяйте параметр auto_login=true на вашей целевой странице:
const params = new URLSearchParams(window.location.search);
if (params.get('auto_login') === 'true') {
const issuerUrl = params.get('custom4');
const orderId = params.get('order_id');
// Инициировать OAuth вход
initiateKukurukuLogin(issuerUrl, orderId);
}
Шаг 2: Аутентификация через KukurukuID
Используйте параметр custom4 как URL издателя OAuth для инициации Authorization Code Flow:
function initiateKukurukuLogin(issuerUrl, orderId) {
const state = JSON.stringify({ orderId });
const authUrl = `${issuerUrl}/protocol/openid-connect/auth` +
`?client_id=${YOUR_CLIENT_ID}` +
`&redirect_uri=${encodeURIComponent(YOUR_CALLBACK_URL)}` +
`&response_type=code` +
`&scope=openid+profile+email` +
`&state=${encodeURIComponent(state)}`;
window.location.href = authUrl;
}
Шаг 3: Обработка OAuth callback
Обменяйте код авторизации на токены и идентифицируйте пользователя:
app.get('/callback', async (req, res) => {
const { code, state } = req.query;
const { orderId } = JSON.parse(state);
// Обмен кода на токены
const tokens = await exchangeCodeForTokens(code);
// Получение профиля пользователя
const user = await getUserProfile(tokens.access_token);
// Найти или создать пользователя по email
const localUser = await findOrCreateUser(user.data.email);
// Сохранить контекст ордера для сопоставления с callback'ом
await storeOrderContext(orderId, localUser.id);
// Перенаправить на платформу
res.redirect('/dashboard');
});
Шаг 4: Обработка callback оплаты
Kukuruku асинхронно отправляет callback оплаты. При получении:
app.post('/kukuruku/callback', (req, res) => {
// 1. Проверить подпись
const isValid = verifySignature(req.body, req.headers.signature);
if (!isValid) return res.status(401).json({ success: false });
// 2. Найти пользователя по email из callback'а
const user = findUserByEmail(req.body.user_email);
// 3. Зачислить баланс
if (req.body.status === 'paid') {
creditUserBalance(user.id, req.body.amount, req.body.currency);
}
res.json({ success: true });
});
Callback оплаты и редирект пользователя могут прийти в любом порядке. Ваша реализация должна обрабатывать оба сценария:
- Пользователь приходит первым, callback позже — создать сессию, зачислить баланс при получении callback'а
- Callback приходит первым, пользователь позже — зачислить баланс, создать сессию при появлении пользователя
Используйте user_email из callback'а для сопоставления с пользователем, аутентифицированным через OAuth.
Настройка URL мерчанта
URL вашей платформы настраивается в системе Kukuruku. Каждый мерчант может иметь несколько URL (для A/B тестирования или балансировки нагрузки). Система выбирает один случайным образом при каждом редиректе.
Свяжитесь с командой Kukuruku для регистрации или обновления URL вашей платформы.
Полный пример (Express.js)
const express = require('express');
const axios = require('axios');
const sha512 = require('js-sha512').sha512;
const AUTH_URL = 'https://auth.kukuruku.win/realms/public';
const API_URL = 'https://api.kukuruku.win';
const CLIENT_ID = 'your-client-id';
const CLIENT_SECRET = 'your-client-secret';
const SECRET_KEY = 'your-merchant-secret-key';
const CALLBACK_URL = 'https://your-site.com/auth/callback';
const app = express();
app.use(express.json());
// Целевая страница — обнаружение автовхода
app.get('/', (req, res) => {
if (req.query.auto_login === 'true') {
const issuer = req.query.custom4;
const orderId = req.query.order_id;
const state = Buffer.from(JSON.stringify({ orderId })).toString('base64');
return res.redirect(
`${issuer}/protocol/openid-connect/auth` +
`?client_id=${CLIENT_ID}` +
`&redirect_uri=${encodeURIComponent(CALLBACK_URL)}` +
`&response_type=code` +
`&scope=openid+profile+email` +
`&state=${state}`
);
}
res.render('home');
});
// OAuth callback
app.get('/auth/callback', async (req, res) => {
const { code, state } = req.query;
const { orderId } = JSON.parse(
Buffer.from(state, 'base64').toString()
);
// Обмен кода на токены
const { data: tokens } = 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: CALLBACK_URL,
})
);
// Получение профиля из API Kukuruku
const { data: profile } = await axios.get(`${API_URL}/api/v1/me`, {
headers: { Authorization: `Bearer ${tokens.access_token}` },
});
// Найти или создать пользователя
const user = await findOrCreateUser({
kukurukuId: profile.data.id,
name: profile.data.first_name,
});
// Создать сессию
req.session.userId = user.id;
req.session.orderId = orderId;
res.redirect('/dashboard');
});
// Callback оплаты от Kukuruku
app.post('/kukuruku/callback', (req, res) => {
// Проверка HMAC-SHA512 подписи
const expectedSignature = sha512.hmac(
SECRET_KEY, JSON.stringify(req.body)
);
if (expectedSignature !== req.headers.signature) {
return res.status(401).json({ success: false });
}
// Обработка платежа
if (req.body.status === 'paid') {
creditBalance(req.body.user_email, req.body.amount, req.body.currency);
}
res.json({ success: true });
});