Авторизация через мессенджеры вместо SMS — без расходов на каждое сообщение. Каждый авторизованный пользователь доступен для уведомлений по номеру телефона через тех же ботов. Система сама выбирает мессенджер, а вы задаёте приоритет.
Поле token в ответе подтверждённой сессии — подписанный JWT (RS256). Данные профиля (имя, username) берутся из мессенджера в момент авторизации и не хранятся на сервере. Для проверки токена используйте публичный ключ, доступный по JWKS-эндпоинту.
| Field | Description |
|---|---|
| _id | ID пользователя (24 hex-символа) |
| user_id | ID пользователя в мессенджере (числовой ID Telegram / MAX / WhatsApp) |
| type | Тип мессенджера: "telegram", "max" или "whatsapp" |
| phone | Номер телефона (например "+79001234567") |
| first_name | Имя из профиля мессенджера (не хранится, берётся в момент авторизации) |
| last_name | Фамилия (может быть null, не хранится) |
| username | Username в мессенджере (может быть null, не хранится) |
| app_id | ID приложения, для которого выпущен токен |
| iss | Издатель (URL сервера Antirius Auth Cloud) |
| iat | Время выпуска (Unix timestamp) |
| exp | Время истечения (Unix timestamp) |
Публичный ключ для проверки JWT доступен по стандартному JWKS-эндпоинту:
https://id.antirius.com/.well-known/jwks.jsonПроверьте подпись токена публичным ключом из JWKS (RS256), затем убедитесь, что app_id в токене совпадает с ID вашего приложения:
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';
const APP_ID = 'YOUR_APP_ID';
const ISSUER = 'https://id.antirius.com';
const JWKS_URI = 'https://id.antirius.com/.well-known/jwks.json';
const jwks = jwksClient({ jwksUri: JWKS_URI });
function verifyAuthToken(token) {
return new Promise((resolve, reject) => {
jwt.verify(
token,
(header, cb) => {
jwks.getSigningKey(header.kid, (err, key) => cb(err, key?.getPublicKey()));
},
{ algorithms: ['RS256'], issuer: ISSUER },
(err, decoded) => {
if (err) return reject(err);
if (decoded.app_id !== APP_ID) return reject(new Error('APP_ID_MISMATCH'));
resolve(decoded);
},
);
});
}
export async function authMiddleware(ctx, next) {
const auth = ctx.headers.authorization || '';
if (!auth.startsWith('Bearer ')) {
ctx.status = 401;
ctx.body = { error: 'No token' };
return;
}
try {
ctx.state.user = await verifyAuthToken(auth.slice(7));
await next();
} catch (e) {
ctx.status = 401;
ctx.body = { error: e.message || 'Invalid token' };
}
}import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';
const APP_ID = 'YOUR_APP_ID';
const ISSUER = 'https://id.antirius.com';
const JWKS_URI = 'https://id.antirius.com/.well-known/jwks.json';
const jwks = jwksClient({ jwksUri: JWKS_URI });
function verifyAuthToken(token) {
return new Promise((resolve, reject) => {
jwt.verify(
token,
(header, cb) => {
jwks.getSigningKey(header.kid, (err, key) => cb(err, key?.getPublicKey()));
},
{ algorithms: ['RS256'], issuer: ISSUER },
(err, decoded) => {
if (err) return reject(err);
if (decoded.app_id !== APP_ID) return reject(new Error('APP_ID_MISMATCH'));
resolve(decoded);
},
);
});
}
async function authPreHandler(request, reply) {
const auth = request.headers.authorization || '';
if (!auth.startsWith('Bearer ')) {
return reply.code(401).send({ error: 'No token' });
}
try {
request.user = await verifyAuthToken(auth.slice(7));
} catch (e) {
return reply.code(401).send({ error: e.message || 'Invalid token' });
}
}Также можно проверить авторизацию напрямую через эндпоинт статуса сессии:
GET https://id.antirius.com/api/v1/auth/session/SESSION_ID?type=full
// If confirmed → response includes token + user:
{
"status": "confirmed",
"poll_type": "full",
"token": "eyJhbGciOi...",
"user": { "_id": "...", "phone": "+79001234567", ... },
"app_id": "YOUR_APP_ID"
}
// Progress check without JWT (repeatable):
GET https://id.antirius.com/api/v1/auth/session/SESSION_ID?type=statusЗапрос с type=full. Если в ответе "status": "confirmed" и поле "token" — пользователь авторизован. type=status — только проверка прогресса без деактивации сессии.