Skip to main content

Integrating Veeva Vault with Salesforce: OAuth 2.0, Apex REST & Architecture Guide

In plain words: Integrating Veeva Vault with Salesforce connects a life sciences regulatory content management system directly to your CRM. By authorizing Salesforce via OAuth 2.0 and making secure Apex REST callouts, pharmaceutical and biotech teams can search, preview, and link compliant medical documents, clinical trial data, and approved promotional materials without leaving Salesforce.

In life sciences and pharmaceutical organizations, managing regulated content requires strict adherence to global health authority standards (such as FDA 21 CFR Part 11). While Veeva Vault serves as the validated repository for clinical, regulatory, and commercial documentation, field teams operate daily inside Salesforce CRM and Life Sciences Cloud. Building a secure, programmatic bridge between these platforms streamlines access to approved collateral and maintains a synchronized regulatory audit trail.

1. Understanding the Veeva Vault & Salesforce Architecture

Veeva Vault provides an open REST API built on standard web protocols. Integrating Vault with Salesforce involves three core architectural tiers:

  • Authentication Tier: Employs OAuth 2.0 (Authorization Code Grant) or session-based API authentication to issue secure, scoped access tokens.
  • Data Access Tier (VQL): Uses Vault Query Language (VQL) over REST endpoints to search documents, retrieve metadata, and query audit histories.
  • UI Presentation Tier: Surfaces Vault document links and metadata inside Salesforce using Lightning Web Components (LWC) or Visualforce pages.
360 Veeva Vault Integration Card:
  • Protocol: REST API over HTTPS with JSON / URL-encoded form payloads.
  • Query Language: Veeva Vault Query Language (VQL) executed via /api/{version}/query.
  • Authentication: OAuth 2.0 / User-Session tokens passed via the Authorization or sessionId header.
  • Modern Salesforce Tooling: External Credentials & Named Credentials for secure token lifecycle management without hardcoded secrets.

2. Step-by-Step Implementation: Authentication & Token Exchange

Step 1: Configure Network & Remote Site Settings
Navigate to Setup > Security > Remote Site Settings in Salesforce and whitelist your specific Veeva Vault domain (e.g., https://mycompany.veevavault.com).
Step 2: Apex OAuth Service & Document Fetcher
Create an Apex controller to manage the authorization redirect, token exchange, and VQL document queries.
public with sharing class VeevaVaultService {

    // Store credentials securely in Custom Metadata or Named Credentials
    private static final String VAULT_BASE_URL = 'https://mycompany.veevavault.com';
    private static final String CLIENT_ID = 'your_client_id';
    private static final String CLIENT_SECRET = 'your_client_secret';
    private static final String REDIRECT_URI = 'https://yourinstance.salesforce.com/apex/VeevaCallback';

    // Generate OAuth Authorization URL
    public static String getAuthorizationUrl() {
        return VAULT_BASE_URL + '/oauth/authorize?response_type=code' +
            '&client_id=' + EncodingUtil.urlEncode(CLIENT_ID, 'UTF-8') +
            '&redirect_uri=' + EncodingUtil.urlEncode(REDIRECT_URI, 'UTF-8') +
            '&state=' + EncodingUtil.urlEncode(Crypto.getRandomInteger().format(), 'UTF-8');
    }

    // Exchange Authorization Code for an Access Token
    public static String exchangeCodeForToken(String authCode) {
        HttpRequest req = new HttpRequest();
        req.setEndpoint(VAULT_BASE_URL + '/oauth/token');
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/x-www-form-urlencoded');

        String payload = 'grant_type=authorization_code' +
            '&code=' + EncodingUtil.urlEncode(authCode, 'UTF-8') +
            '&client_id=' + EncodingUtil.urlEncode(CLIENT_ID, 'UTF-8') +
            '&client_secret=' + EncodingUtil.urlEncode(CLIENT_SECRET, 'UTF-8') +
            '&redirect_uri=' + EncodingUtil.urlEncode(REDIRECT_URI, 'UTF-8');

        req.setBody(payload);

        Http http = new Http();
        HttpResponse res = http.send(req);

        if (res.getStatusCode() == 200) {
            Map<String, Object> responseBody = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
            return (String) responseBody.get('access_token');
        } else {
            throw new CalloutException('Veeva Vault Authentication Failed: ' + res.getBody());
        }
    }

    // Query Approved Documents using VQL (Vault Query Language)
    public static String queryApprovedDocuments(String accessToken) {
        HttpRequest req = new HttpRequest();
        String vqlQuery = EncodingUtil.urlEncode('SELECT id, name__v, status__v FROM documents WHERE status__v = \'Approved\' LIMIT 10', 'UTF-8');
        req.setEndpoint(VAULT_BASE_URL + '/api/v24.1/query?q=' + vqlQuery);
        req.setMethod('GET');
        req.setHeader('Authorization', accessToken);
        req.setHeader('Accept', 'application/json');

        Http http = new Http();
        HttpResponse res = http.send(req);
        return res.getBody();
    }
}
Step 3: User Interface for Connection Initiation
Expose a connection trigger to users via Visualforce or a Lightning Web Component.
<apex:page controller="VeevaVaultService">
    <apex:form>
        <apex:pageBlock title="Veeva Vault Integration Console">
            <apex:pageBlockButtons location="top">
                <apex:commandButton value="Authorize Veeva Vault" 
                                    onclick="window.open('{!authorizationUrl}', '_blank'); return false;" />
            </apex:pageBlockButtons>
            <p>Connect to Veeva Vault to synchronize clinical documents and approved promotional assets.</p>
        </apex:pageBlock>
    </apex:form>
</apex:page>

3. Common Traps & Compliance Best Practices

Security & Regulatory Trap: Hardcoding API Secrets & Unencrypted Tokens
Hardcoding Client Secrets in Apex classes breaches security standards and violates 21 CFR Part 11 audit requirements. Furthermore, access tokens must never be exposed in client-side cookies or debug logs. Always store secrets in Protected Custom Metadata or use Salesforce Named Credentials.
Core Rule: Use Salesforce Named Credentials with OAuth 2.0 to automate token refresh lifecycles, and use parameterized Vault Query Language (VQL) over HTTPS to maintain regulatory audit trails.
  • Leverage Named Credentials: Replace manual token exchange endpoints with native Salesforce Named Credentials to eliminate custom token refresh code.
  • Maintain 21 CFR Part 11 Compliance: Ensure all document retrieval operations in Salesforce record an audit log entry detailing the user ID, timestamp, and document version accessed.
  • Sanitize VQL Input Parameters: Always encode and sanitize user input before concatenating values into VQL strings to prevent injection vulnerabilities.

Summary

Connecting Veeva Vault with Salesforce enables life sciences organizations to bridge regulatory content management with active CRM operations. By leveraging OAuth 2.0 authentication, robust Apex HTTP callouts, and VQL data retrieval, development teams can deliver a compliant, seamless document management experience directly within Salesforce.