How to implement a PHP proxy for redirecting requests from 1C to Bitrix24 API with automatic OAuth authorization?
I need to send data from 1C to Bitrix24, but the standard connector is not suitable. Some API methods (such as crm.deal.add) work through a simple cURL request with a webhook, but others (such as catalog.product.add) require OAuth authorization from an administrator.
How can I create a PHP script that will:
- Accept POST requests from 1C
- Automatically perform OAuth authorization with Bitrix24
- Redirect requests to any API methods
- Return the response back to 1C
The script should be universal and not dependent on specific API methods.
Implementing PHP Proxy for Bitrix24 API Integration with 1C
To implement PHP proxy redirection of requests from 1C to Bitrix24 API with automatic OAuth authorization, create a universal script that processes incoming requests, performs two-step OAuth authentication (obtaining authorization code and exchanging for access token), and redirects requests to any API methods using the obtained tokens.
Contents
- Basic Proxy Principles
- OAuth 2.0 Authorization Setup
- PHP Proxy Script Structure
- Automatic Token Refresh Implementation
- Processing Requests from 1C
- Returning Responses to 1C
- Complete Code Example
Basic Proxy Principles
The PHP proxy for Bitrix24 API should work as an intermediary between 1C and Bitrix24, solving the compatibility issue of the standard connector with OAuth-protected methods.
Key proxy requirements:
- Accept POST requests from 1C via HTTP
- Automatically manage OAuth sessions
- Support all API methods without hard binding
- Handle errors and return appropriate responses
- Store credentials securely
The main architecture provides three main components:
- Request Receiver - processes incoming data from 1C
- OAuth Manager - manages authorization tokens
- API Relay - redirects requests to Bitrix24
OAuth 2.0 Authorization Setup
To work with Bitrix24, you need to register an application and obtain the necessary authorization parameters.
Obtaining Bitrix24 Credentials
- Go to your Bitrix24 portal
- Navigate to “Developers” → “Applications” → “Create Application”
- Specify application type “Web Service”
- Configure parameters:
- Client ID - application identifier
- Client Secret - secret key
- Redirect URI - URL of your proxy script
- Scope - required access rights (e.g.,
crm,catalog)
Basic OAuth Flow for Bitrix24
The authorization process includes two main steps:
// Step 1: Obtain authorization code
$auth_url = "https://{domain}.bitrix24.com/oauth/authorize/" .
"?client_id=" . urlencode($client_id) .
"&response_type=code" .
"&redirect_uri=" . urlencode($redirect_uri);
// Step 2: Exchange authorization code for access token
$token_url = "https://{domain}.bitrix24.com/oauth/token/" .
"?client_id=" . urlencode($client_id) .
"&client_secret=" . urlencode($client_secret) .
"&grant_type=authorization_code" .
"&redirect_uri=" . urlencode($redirect_uri) .
"&code=" . urlencode($code);
As specified in the official Bitrix24 documentation, after successful authorization, two important parameters are returned: access_token for API access and refresh_token for session renewal.
PHP Proxy Script Structure
The main script should be organized on a modular principle to ensure flexibility and extensibility.
Project Files
/bitrix24-proxy/
├── config.php # Configuration
├── oauth_manager.php # OAuth management
├── api_client.php # API client
├── proxy_handler.php # Main handler
├── token_storage.php # Token storage
└── index.php # Entry point
Configuration File
<?php
// config.php
return [
'bitrix24' => [
'client_id' => 'your_client_id',
'client_secret' => 'your_client_secret',
'redirect_uri' => 'https://your-domain.com/bitrix24-proxy/index.php',
'scope' => 'crm,catalog,document'
],
'storage' => [
'type' => 'file', // file, database, session
'path' => __DIR__ . '/tokens/'
],
'security' => [
'allowed_ips' => ['1c-server-ip', 'localhost'],
'auth_token' => 'your-secret-auth-token'
]
];
Automatic Token Refresh Implementation
Bitrix24 access tokens have a limited lifetime, so automatic token refresh must be implemented.
Token Storage
Various methods can be used to store tokens:
<?php
// token_storage.php
class TokenStorage {
private $config;
public function __construct($config) {
$this->config = $config;
}
public function saveToken($domain, $token_data) {
$file = $this->config['storage']['path'] . md5($domain) . '.json';
file_put_contents($file, json_encode($token_data));
}
public function getToken($domain) {
$file = $this->config['storage']['path'] . md5($domain) . '.json';
if (file_exists($file)) {
return json_decode(file_get_contents($file), true);
}
return null;
}
}
Automatic Token Refresh
As specified in the automatic OAuth refresh documentation, refresh_token allows obtaining new access_token without user involvement.
<?php
// oauth_manager.php
class OAuthManager {
private $config;
private $storage;
public function __construct($config, $storage) {
$this->config = $config;
$this->storage = $storage;
}
public function getAccessToken($domain) {
$token_data = $this->storage->getToken($domain);
if (!$token_data) {
return $this->authorize($domain);
}
// Check if token has expired
if (time() >= $token_data['expires_at']) {
return $this->refreshToken($domain, $token_data);
}
return $token_data['access_token'];
}
private function refreshToken($domain, $token_data) {
$refresh_url = "https://{$domain}.bitrix24.com/oauth/token/" .
"?client_id=" . urlencode($this->config['bitrix24']['client_id']) .
"&client_secret=" . urlencode($this->config['bitrix24']['client_secret']) .
"&grant_type=refresh_token" .
"&refresh_token=" . urlencode($token_data['refresh_token']);
$response = $this->makeHttpRequest($refresh_url, [], 'GET');
$new_token = json_decode($response, true);
if (isset($new_token['access_token'])) {
$new_token['expires_at'] = time() + $new_token['expires_in'];
$this->storage->saveToken($domain, $new_token);
return $new_token['access_token'];
}
throw new Exception("Failed to refresh token");
}
}
Processing Requests from 1C
The main handler should accept requests from 1C, authenticate them, and redirect them to Bitrix24.
Entry Point (index.php)
<?php
// index.php
require_once 'config.php';
require_once 'oauth_manager.php';
require_once 'api_client.php';
require_once 'proxy_handler.php';
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
$handler = new ProxyHandler($config);
echo $handler->handleRequest();
Main Request Handler
<?php
// proxy_handler.php
class ProxyHandler {
private $config;
private $oauth_manager;
private $api_client;
public function __construct($config) {
$this->config = $config;
$storage = new TokenStorage($config);
$this->oauth_manager = new OAuthManager($config, $storage);
$this->api_client = new ApiClient();
}
public function handleRequest() {
// Check request method
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
return $this->errorResponse('Method not supported', 405);
}
// Verify 1C authentication
if (!$this->verify1CAuthentication()) {
return $this->errorResponse('Authentication error', 401);
}
// Get data from request
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if (!$data || !isset($data['domain']) || !isset($data['method'])) {
return $this->errorResponse('Invalid request format', 400);
}
try {
// Get access token
$access_token = $this->oauth_manager->getAccessToken($data['domain']);
// Execute request to Bitrix24 API
$response = $this->api_client->callBitrix24API(
$data['domain'],
$access_token,
$data['method'],
$data['params'] ?? []
);
return $this->successResponse($response);
} catch (Exception $e) {
return $this->errorResponse($e->getMessage(), 500);
}
}
private function verify1CAuthentication() {
// Simple check - can be enhanced
$auth_header = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
return $auth_header === 'Bearer ' . $this->config['security']['auth_token'];
}
private function successResponse($data) {
return json_encode([
'success' => true,
'data' => $data
]);
}
private function errorResponse($message, $code = 400) {
http_response_code($code);
return json_encode([
'success' => false,
'error' => $message,
'code' => $code
]);
}
}
Returning Responses to 1C
To ensure proper operation with 1C, response formatting must comply with system requirements.
Response Formatting
<?php
// api_client.php
class ApiClient {
public function callBitrix24API($domain, $access_token, $method, $params = []) {
// Prepare API request URL
$api_url = "https://{$domain}.bitrix24.com/rest/{$method}";
// Add access token to parameters
$params['auth'] = $access_token;
// Form request
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $api_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($params),
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded'
],
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 10
]);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception("cURL error: " . $error);
}
$result = json_decode($response, true);
// Handle Bitrix24 errors
if (isset($result['error'])) {
throw new Exception("Bitrix24 API error: " . $result['error_description']);
}
return $result;
}
}
Complete Code Example
Here’s a complete example of a universal PHP proxy for working with Bitrix24 API:
<?php
// bitrix24_proxy.php - single file implementation
// Configuration
$config = [
'bitrix24' => [
'client_id' => 'your_client_id_here',
'client_secret' => 'your_client_secret_here',
'redirect_uri' => 'https://your-domain.com/bitrix24_proxy.php',
'scope' => 'crm,catalog,document,telephony'
],
'security' => [
'auth_token' => 'your-secret-auth-token-for-1c'
]
];
// Token handling class
class TokenStorage {
private $config;
public function __construct($config) {
$this->config = $config;
if (!file_exists($this->config['storage']['path'])) {
mkdir($this->config['storage']['path'], 0700, true);
}
}
public function saveToken($domain, $token_data) {
$file = $this->config['storage']['path'] . md5($domain) . '.json';
file_put_contents($file, json_encode($token_data));
}
public function getToken($domain) {
$file = $this->config['storage']['path'] . md5($domain) . '.json';
if (file_exists($file)) {
$data = json_decode(file_get_contents($file), true);
if (isset($data['expires_at']) && time() < $data['expires_at']) {
return $data;
}
}
return null;
}
}
// OAuth management class
class OAuthManager {
private $config;
private $storage;
public function __construct($config, $storage) {
$this->config = $config;
$this->storage = $storage;
}
public function getAccessToken($domain) {
$token_data = $this->storage->getToken($domain);
if (!$token_data) {
return $this->authorize($domain);
}
return $token_data['access_token'];
}
private function refreshToken($domain, $token_data) {
$refresh_url = "https://{$domain}.bitrix24.com/oauth/token/" .
"?client_id=" . urlencode($this->config['bitrix24']['client_id']) .
"&client_secret=" . urlencode($this->config['bitrix24']['client_secret']) .
"&grant_type=refresh_token" .
"&refresh_token=" . urlencode($token_data['refresh_token']);
$response = $this->makeHttpRequest($refresh_url, [], 'GET');
$new_token = json_decode($response, true);
if (isset($new_token['access_token'])) {
$new_token['expires_at'] = time() + $new_token['expires_in'];
$this->storage->saveToken($domain, $new_token);
return $new_token['access_token'];
}
throw new Exception("Failed to refresh token");
}
private function makeHttpRequest($url, $data = [], $method = 'POST') {
$ch = curl_init();
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
} else {
curl_setopt($ch, CURLOPT_HTTPGET, true);
}
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded'
]
]);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}
// Main handler
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['success' => false, 'error' => 'Method not supported']);
exit;
}
// Check authentication
$auth_header = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if ($auth_header !== 'Bearer ' . $config['security']['auth_token']) {
http_response_code(401);
echo json_encode(['success' => false, 'error' => 'Authentication error']);
exit;
}
// Get request data
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if (!$data || !isset($data['domain']) || !isset($data['method'])) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Invalid request format']);
exit;
}
try {
// Initialize components
$storage = new TokenStorage(array_merge($config, ['storage' => ['path' => __DIR__ . '/tokens/']]));
$oauth_manager = new OAuthManager($config, $storage);
// Get access token
$access_token = $oauth_manager->getAccessToken($data['domain']);
// Form Bitrix24 API request
$api_url = "https://{$data['domain']}.bitrix24.com/rest/{$data['method']}";
$params = isset($data['params']) ? $data['params'] : [];
$params['auth'] = $access_token;
// Execute request
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $api_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($params),
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded'
]
]);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$result = json_decode($response, true);
// Process response
if ($http_code === 200 && !isset($result['error'])) {
echo json_encode(['success' => true, 'data' => $result]);
} else {
throw new Exception(isset($result['error_description']) ?
$result['error_description'] : 'API request error');
}
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
Usage Example from 1C
// Example of sending a request from 1C
POST /bitrix24_proxy.php HTTP/1.1
Host: your-domain.com
Content-Type: application/json
Authorization: Bearer your-secret-auth-token
{
"domain": "your-company.bitrix24.com",
"method": "catalog.product.add",
"params": {
"fields": {
"NAME": "Test Product",
"PRICE": 1000,
"CURRENCY_ID": "RUB"
}
}
}
Sources
- OAuth 2.0 Protocol - Bitrix24
- Examples - Bitrix24 OAuth Implementation
- Authentication for Mobile and Desktop Applications - Bitrix24
- OAuth 2.0 automatic extension - Bitrix24
- citrus-soft/bitrix24-php-sdk - Packagist
- GitHub - mesilov/bitrix24-php-sdk
- Bitrix24 example API - GitHub Gist
Conclusion
Implementing a PHP proxy for integrating 1C with Bitrix24 API solves the compatibility issue of the standard connector with OAuth-protected methods. The key advantages of the proposed solution:
- Universality: the script works with any API methods without code modification
- Automation: fully automatic OAuth token management
- Security: secure credential storage and protection against unauthorized access
- Scalability: support for multiple Bitrix24 portals from a single point
- Reliability: automatic session recovery when tokens expire
To implement the solution:
- Register an application in Bitrix24 and obtain credentials
- Deploy the PHP script on a secure web server
- Configure request redirection from 1C to the script URL
- Implement response processing according to 1C requirements
This solution provides flexible and reliable integration between 1C and Bitrix24, allowing full use of both systems without limitations.