NeuroAgent

PHP Proxy for 1C and Bitrix24 with OAuth

Complete guide to creating a universal PHP proxy for integrating 1C with Bitrix24 API. Automatic OAuth authorization, request processing and response handling.

Question

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.

NeuroAgent

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

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:

  1. Request Receiver - processes incoming data from 1C
  2. OAuth Manager - manages authorization tokens
  3. 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

  1. Go to your Bitrix24 portal
  2. Navigate to “Developers” → “Applications” → “Create Application”
  3. Specify application type “Web Service”
  4. 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:

php
// 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
<?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
<?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
<?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
<?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
<?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
<?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
<?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

vbscript
// 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

  1. OAuth 2.0 Protocol - Bitrix24
  2. Examples - Bitrix24 OAuth Implementation
  3. Authentication for Mobile and Desktop Applications - Bitrix24
  4. OAuth 2.0 automatic extension - Bitrix24
  5. citrus-soft/bitrix24-php-sdk - Packagist
  6. GitHub - mesilov/bitrix24-php-sdk
  7. 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:

  1. Register an application in Bitrix24 and obtain credentials
  2. Deploy the PHP script on a secure web server
  3. Configure request redirection from 1C to the script URL
  4. 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.