Вход, который
понимает ваш проект.
Подключите вход через PrxID: сформируйте ссылку авторизации, настройте callback, обменяйте код на сервере и создайте сессию вашего сайта.
Поток входа
- Ваш backendСоздаёт случайный state, сохраняет его в серверном хранилище и связывает с cookie браузера.
- Браузер → PrxIDПользователь входит на стороне PrxID и подтверждает доступ приложению.
- PrxID → callbackБраузер возвращается на зарегистрированный URL с code и state.
- Ваш backend → /api/oauth/tokenПосле проверки state backend обменивает code, используя секретный ключ.
- Ваш сайтНаходит пользователя по usr_…, создаёт собственную сессию и открывает кабинет.
Это партнёрский протокол, а не полный OAuth/OIDC: endpoint с названием token сразу возвращает пользовательские данные. Не ожидайте access_token, refresh_token, ID token или отдельный userinfo.
Запрос авторизации
Публичная точка входа — GET /auth на базовом адресе из prxid_url. Формируйте ссылку стандартным URL-кодировщиком.
const url = new URL('/auth', prxidUrl);
url.search = new URLSearchParams({
idpart_link: partnerId,
redirect_uri: registeredCallback,
state: serverGeneratedState,
theme: 'white',
scope: 'profile',
}).toString();
// API key в эту ссылку не добавляется.
redirectToProvider(url.href);| Параметр | Смысл |
|---|---|
| idpart_link | Публичный ID данного входа из карточки Cloud |
| redirect_uri | Точное зарегистрированное значение callback |
| state | Случайное одноразовое значение для защиты возврата |
| theme | white, glass, neon или plata |
| scope | profile; email и phone — только при необходимости и согласии |
PrxID добавляет profile автоматически. Контакты возвращаются только при запросе соответствующего scope и явном согласии. Минимальной интеграции достаточно profile; Cloud сейчас не сохраняет контакты.
Callback и state
GET /auth/prxid/callback?code=prx_code_…&state=…Создайте state через криптографический генератор, например randomBytes(32). Сохраните его хеш, срок действия и привязку к случайной cookie браузера на сервере. Используйте короткий срок: в примере — десять минут.
- Проверьте метод запроса, наличие ровно одного code и одного state, формат и срок действия.
- Найдите попытку по защищённой cookie этого браузера. State сам по себе не заменяет такую привязку.
- Атомарно удалите попытку и сравните хеши constant-time сравнением.
- При любой ошибке завершите попытку. Не создавайте сессию и не обменивайте код.
- После успеха выполните серверный обмен и уберите code из адресной строки перенаправлением в кабинет.
PrxID выдаёт code на пять минут. Один code можно использовать только один раз. Повторный callback, истёкшая попытка и возврат в другом браузере должны завершаться отказом. Не сохраняйте полный code или ключ в логах и аналитике.
Обмен кода
Запрос идёт с backend на HTTPS-адрес из prxid_url. Не выполняйте обмен в браузере и не отключайте проверку TLS.
// Только backend. После проверки и удаления state.
const response = await fetch(new URL('/api/oauth/token', prxidUrl), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
redirect: 'error',
signal: AbortSignal.timeout(10000),
body: JSON.stringify({
api_key: serverOnlyApiKey,
code: codeFromCallback,
redirect_uri: registeredCallback,
}),
});
if (!response.ok) throw new Error('PrxID не подтвердил вход');
const data = await response.json();
if (data.success !== true || typeof data.user?.id !== 'string') {
throw new Error('Некорректный ответ PrxID');
}
// Найдите или создайте локального пользователя по data.user.id.
// Только теперь создайте защищённую серверную сессию своего сайта.Минимальный успешный ответ:
{
"success": true,
"user": {
"id": "usr_ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"Ferif": "01",
"email_verified": true,
"number_verified": false
}
}Ferif и флаги подтверждения не содержат сами контакты. Email и phone появляются отдельно при разрешённых scopes. Имя и фамилия в текущем протоколе не передаются. Не считайте эти поля обязательными.
Локальная сессия вашего сайта
Используйте user.id как уникальный внешний ключ пользователя в пределах проекта. Повторный вход должен находить ту же запись. Создавайте новый случайный токен сессии после подтверждённого обмена; храните на сервере его хеш, пользователя и срок действия.
Cookie должна иметь HttpOnly, SameSite=Lax и Secure при HTTPS. Проверяйте сессию и права на каждом приватном API-запросе, а не только в интерфейсе. Выход удаляет серверную запись и cookie. Для действий, изменяющих данные, нужна защита от CSRF, например точная проверка Origin.
Одинаковый пользовательский ID в двух приложениях проекта не даёт автоматический доступ к данным другого приложения. Это зависит от вашей бизнес-логики. Сессии разных доменов остаются отдельными.
Готовый пример для вашего сайта
Пример использует Node.js 24+ и встроенный SQLite. Скачайте два файла в одну папку; внешние npm-зависимости не нужны. Модуль реализует state, одноразовый callback, серверный обмен, локальную базу пользователей, session API и выход.
node server.mjsПри первом запуске создаются time/prxid.json и time/users.db. В JSON заполните prxid_url из карточки входа, выданные idpart_link и api_key и точный redirect_uri. Пример слушает localhost:3000; для локального теста создайте вход с callback http://localhost:3000/auth/prxid/callback. Для туннеля зарегистрируйте его полный HTTPS callback и открывайте сайт через этот туннель.
{
"prxid_url": "БАЗОВЫЙ_АДРЕС_ИЗ_CLOUD",
"idpart_link": "ВЫДАННЫЙ_ID",
"api_key": "СЕКРЕТНЫЙ_ТОКЕН",
"redirect_uri": "http://localhost:3000/auth/prxid/callback",
"theme": "white",
"token_server_ip": ""
}Если у вас уже есть интерфейс, кнопка входа обращается к вашему backend:
// Кнопка «Войти» на вашем сайте. Ключ остаётся на backend.
const response = await fetch('/api/auth/prxid/start', { method: 'POST' });
const data = await response.json();
if (!response.ok) throw new Error(data.message);
window.location.assign(data.url);В существующем backend можно использовать createAuth и вызывать auth.handle(req, res) до обработки остальных маршрутов. Обязательно согласуйте пути и хранение сессий со своим приложением; не подключайте второй независимый механизм сессий незаметно для остального кода. Для другой технологии повторите протокол, а не переносите секрет в клиент.
Добавьте /time/ в .gitignore и обеспечьте сохранность базы при обновлении. Пример запускайте за HTTPS reverse proxy в production. Демо HTML служит стартовой точкой; внешний вид заменяется вашим интерфейсом.
Ошибки и проверка
| HTTP | Что проверить |
|---|---|
| 400 | Code, срок, повторное использование и точный callback |
| 401 | Правильность и активность API-ключа |
| 403 | Принадлежность ключа, кода и callback одной компании |
| 429 | Лимит попыток; подождать перед новой попыткой |
| 503 / сеть | Доступность PrxID, DNS, HTTPS и баз данных |
Не создавайте сессию при ошибках. Не повторяйте обмен бесконечно: если ответ потерялся после успешного обмена, code уже может быть использован. Предложите пользователю начать новый вход.
- Проверьте полный вход в обычном браузере и повторный вход того же пользователя.
- Проверьте неверный state, истёкшую попытку, повтор callback и другой браузер.
- Убедитесь, что секрет отсутствует в HTML, клиентских бандлах, URL и логах.
- Для двух входов одного проекта сравните user.id одного аккаунта — значения должны совпасть.
- Для входа другого проекта повторите тест — значение должно отличаться.
- Проверьте выход и отказ в доступе к защищённым маршрутам без действующей сессии вашего сайта.