• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » How to securely integrate Salesforce CRM endpoints into WordPress custom plugins using WP HTTP API

How to securely integrate Salesforce CRM endpoints into WordPress custom plugins using WP HTTP API

Establishing Secure Salesforce API Authentication

Integrating Salesforce CRM endpoints into a WordPress custom plugin necessitates a robust authentication strategy. For enterprise-grade solutions, OAuth 2.0 is the de facto standard, providing a secure and scalable mechanism for delegated access. We will focus on the “JSON Web Token (JWT) Bearer Flow” for server-to-server integrations, as it eliminates the need for user interaction and is ideal for background processes or automated data synchronization.

The JWT Bearer Flow involves several key components:

  • Connected App in Salesforce: This acts as the client application, defining the API access permissions and integration details.
  • Digital Certificate: A self-signed or CA-signed certificate is required to sign the JWT. The public key of this certificate must be uploaded to the Salesforce Connected App.
  • JWT Assertion: A JSON Web Token containing claims about the issuer, subject, audience, and expiration time, signed with the private key corresponding to the uploaded public key.
  • Salesforce Token Endpoint: The specific Salesforce URL that accepts the JWT assertion and issues an access token.

Generating the Digital Certificate and JWT

Before writing any PHP code, you’ll need to generate a digital certificate and its corresponding private key. This can be done using OpenSSL. For production, it’s highly recommended to use a certificate signed by a trusted Certificate Authority (CA). For development or internal tools, a self-signed certificate is often sufficient.

First, generate a private key:

openssl genrsa -des3 -out salesforce_private.key 2048

Next, create a Certificate Signing Request (CSR):

openssl req -new -key salesforce_private.key -out salesforce.csr -subj "/C=US/ST=California/L=San Francisco/O=YourCompany/OU=IT/CN=salesforce.yourdomain.com"

Now, sign the CSR with your private key to create a self-signed certificate. For production, you would submit the salesforce.csr to a CA.

openssl x509 -req -days 365 -in salesforce.csr -signkey salesforce_private.key -out salesforce_public.crt

You will need the contents of salesforce_private.key (ensure it’s not password-protected for programmatic use, or handle the decryption) and salesforce_public.crt. The private key should be stored securely, ideally outside the webroot and protected by file permissions.

Configuring Salesforce Connected App

In your Salesforce instance, navigate to Setup > Apps > App Manager > New Connected App.

  • Basic Information: Fill in the App Name, API Name, and Contact Email.
  • API (Enable OAuth Settings):
    • Check “Enable OAuth Settings”.
    • Callback URL: This is not strictly required for JWT Bearer Flow but must be provided. A placeholder like https://localhost/callback is acceptable.
    • Selected OAuth Scopes: Choose the necessary scopes. For example, “Access and manage your data (api)” and “Perform requests on your behalf at any time (refresh_token, offline_access)”.
    • Use digital signatures (requires certificate): Check this box.
    • API (Enable OAuth Settings) > Certificate: Upload the salesforce_public.crt file you generated.
  • Save the Connected App.

After saving, you will see the Consumer Key (Client ID) and Consumer Secret (Client Secret). The Consumer Secret is not used in the JWT Bearer Flow but is good to note. You will also need the My Domain URL for your Salesforce instance (e.g., yourcompany.my.salesforce.com) to construct the token endpoint URL.

Implementing the JWT Generation and Token Request in WordPress

Within your WordPress plugin, you’ll need a function to construct the JWT and make an authenticated HTTP request to the Salesforce token endpoint. We’ll use WordPress’s built-in wp_remote_post() function for this.

First, define your configuration constants or options. It’s best practice to store sensitive information like private keys and client IDs in WordPress options or constants defined in wp-config.php, and ensure appropriate access controls.

// In your plugin's main file or an included configuration file
define( 'SALESFORCE_CONSUMER_KEY', 'YOUR_SALESFORCE_CONSUMER_KEY' );
define( 'SALESFORCE_MY_DOMAIN_URL', 'https://yourcompany.my.salesforce.com' ); // e.g., https://yourcompany.my.salesforce.com
define( 'SALESFORCE_PRIVATE_KEY_PATH', WP_PLUGIN_DIR . '/your-plugin-name/certs/salesforce_private.key' ); // Securely store this key
define( 'SALESFORCE_JWT_ISSUER', SALESFORCE_CONSUMER_KEY ); // Typically the Consumer Key
define( 'SALESFORCE_JWT_SUBJECT', SALESFORCE_CONSUMER_KEY ); // Typically the Consumer Key
define( 'SALESFORCE_JWT_AUDIENCE', SALESFORCE_MY_DOMAIN_URL . '/services/oauth2/token' );

Now, let’s create the function to obtain the Salesforce access token:

/**
 * Generates a JWT assertion for Salesforce authentication.
 *
 * @param string $consumer_key Your Salesforce Connected App Consumer Key.
 * @param string $private_key_path Path to your Salesforce private key file.
 * @param string $audience The audience URL for the JWT.
 * @return string|WP_Error The signed JWT assertion or a WP_Error object on failure.
 */
function get_salesforce_jwt_assertion( $consumer_key, $private_key_path, $audience ) {
    if ( ! file_exists( $private_key_path ) ) {
        return new WP_Error( 'salesforce_auth_error', __( 'Salesforce private key file not found.', 'your-text-domain' ) );
    }

    $private_key = file_get_contents( $private_key_path );
    if ( $private_key === false ) {
        return new WP_Error( 'salesforce_auth_error', __( 'Failed to read Salesforce private key.', 'your-text-domain' ) );
    }

    // Ensure private key is not password protected for programmatic use, or handle decryption.
    // For simplicity, assuming no password here. If password protected, you'd need openssl_decrypt or similar.

    $header = json_encode( [
        'alg' => 'RS256', // Or RS384, RS512 depending on your certificate
        'typ' => 'JWT',
    ] );

    // Salesforce requires specific claims for JWT Bearer Flow
    $now = time();
    $claims = json_encode( [
        'iss' => $consumer_key,       // Issuer (Connected App Consumer Key)
        'sub' => $consumer_key,       // Subject (Connected App Consumer Key)
        'aud' => $audience,           // Audience (Salesforce token endpoint URL)
        'exp' => $now + 300,          // Expiration time (e.g., 5 minutes from now)
        'iat' => $now,               // Issued at time
    ] );

    // Base64 URL-encode header and claims
    $base64_header = str_replace( ['+', '/', '='], ['-', '_', ''], base64_encode( $header ) );
    $base64_claims = str_replace( ['+', '/', '='], ['-', '_', ''], base64_encode( $claims ) );

    // Sign the header and claims with the private key
    $signature = '';
    if ( ! openssl_sign( $base64_header . '.' . $base64_claims, $signature, $private_key, OPENSSL_ALGO_SHA256 ) ) {
        return new WP_Error( 'salesforce_auth_error', __( 'Failed to sign JWT assertion.', 'your-text-domain' ) );
    }

    $base64_signature = str_replace( ['+', '/', '='], ['-', '_', ''], base64_encode( $signature ) );

    return $base64_header . '.' . $base64_claims . '.' . $base64_signature;
}

/**
 * Obtains an OAuth 2.0 access token from Salesforce using JWT Bearer Flow.
 *
 * @return string|WP_Error The access token or a WP_Error object on failure.
 */
function get_salesforce_access_token() {
    $token_endpoint = SALESFORCE_JWT_AUDIENCE; // This is the token endpoint URL

    $jwt_assertion = get_salesforce_jwt_assertion(
        SALESFORCE_JWT_ISSUER,
        SALESFORCE_PRIVATE_KEY_PATH,
        SALESFORCE_JWT_AUDIENCE
    );

    if ( is_wp_error( $jwt_assertion ) ) {
        return $jwt_assertion;
    }

    $body = [
        'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        'assertion'  => $jwt_assertion,
    ];

    $args = [
        'method'  => 'POST',
        'timeout' => 30,
        'body'    => $body,
        'headers' => [
            'Content-Type' => 'application/x-www-form-urlencoded',
        ],
    ];

    $response = wp_remote_post( $token_endpoint, $args );

    if ( is_wp_error( $response ) ) {
        return new WP_Error( 'salesforce_auth_error', sprintf( __( 'Salesforce API request failed: %s', 'your-text-domain' ), $response->get_error_message() ) );
    }

    $response_code = wp_remote_retrieve_response_code( $response );
    $response_body = wp_remote_retrieve_body( $response );
    $response_data = json_decode( $response_body, true );

    if ( $response_code !== 200 || ! isset( $response_data['access_token'] ) ) {
        $error_message = isset( $response_data['error_description'] ) ? $response_data['error_description'] : $response_body;
        return new WP_Error( 'salesforce_auth_error', sprintf( __( 'Failed to obtain Salesforce access token. Response: %s', 'your-text-domain' ), $error_message ) );
    }

    return $response_data['access_token'];
}

Making Authenticated Salesforce API Calls

Once you have a valid access token, you can make authenticated requests to Salesforce REST API endpoints. The access token is passed in the Authorization header as a Bearer token.

Here’s an example of fetching Account records:

/**
 * Fetches Salesforce Account records.
 *
 * @param string $access_token The Salesforce access token.
 * @param string $salesforce_instance_url The base URL of your Salesforce instance (e.g., https://yourcompany.my.salesforce.com).
 * @return array|WP_Error An array of Account records or a WP_Error object on failure.
 */
function fetch_salesforce_accounts( $access_token, $salesforce_instance_url ) {
    if ( empty( $access_token ) || is_wp_error( $access_token ) ) {
        return new WP_Error( 'salesforce_api_error', __( 'Invalid or missing Salesforce access token.', 'your-text-domain' ) );
    }

    // Salesforce REST API endpoint for Accounts
    $api_endpoint = trailingslashit( $salesforce_instance_url ) . 'services/data/v58.0/query/'; // Adjust API version as needed

    // SOQL query to fetch accounts
    $soql_query = urlencode( 'SELECT Id, Name, Industry FROM Account LIMIT 10' );
    $query_url = $api_endpoint . '?q=' . $soql_query;

    $args = [
        'method'  => 'GET',
        'timeout' => 30,
        'headers' => [
            'Authorization' => 'Bearer ' . $access_token,
            'Accept'        => 'application/json',
        ],
    ];

    $response = wp_remote_get( $query_url, $args );

    if ( is_wp_error( $response ) ) {
        return new WP_Error( 'salesforce_api_error', sprintf( __( 'Salesforce API request failed: %s', 'your-text-domain' ), $response->get_error_message() ) );
    }

    $response_code = wp_remote_retrieve_response_code( $response );
    $response_body = wp_remote_retrieve_body( $response );
    $response_data = json_decode( $response_body, true );

    if ( $response_code !== 200 || ! isset( $response_data['records'] ) ) {
        $error_message = isset( $response_data['error_description'] ) ? $response_data['error_description'] : $response_body;
        return new WP_Error( 'salesforce_api_error', sprintf( __( 'Failed to fetch Salesforce accounts. Response: %s', 'your-text-domain' ), $error_message ) );
    }

    return $response_data['records'];
}

// Example usage within your plugin:
add_action( 'admin_init', function() {
    $access_token = get_salesforce_access_token();

    if ( ! is_wp_error( $access_token ) ) {
        $accounts = fetch_salesforce_accounts( $access_token, SALESFORCE_MY_DOMAIN_URL );

        if ( ! is_wp_error( $accounts ) ) {
            // Process the $accounts array
            error_log( 'Successfully fetched Salesforce accounts: ' . print_r( $accounts, true ) );
        } else {
            error_log( 'Error fetching Salesforce accounts: ' . $accounts->get_error_message() );
        }
    } else {
        error_log( 'Error obtaining Salesforce access token: ' . $access_token->get_error_message() );
    }
});

Security Considerations and Best Practices

  • Private Key Security: The private key file (salesforce_private.key) is highly sensitive. It should be stored outside the webroot (e.g., in a directory above wp-content) and have strict file permissions (e.g., chmod 400). Never commit it to version control.
  • Error Handling and Logging: Implement comprehensive error handling and logging for all API interactions. This is crucial for debugging and monitoring. Use WordPress’s error_log() or a dedicated logging plugin.
  • Token Expiration and Refresh: Salesforce access tokens expire (typically after 2 hours). The JWT Bearer Flow can be used to obtain new tokens. Implement logic to check token validity and refresh it proactively or when an API call fails with an authorization error.
  • Rate Limiting: Be mindful of Salesforce API limits. Implement retry mechanisms with exponential backoff for transient errors, but avoid excessive calls that could lead to your integration being throttled.
  • HTTPS: Always use HTTPS for all communication between WordPress and Salesforce.
  • WordPress Options API: For production, consider storing sensitive configuration (Consumer Key, My Domain URL, private key path) in the WordPress Options API (e.g., using `update_option()` and `get_option()`) rather than hardcoding them as constants. Encrypt sensitive values if stored directly in the database.
  • Dependency Management: For more complex JWT signing or certificate handling, consider using a well-vetted PHP library like firebase/php-jwt. Ensure you understand its security implications and proper usage.
  • Salesforce API Versioning: Salesforce frequently updates its API. Ensure your integration uses a supported and appropriate API version and plan for updates.

By following these steps, you can establish a secure and reliable integration between your WordPress custom plugin and Salesforce CRM endpoints, enabling powerful data synchronization and automation scenarios.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • How to securely integrate OpenAI Completion API endpoints into WordPress custom plugins using Heartbeat API
  • Advanced Diagnostics: Identifying and fixing theme asset blocking in Elementor custom widgets layouts
  • How to build custom Sage Roots modern environments extensions utilizing modern Block Patterns API schemas
  • Troubleshooting Zend memory limit exceed in production when using modern Genesis child themes wrappers
  • WordPress Development Recipe: Secure token-based API authentication for Mailchimp Newsletter in custom plugins

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (658)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (872)
  • PHP (5)
  • PHP Development (38)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (15)
  • WordPress Plugin Development (14)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • How to securely integrate OpenAI Completion API endpoints into WordPress custom plugins using Heartbeat API
  • Advanced Diagnostics: Identifying and fixing theme asset blocking in Elementor custom widgets layouts
  • How to build custom Sage Roots modern environments extensions utilizing modern Block Patterns API schemas

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (872)
  • Debugging & Troubleshooting (658)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala