API
Документация бесплатного и открытого API системы аутентификации. Интегрируйте единую систему идентификации в ваши сервисы и приложения через OAuth 2.0, REST API и SDK.
https://id.tokenpay.space/api/v1
API использует JSON для всех запросов и ответов. Все запросы должны содержать заголовок Content-Type: application/json.
Быстрый старт
Для начала работы с API вам нужно:
1. Создать аккаунт TOKEN PAY ID
2. Получить API ключи в личном кабинете
3. Использовать секретный ключ для серверных запросов
curl -X GET https://id.tokenpay.space/api/v1/users/me \ -H "Authorization: Bearer tpid_sk_your_secret_key" \ -H "Content-Type: application/json"
Аутентификация
TOKEN PAY ID API поддерживает два метода аутентификации:
API ключи
Используйте секретный ключ (tpid_sk_...) в заголовке Authorization:
Authorization: Bearer tpid_sk_ваш_секретный_ключ
OAuth 2.0 Bearer Token
Для пользовательских запросов используйте access_token полученный через OAuth 2.0 flow:
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Лимиты запросов
API имеет следующие ограничения:
| Тарифный план | Запросов/мин | Запросов/день |
|---|---|---|
| Free | 60 | 10,000 |
| Pro | 300 | 100,000 |
| Enterprise | 1,000 | Unlimited |
Заголовки ответа содержат информацию о лимитах:
X-RateLimit-Limit: 60 X-RateLimit-Remaining: 45 X-RateLimit-Reset: 1678886400
Коды ошибок
API возвращает стандартные HTTP коды и JSON-объект ошибки:
{
"error": {
"code": "invalid_token",
"message": "The access token is invalid or expired",
"status": 401
}
}
| Код | Описание |
|---|---|
| 400 | Некорректный запрос |
| 401 | Неавторизован — неверный или отсутствующий токен |
| 403 | Запрещено — недостаточно прав |
| 404 | Ресурс не найден |
| 429 | Превышен лимит запросов |
| 500 | Внутренняя ошибка сервера |
OAuth 2.0 — Авторизация
TOKEN PAY ID поддерживает стандартный OAuth 2.0 Authorization Code flow для безопасной авторизации пользователей в сторонних сервисах.
Шаг 1: Redirect к авторизации
Перенаправьте пользователя на страницу авторизации:
https://id.tokenpay.space/api/v1/oauth/authorize? client_id=tpid_pk_your_public_key& redirect_uri=https://yourapp.com/callback& response_type=code& scope=profile email& state=random_csrf_token& prompt=login& code_challenge=SHA256_HASH& code_challenge_method=S256
code_challenge и code_challenge_method=S256 являются обязательными для всех клиентов. Запросы без PKCE будут отклонены.
| Параметр | Тип | Описание |
|---|---|---|
| client_id | string | required — Публичный ключ |
| redirect_uri | string | required — URL для редиректа |
| response_type | string | required — Только code |
| scope | string | Запрашиваемые разрешения (по умолч. profile) |
| state | string | CSRF-токен (рекомендуется) |
| prompt | string | login — принудительная переавторизация, consent, none |
| login_hint | string | Email для предзаполнения формы входа |
| code_challenge | string | required — PKCE challenge (SHA-256 хеш code_verifier) |
| code_challenge_method | string | required — Только S256 |
Шаг 2: Обмен кода на токен
После авторизации пользователь будет перенаправлен на ваш redirect_uri с параметром code. Обменяйте его на access_token:
POST /oauth/token
Обмен authorization code на access token.
| Параметр | Тип | Описание |
|---|---|---|
| grant_type | string | required — authorization_code или refresh_token |
| code | string | required — Authorization code |
| client_id | string | required — Ваш публичный ключ |
| client_secret | string | Секретный ключ (обязателен для confidential-клиентов, не нужен для public + PKCE) |
| redirect_uri | string | required — Должен совпадать с исходным |
| code_verifier | string | required — PKCE verifier (случайная строка 43–128 символов, из которой был создан code_challenge) |
curl -X POST https://id.tokenpay.space/api/v1/oauth/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "authorization_code", "code": "abc123...", "client_id": "tpid_pk_...", "client_secret": "tpid_sk_...", "redirect_uri": "https://yourapp.com/callback", "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" }'
Ответ
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "tpid_rt_8a7b6c5d...",
"scope": "profile email",
"user": {
"id": "tpid_usr_a1b2c3d4",
"email": "[email protected]",
"name": "Иван",
"email_verified": true
}
}
POST /oauth/revoke
Отзыв access или refresh токена.
| Параметр | Тип | Описание |
|---|---|---|
| token | string | required — Токен для отзыва |
| token_type_hint | string | access_token или refresh_token |
GET /oauth/userinfo
Получить профиль пользователя по OAuth access token. Возвращает данные в зависимости от запрошенного scope.
curl -X GET https://tokenpay.space/api/v1/oauth/userinfo \ -H "Authorization: Bearer ACCESS_TOKEN"
{
"id": "tpid_usr_a1b2c3d4e5f6",
"email": "[email protected]",
"name": "Иван",
"role": "user",
"email_verified": true,
"locale": "ru",
"theme": "dark",
"telegram_linked": true,
"cupol_balance": 150,
"cupol_subscription_active": true,
"created_at": "2026-01-15T12:00:00Z"
}
POST /oauth/cancel
Уведомить enterprise о том, что пользователь закрыл окно согласия (вызывается автоматически через sendBeacon). Запускает webhook user.oauth_cancel.
| Параметр | Тип | Описание |
|---|---|---|
| client_id | string | required |
| reason | string | Причина: window_closed, user_cancel |
POST /oauth/deny
Пользователь явно отклонил запрос на авторизацию. Запускает webhook user.oauth_deny и перенаправляет с ошибкой access_denied.
| Параметр | Тип | Описание |
|---|---|---|
| client_id | string | required |
| redirect_uri | string | required |
| state | string | Передаётся обратно в redirect |
GET /oauth/branding
Получить конфигурацию кнопок, иконки и готовый код для интеграции виджета TOKEN PAY ID. Не требует аутентификации.
{
"provider": "TOKEN PAY ID",
"widget_url": "https://tokenpay.space/sdk/tpid-widget.js",
"widget_version": "1.2.0",
"icon": { "shield_svg": "<svg ...>" },
"buttons": {
"standard": { "label": "Войти через TOKEN PAY", ... },
"icon": { "shape": "circle", ... },
"logo": { "background": "transparent", ... }
},
"integration": {
"quick_start": "<script src=... data-client-id=...>",
"oauth_popup": "TPID.loginWithOAuth().then(...);"
},
"themes": ["dark", "light", "auto"],
"languages": ["ru", "en"]
}
POST /oauth/register — Dynamic Client Registration (RFC 7591)
Зарегистрировать новый OAuth-клиент программно. Требуется авторизация (Bearer token или API ключ).
| Параметр | Тип | Описание |
|---|---|---|
| client_name | string | required — Название приложения |
| redirect_uris | string[] | required — Массив разрешённых redirect URI |
| client_type | string | public или confidential (по умолч. public) |
| client_uri | string | URL сайта приложения |
| logo_uri | string | URL логотипа |
| tos_uri | string | URL условий использования |
| policy_uri | string | URL политики конфиденциальности |
| contacts | string | Контактные email (через запятую) |
| scope | string | Запрашиваемые scope: openid, profile, email |
{
"client_id": "tpid_pk_...",
"client_secret": "tpid_sk_...",
"client_name": "My App",
"redirect_uris": ["https://myapp.com/callback"],
"client_type": "public",
"registration_access_token": "Bearer ..."
}
client_secret показывается только один раз при регистрации. Сохраните его.
GET /oauth/client-info/:client_id
Получить метаданные зарегистрированного OAuth-клиента. Доступно только владельцу ключа.
{
"client_id": "tpid_pk_...",
"client_name": "My App",
"client_type": "public",
"redirect_uris": ["https://myapp.com/callback"],
"client_uri": "https://myapp.com",
"logo_uri": null,
"tos_uri": null,
"policy_uri": null,
"scope": "openid,profile,email"
}
Пользователи
GET /users/me
Получить профиль текущего авторизованного пользователя.
{
"id": "tpid_usr_a1b2c3d4",
"email": "[email protected]",
"name": "Иван Чернов",
"email_verified": true,
"two_factor_enabled": false,
"telegram_linked": true,
"created_at": "2025-01-15T10:30:00Z",
"last_login": "2026-03-13T09:45:00Z"
}
PUT /users/me
Обновить профиль пользователя.
| Параметр | Тип | Описание |
|---|---|---|
| name | string | Имя пользователя |
| avatar_url | string | URL аватара |
GET /users/activity
История активности пользователя: входы, API вызовы, изменения безопасности.
| Параметр | Тип | Описание |
|---|---|---|
| limit | integer | Количество записей (по умолчанию 50, максимум 200) |
| offset | integer | Смещение для пагинации |
| type | string | Фильтр: auth, api, security |
GET /users/sessions
Список активных сессий пользователя.
{
"sessions": [
{
"id": "ses_abc123",
"device": "Chrome — Windows",
"ip": "192.168.1.1",
"location": "Saint Petersburg, RU",
"last_active": "2026-03-13T12:00:00Z",
"current": true
}
]
}
Auth
POST /auth/send-code
Отправить 6-значный код верификации на email. Используется перед регистрацией и при входе.
| Параметр | Тип | Описание |
|---|---|---|
| string | required — Email адрес | |
| type | string | required — register или login |
{
"success": true,
"message": "Verification code sent",
"expires_in": 600
}
POST /auth/verify
Верификация access токена. Используется сторонними сервисами для проверки авторизации пользователя.
| Параметр | Тип | Описание |
|---|---|---|
| token | string | required — Access token для проверки |
{
"valid": true,
"user_id": "tpid_usr_a1b2c3d4",
"email": "[email protected]",
"scopes": ["profile", "email"],
"expires_at": 1678886400
}
POST /auth/register
Регистрация нового пользователя. Требуется предварительная отправка кода через /auth/send-code.
| Параметр | Тип | Описание |
|---|---|---|
| string | required | |
| password | string | required — Минимум 8 символов |
| name | string | required |
| email_code | string | required — 6-значный код из email (от /auth/send-code) |
POST /auth/send-code с type: "register".
POST /auth/login
Двухэтапная авторизация. Первый вызов с email+password отправляет код на почту и возвращает requires_email_code: true. Второй вызов с email+password+email_code завершает авторизацию.
| Параметр | Тип | Описание |
|---|---|---|
| string | required | |
| password | string | required |
| email_code | string | 6-значный код из email (обязателен на втором шаге) |
| two_factor_code | string | TOTP код, если 2FA включена |
Шаг 1 — отправка пароля:
{
"requires_email_code": true,
"requires_2fa": false,
"message": "Verification code sent to your email"
}
Шаг 2 — подтверждение кода:
Повторите запрос, добавив email_code. При успехе возвращается access/refresh token и данные пользователя.
POST /auth/refresh
Обновление access токена с помощью refresh токена.
| Параметр | Тип | Описание |
|---|---|---|
| refresh_token | string | required |
QR-вход
Двухэтапный вход через QR-код: десктоп генерирует сессию, мобильное устройство (с активной авторизацией) подтверждает.
1. Инициализация QR-сессии
Создаёт QR-сессию (не требует авторизации). Возвращает sessionId и URL для QR-кода.
{
"sessionId": "uuid-...",
"ttl": 300,
"qrUrl": "https://tokenpay.space/qr-login?sid=uuid-..."
}
2. Polling (десктоп)
Десктоп опрашивает каждые 2 секунды. Статус: pending → approved → возвращает токены.
3. Подтверждение (мобильное устройство)
Требует Authorization: Bearer. Мобильное устройство подтверждает вход.
status: "expired".
API ключи
GET /keys
Получить список API ключей пользователя.
POST /keys
Создать новый API ключ.
| Параметр | Тип | Описание |
|---|---|---|
| name | string | required — Название ключа |
| scopes | string[] | Массив разрешений |
DELETE /keys/:id
Отозвать (удалить) API ключ. Все запросы с этим ключом немедленно перестанут работать.
Webhooks
Webhooks позволяют получать уведомления о событиях TOKEN PAY ID в реальном времени. Настройте URL вашего сервера в личном кабинете.
Каждый webhook запрос содержит подпись в заголовке X-TPID-Signature формата Stripe-style для верификации подлинности:
X-TPID-Signature: t=1711000000,v1=hmac_sha256_hex
Для проверки подписи:
const crypto = require('crypto'); function verifyWebhook(body, signature, secret) { const parts = {}; signature.split(',').forEach(p => { const [k, v] = p.split('='); parts[k] = v; }); const expected = crypto .createHmac('sha256', secret) .update(parts.t + '.' + JSON.stringify(body)) .digest('hex'); return parts.v1 === expected; }
t (timestamp) — отклоняйте запросы старше 5 минут.
Payload
{
"event": "user.login",
"timestamp": "2026-03-13T12:00:00Z",
"data": {
"user_id": "tpid_usr_a1b2c3d4",
"ip": "192.168.1.1",
"device": "Chrome — Windows"
}
}
Доступные события
| Событие | Описание |
|---|---|
| user.register | Новая регистрация пользователя |
| user.login | Успешный вход в аккаунт |
| user.logout | Выход из аккаунта |
| user.updated | Профиль обновлён |
| user.deleted | Аккаунт удалён |
| user.2fa.enabled | 2FA включена |
| user.2fa.disabled | 2FA отключена |
| key.created | Создан новый API ключ |
| key.revoked | API ключ отозван |
| session.created | Новая сессия |
| session.revoked | Сессия завершена |
| token.refreshed | Токен обновлён |
| user.oauth_connect | Пользователь одобрил OAuth авторизацию |
| user.oauth_cancel | Пользователь закрыл окно OAuth |
| user.oauth_deny | Пользователь отклонил OAuth запрос |
Push Notifications API
Система push-уведомлений позволяет получать уведомления в реальном времени через SSE (Server-Sent Events) или через REST API.
Получить историю уведомлений (последние 50). Требует Authorization: Bearer <token>.
{
"notifications": [
{ "id": "...", "type": "oauth_connect", "title": "New user connected", "body": "[email protected] authorized via OAuth", "is_read": false, "created_at": "2026-04-02T12:00:00Z" }
],
"unread": 3
}Отметить уведомление как прочитанное.
Отметить все уведомления как прочитанные.
SSE Stream (Server-Sent Events)
Подключение к потоку уведомлений в реальном времени. JWT передаётся через query-параметр (EventSource не поддерживает заголовки).
const es = new EventSource('/api/v1/notifications/stream?token=' + token); es.addEventListener('notification', e => { const data = JSON.parse(e.data); console.log(data.event, data.data.title); }); es.addEventListener('connected', e => { console.log('SSE connected', JSON.parse(e.data)); });
oauth_connect, oauth_cancelled, oauth_denied, key_created, key_revoked, user_unlink
Widget SDK v1.2 — Быстрый старт
Виджет TOKEN PAY ID предоставляет три варианта кнопок для интеграции: стандартная, круглая иконка и прозрачный логотип. Все кнопки автоматически работают с OAuth 2.0 + PKCE.
https://tokenpay.space/sdk/tpid-widget.jsВерсия 1.2.0 — автообновления, без кэширования.
Минимальная интеграция (1 строка)
<script src="https://tokenpay.space/sdk/tpid-widget.js" data-client-id="tpid_pk_ваш_ключ"></script>
Виджет автоматически создаст кнопку «Войти через TOKEN PAY» на странице.
OAuth Popup Flow (Promise API)
Метод TPID.loginWithOAuth() открывает popup, проводит OAuth flow и возвращает Promise с authorization code.
TPID.loginWithOAuth({ prompt: 'login' })
.then(function(result) {
console.log('Auth code:', result.code);
console.log('State:', result.state);
// Отправьте code на ваш сервер для обмена на токен
})
.catch(function(err) {
console.error('OAuth error:', err);
});
Программный API (TPID)
| Метод | Описание |
|---|---|
| TPID.init(opts) | Инициализация с clientId, redirectUri, onSuccess, onError, lang, autoButton |
| TPID.open() | Открыть окно авторизации (redirect flow) |
| TPID.loginWithOAuth(opts) | OAuth popup flow → Promise<{code, state}> |
| TPID.renderButton(el, opts) | Рендер стандартной кнопки в контейнер |
| TPID.renderIconButton(el, opts) | Рендер круглой иконки |
| TPID.renderLogoButton(el, opts) | Рендер прозрачной кнопки-логотипа |
| TPID.version | Текущая версия виджета (1.2.0) |
SDK — JavaScript v2.0 (tokenpay-auth.js)
OAuth SDK с автоматической генерацией PKCE (S256). Рекомендуется как основной SDK для серверных и SPA-приложений. Для простой интеграции кнопок см. Widget SDK v1.2.
https://tokenpay.space/sdk/tokenpay-auth.jsv2.0.0 — PKCE (S256) генерируется автоматически. code_verifier сохраняется в sessionStorage.
Два типа кнопок
| Тип | Вид | Описание |
|---|---|---|
| icon | data-mode="icon" | Круглая иконка (щит TOKEN PAY) — как у Google/Apple. Размеры: 36×36 / 44×44 / 54×54 px |
| logo | data-mode="logo" | Прямоугольная кнопка с иконкой + текст «Войти через TOKEN PAY». Min/max ширина ограничена. |
1. Быстрое подключение (data-атрибуты)
<!-- Прямоугольная кнопка с текстом --> <script src="https://tokenpay.space/sdk/tpid-auth.js" data-client-id="tpid_pk_ваш_ключ" data-redirect-uri="https://ваш-сайт.com/callback" data-mode="logo" data-theme="dark" data-size="medium" data-lang="ru"> </script>
<!-- Круглая иконка --> <script src="https://tokenpay.space/sdk/tpid-auth.js" data-client-id="tpid_pk_ваш_ключ" data-redirect-uri="https://ваш-сайт.com/callback" data-mode="icon" data-theme="light" data-size="large"> </script>
2. Программный API
// Инициализация TokenPayAuth.init({ clientId: 'tpid_pk_ваш_ключ', redirectUri: 'https://ваш-сайт.com/callback', theme: 'dark', locale: 'ru', onSuccess: function(data) { console.log('Код:', data.code); console.log('Verifier:', data.codeVerifier); // Отправьте code + codeVerifier на ваш сервер } }); // Рендер кнопки в контейнер TokenPayAuth.renderButton('#my-container', { mode: 'button', // 'button' | 'icon' theme: 'dark', // 'dark' | 'light' | 'auto' size: 'medium', // 'small' | 'medium' | 'large' locale: 'ru' }); // Или запуск OAuth вручную (PKCE генерируется автоматически) TokenPayAuth.authorize(); // Получить code_verifier для серверного обмена const verifier = TokenPayAuth.getCodeVerifier();
3. Обмен кода на токен (серверная сторона)
curl -X POST https://tokenpay.space/api/v1/oauth/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "authorization_code", "code": "tpid_code_...", "client_id": "tpid_pk_...", "client_secret": "tpid_sk_...", "redirect_uri": "https://ваш-сайт.com/callback", "code_verifier": "PKCE_VERIFIER" }'
4. Получение профиля пользователя
curl -X GET https://tokenpay.space/api/v1/oauth/userinfo \ -H "Authorization: Bearer ACCESS_TOKEN"
{
"id": "tpid_usr_a1b2c3d4e5f6",
"email": "[email protected]",
"name": "Иван",
"email_verified": true,
"created_at": "2026-01-15T12:00:00Z"
}
Параметры
| Параметр / Атрибут | Тип | Описание |
|---|---|---|
| clientId / data-client-id | string | required — Публичный ключ API (tpid_pk_...) |
| redirectUri / data-redirect-uri | string | required — URL для редиректа после авторизации |
| mode / data-mode | string | Тип кнопки: icon (круглая) или logo (прямоугольная, по умолчанию) |
| theme / data-theme | string | Тема: dark (белая кнопка), light (тёмная кнопка), auto |
| size / data-size | string | Размер: small (36px), medium (44px), large (54px) |
| lang / data-lang | string | Язык: ru или en |
| scope / data-scope | string | OAuth scope (по умолчанию openid email profile) |
| onSuccess | function | Callback: ({code, state, type}) => {} |
| onError | function | Callback при ошибке |
Ограничения размеров
| Режим | Small | Medium | Large |
|---|---|---|---|
| icon | 36×36 px | 44×44 px | 54×54 px |
| logo | h:36, w:180–320 px | h:44, w:220–400 px | h:54, w:260–480 px |
SDK — Python
pip install tokenpay-id
from tokenpay_id import TokenPayID client = TokenPayID( client_id="tpid_pk_your_public_key", client_secret="tpid_sk_your_secret_key" ) # Verify a user's token result = client.verify(access_token) print(result.user_id) # tpid_usr_... # Get user profile user = client.get_user(access_token) print(user.email) # [email protected] # Webhook signature verification is_valid = client.verify_webhook( payload=request.body, signature=request.headers["X-TPID-Signature"] )
SDK — Go
go get github.com/tokenpay/id-go
package main import ( tpid "github.com/tokenpay/id-go" ) func main() { client := tpid.NewClient(tpid.Config{ ClientID: "tpid_pk_your_public_key", ClientSecret: "tpid_sk_your_secret_key", }) // Verify token result, err := client.Verify(accessToken) if err != nil { log.Fatal(err) } fmt.Println(result.UserID) // tpid_usr_... }
SDK — Kotlin / Android
implementation("space.tokenpay:id-sdk:2.2.0")
import space.tokenpay.id.TokenPayID val client = TokenPayID( clientId = "tpid_pk_your_public_key", clientSecret = "tpid_sk_your_secret_key", redirectUri = "myapp://callback" ) // OAuth — открыть браузер val authUrl = client.getAuthorizationUrl( scopes = listOf("profile", "email"), usePKCE = true ) startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(authUrl))) // Обработка callback в Activity override fun onNewIntent(intent: Intent) { val code = intent.data?.getQueryParameter("code") ?: return lifecycleScope.launch { val tokens = client.exchangeCode(code) val user = client.getUserInfo(tokens.accessToken) Log.d("TPID", "User: ${user.name} (${user.email})") } } // Верификация токена на сервере val result = client.verify(accessToken) println(result.userId) // tpid_usr_...
SDK — Swift / iOS
.package(url: "https://github.com/tokenpay/id-swift", from: "2.2.0")
import TokenPayID let client = TPIDClient( clientId: "tpid_pk_your_public_key", clientSecret: "tpid_sk_your_secret_key", redirectURI: "myapp://callback" ) // OAuth через ASWebAuthenticationSession let authURL = client.authorizationURL(scopes: [.profile, .email], usePKCE: true) let session = ASWebAuthenticationSession( url: authURL, callbackURLScheme: "myapp" ) { callbackURL, error in guard let code = callbackURL?.queryParam("code") else { return } Task { let tokens = try await client.exchangeCode(code) let user = try await client.userInfo(tokens.accessToken) print("User: \(user.name) — \(user.email)") } } session.start()
SDK — C# / .NET
dotnet add package TokenPayID --version 2.2.0
using TokenPayID; var client = new TPIDClient( clientId: "tpid_pk_your_public_key", clientSecret: "tpid_sk_your_secret_key", redirectUri: "https://yourapp.com/callback" ); // Генерация OAuth URL (с PKCE) var (authUrl, verifier) = client.GetAuthorizationUrl( scopes: new[] { "profile", "email" }, usePKCE: true ); // Обмен кода на токены var tokens = await client.ExchangeCodeAsync(code, verifier); var user = await client.GetUserInfoAsync(tokens.AccessToken); Console.WriteLine($"User: {user.Name} ({user.Email})"); // ASP.NET — middleware services.AddAuthentication() .AddTokenPayID(options => { options.ClientId = "tpid_pk_..."; options.ClientSecret = "tpid_sk_..."; });
SDK — PHP
composer require tokenpay/id-php
use TokenPay\ID\Client; $client = new Client([ 'client_id' => 'tpid_pk_your_public_key', 'client_secret' => 'tpid_sk_your_secret_key', 'redirect_uri' => 'https://yourapp.com/callback', ]); // Редирект на авторизацию (с PKCE) [$authUrl, $verifier] = $client->getAuthorizationUrl(['profile', 'email']); $_SESSION['tpid_verifier'] = $verifier; header("Location: $authUrl"); // Callback — обмен кода $tokens = $client->exchangeCode($_GET['code'], $_SESSION['tpid_verifier']); $user = $client->getUserInfo($tokens->access_token); echo "Hello, {$user->name}!"; // Laravel — встроенный Socialite драйвер // config/services.php 'tokenpay' => [ 'client_id' => env('TPID_CLIENT_ID'), 'client_secret' => env('TPID_CLIENT_SECRET'), 'redirect' => '/auth/tokenpay/callback', ]
SDK — Ruby
gem 'tokenpay-id', '~> 2.2'
require 'tokenpay/id' client = TokenPay::ID::Client.new( client_id: 'tpid_pk_your_public_key', client_secret: 'tpid_sk_your_secret_key', redirect_uri: 'https://yourapp.com/callback' ) # OAuth URL auth_url, verifier = client.authorization_url( scopes: ['profile', 'email'], pkce: true ) # Обмен кода tokens = client.exchange_code(params[:code], verifier) user = client.user_info(tokens.access_token) puts "#{user.name} (#{user.email})" # Rails — OmniAuth стратегия Rails.application.config.middleware.use OmniAuth::Builder do provider :tokenpay_id, ENV['TPID_CLIENT_ID'], ENV['TPID_CLIENT_SECRET'] end
SDK — Dart / Flutter
dependencies: tokenpay_id: ^2.2.0
import 'package:tokenpay_id/tokenpay_id.dart'; final client = TPIDClient( clientId: 'tpid_pk_your_public_key', clientSecret: 'tpid_sk_your_secret_key', redirectUri: 'myapp://callback', ); // Flutter — OAuth через url_launcher final authUrl = client.getAuthorizationUrl( scopes: ['profile', 'email'], usePKCE: true, ); await launchUrl(Uri.parse(authUrl)); // Обработка deep link void handleCallback(Uri uri) async { final code = uri.queryParameters['code']!; final tokens = await client.exchangeCode(code); final user = await client.getUserInfo(tokens.accessToken); print('Hello, ${user.name}!'); }
SDK — Rust
[dependencies]
tokenpay-id = "2.2"
use tokenpay_id::Client; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let client = Client::new( "tpid_pk_your_public_key", "tpid_sk_your_secret_key", ); // Верификация токена let result = client.verify(access_token).await?; println!("User: {}", result.user_id); // OAuth URL с PKCE let (auth_url, verifier) = client.authorization_url( &["profile", "email"], "https://yourapp.com/callback", )?; // Обмен кода let tokens = client.exchange_code(code, &verifier).await?; let user = client.user_info(&tokens.access_token).await?; println!("{} ({})", user.name, user.email); Ok(()) }
Desktop & Native Integration
Для десктопных приложений (Electron, Tauri, WPF, SwiftUI, Kotlin Desktop) используется OAuth через системный браузер с перехватом deep link.
Поддерживаемые платформы
| Платформа | Метод | Redirect URI |
|---|---|---|
| Electron | Custom protocol | myapp://callback |
| Tauri | Deep link plugin | myapp://callback |
| WPF / WinUI | URI activation | myapp://callback |
| SwiftUI / macOS | Custom URL scheme | myapp://callback |
| Android | Intent filter | myapp://callback |
| iOS | Universal link / scheme | myapp://callback |
| Flutter | uni_links / app_links | myapp://callback |
| CLI / Server | Localhost callback | http://127.0.0.1:PORT/callback |
Параметры для десктопных приложений
GET https://tokenpay.space/api/v1/oauth/authorize ?client_id=tpid_pk_... &redirect_uri=myapp://callback // custom scheme &response_type=code &scope=profile email &state=RANDOM_STATE &code_challenge=BASE64URL(SHA256(verifier)) &code_challenge_method=S256 &theme=dark // dark | light — match app theme &lang=ru // ru | en | zh — UI language
Deep Link Flow
const { app } = require('electron'); // Регистрация custom protocol app.setAsDefaultProtocolClient('myapp'); // Обработка deep link (Windows/Linux) app.on('second-instance', (event, argv) => { const url = argv.find(a => a.startsWith('myapp://')); if (url) handleOAuthCallback(url); }); // Обработка deep link (macOS) app.on('open-url', (event, url) => { event.preventDefault(); handleOAuthCallback(url); }); async function handleOAuthCallback(url) { const { searchParams } = new URL(url); const code = searchParams.get('code'); const state = searchParams.get('state'); // Обменяйте code на токены через API }
// src-tauri/tauri.conf.json { "plugins": { "deep-link": { "desktop": { "schemes": ["myapp"] }, "mobile": [ { "host": "callback", "pathPrefix": "/" } ] } } } // Frontend (TypeScript) import { onOpenUrl } from '@tauri-apps/plugin-deep-link'; onOpenUrl((urls) => { const url = new URL(urls[0]); const code = url.searchParams.get('code'); // Exchange code for tokens });
Changelog
v2.3.0 — 13 апреля 2026
SDK
— Kotlin / Android SDK (space.tokenpay:id-sdk)
— Swift / iOS SDK (SPM)
— C# / .NET SDK (NuGet) + ASP.NET middleware
— PHP SDK (Composer) + Laravel Socialite драйвер
— Ruby SDK (Gem) + OmniAuth стратегия
— Dart / Flutter SDK (pub.dev)
— Rust SDK (crates.io)
Desktop & Native
— Документация по интеграции: Electron, Tauri, WPF, SwiftUI
— Поддержка ?theme= и ?lang= параметров для OAuth страниц
— Deep link flow с custom URL schemes
— Localhost callback для CLI-утилит
UI
— Чёрные звёзды-частицы в белой теме (инверсия тёмной)
— Частицы добавлены на все страницы экосистемы
— Обновлён favicon.ico (мультиразмерный из нового логотипа)
— Cache busting обновлён до v=11
v2.2.0 — 27 марта 2026
Безопасность
— PKCE (S256) теперь обязателен для всех OAuth-клиентов
— Ротация refresh-токенов: при обновлении выдаётся новый refresh_token
— session_version — смена пароля/2FA мгновенно инвалидирует все сессии
— API-ключи запрещены из браузерных окружений (только серверный вызов)
— requireScope middleware для гранулярного контроля доступа
— Webhook подписи в формате Stripe: t=timestamp,v1=hmac
— Отвязка TPID доступна только администратору
— /.well-known/security.txt (RFC 9116)
Dynamic Client Registration (RFC 7591)
— POST /oauth/register — программная регистрация OAuth-клиентов
— GET /oauth/client-info/:id — получение метаданных клиента
— PUT /oauth/register/:id — обновление метаданных клиента
— Consent screen отображает tos_uri, policy_uri, client_uri
— OpenID Discovery: registration_endpoint, client_info_endpoint
QR-вход
— POST /auth/qr/login-init — создание QR-сессии
— GET /auth/qr/login-poll/:id — polling статуса
— POST /auth/qr/login-confirm/:id — подтверждение с мобильного
— Исправлен критический баг: QR-токены теперь корректно проходят авторизацию
API
— Строгая валидация redirect_uri (exact match)
— OpenID Discovery: pkce_required: true, code_challenge_methods_supported: ["S256"]
— API версия обновлена до 2.2.0
SDK
— tokenpay-auth.js обновлён до v2.0.0
— Автоматическая генерация PKCE (S256) в authorize()
— getCodeVerifier() — получение code_verifier из sessionStorage
— CSRF state validation на callback
— code_verifier автоматически передаётся в exchangeCode()
— Кнопки обновлены: текст «TOKEN PAY ID», шрифт Comfortaa
v2.1.0 — 18 марта 2026
OAuth 2.0
— Поддержка prompt=login для принудительной переавторизации
— Поддержка login_hint для предзаполнения email
— Повторная валидация redirect_uri в /oauth/approve
— Новый эндпойнт: GET /oauth/branding
Widget SDK v1.2.0
— 3 варианта кнопок: standard, icon, logo
— TPID.loginWithOAuth() — OAuth popup flow с Promise API
— Автоматический рендер через data-tpid-button
— Поддержка тем dark/light/auto
