JWT Token Setup for 1C-Bitrix API
JWT (JSON Web Token) is a standard for transmitting assertions between systems as a signed JSON object. In the context of 1C-Bitrix API, JWT is used for request authorization: client presents a token, server verifies the signature and allows or denies the request.
What is JWT: structure
The token consists of three parts separated by a period: header.payload.signature.
-
Header — signature algorithm:
{"alg": "HS256", "typ": "JWT"}. -
Payload — data:
{"sub": "user_id", "iat": 1700000000, "exp": 1700003600, "role": "api_client"}. - Signature — HMAC-SHA256 of header+payload with secret key.
Token is not encrypted — payload is readable. But forging signature without secret key is impossible.
JWT authentication implementation in Bitrix
1C-Bitrix has no built-in JWT provider for REST API. JWT authentication is implemented through a custom handler as part of your own API module or through a hook in /local/php_interface/init.php.
Handler structure:
use \Firebase\JWT\JWT;
use \Firebase\JWT\Key;
class JwtAuthMiddleware
{
public static function authenticate(): ?int
{
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (!str_starts_with($authHeader, 'Bearer ')) {
return null;
}
$token = substr($authHeader, 7);
$secret = \Bitrix\Main\Config\Option::get('my_api', 'jwt_secret');
try {
$decoded = JWT::decode($token, new Key($secret, 'HS256'));
return (int)$decoded->sub; // userId
} catch (\Exception $e) {
return null;
}
}
}
Library firebase/php-jwt installed via Composer in /local/:
composer require firebase/php-jwt
Token issuance: authentication endpoint
Client receives JWT through /api/v1/auth/login:
// Check Bitrix user login/password
$user = new CUser();
if ($user->Login($login, $password) === true) {
$userId = $USER->GetID();
$payload = [
'sub' => $userId,
'iat' => time(),
'exp' => time() + 3600, // 1 hour
'role' => getUserRole($userId),
];
$token = JWT::encode($payload, $secret, 'HS256');
echo json_encode(['token' => $token, 'expires_in' => 3600]);
}
Refresh tokens. Short-term access token (1 hour) + long-term refresh token (30 days). When access token expires, client uses refresh to get new one. Refresh tokens stored in table b_local_api_refresh_tokens with user binding and revocation ability.
Secret key
Signing secret stored in b_option:
// Generation on module install
$secret = bin2hex(random_bytes(32)); // 64 characters
\Bitrix\Main\Config\Option::set('my_api', 'jwt_secret', $secret);
Key rotation: when secret changes, all issued tokens become invalid. Need "soft" rotation mechanism — store two keys (old and new) during transition period.
Token verification in protected endpoints
// At beginning of each API controller
$userId = JwtAuthMiddleware::authenticate();
if (!$userId) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
Storing claims
You can include additional data in payload to avoid extra database requests:
{
"sub": 42,
"iat": 1700000000,
"exp": 1700003600,
"role": "manager",
"groups": [1, 5, 12],
"permissions": ["crm.read", "catalog.write"]
}
But carefully: payload increases token size. Rights that change often, better check in DB on each request.
JWT authorization setup for new API — 1-2 days depending on role model complexity.

