top of page
Paulo Correia

Integrate Salesforce with Google Cloud using a Service Account



Connecting Salesforce with Google Cloud can provide a number of benefits to businesses, including streamlined workflows, improved data accuracy and reporting, and more efficient sales processes. Let's explore the steps required to connect Salesforce with Google Cloud, and provide a detailed explanation of the code.


To connect to Google Cloud using a service account, we need a Google Cloud project and obtain the necessary credentials. To do this, we must follow the following steps:

  1. Navigate to the Google Cloud Console and create a project, a bucket and a Service account

  2. Then create/Download the JSON key for the Service Account



Once we have obtained the JSON credentials, we can begin to integrate Salesforce with Google Cloud. To do this, we can use Salesforce's Apex programming language, which allows us to access Google Cloud APIs from within Salesforce.


The following code snippet provides an example of how to integrate Salesforce with the Google Cloud storage API:


public with sharing class GoogleApiTest {

 // NOTE - DONT PUT THIS KEY HERE IN A PROD SCENARIO - SEE ARTICLE ON SECURE CODING STORING SECRETS
  private static final String CLIENT_KEY = 'MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcpeDt533azc48\nXPBm9TVk6oS6kD...i1A2SlNSrm\n3xEj9GXn0N8aSJ0SvX++0F+R';
  private static final String CLIENT_SCOPE = 'https://www.googleapis.com/auth/devstorage.read_only';
  private static final String CLIENT_EMAIL = 'paulotest1@dulcet-field-376715.iam.gserviceaccount.com';

  public GoogleApiTest(){

    String jwt = generateJWT(CLIENT_KEY, CLIENT_SCOPE, CLIENT_EMAIL);
    Token t = getToken(jwt);
    System.debug(t);
  }

  public Token getToken(String jwt) {

    Httprequest req = new HttpRequest();
    req.setEndpoint('https://oauth2.googleapis.com/token');
    req.setMethod('POST');
    req.setHeader('Content-Type','application/x-www-form-urlencoded');

    String body = '';
    body = 'grant_type='+EncodingUtil.urlEncode('urn:ietf:params:oauth:grant-type:jwt-bearer','UTF-8');
    body += '&assertion='+jwt;
    req.setBody(body);

    Http h = new Http();
    HttpResponse res = h.send(req);
    System.debug('Response Body is '+res.getBody());  
    return (Token)JSON.deserialize(res.getBody(), Token.Class);
	}

  private String generateJWT(String key, String scope, String clientEmail){

    String header = '{"alg":"RS256","typ":"JWT"}';
    String headerUrlBase64Encode = EncodingUtil.base64Encode(Blob.valueOf(header));
    String headerBase64UrlEncode = EncodingUtil.urlEncode(headerUrlBase64Encode, 'UTF-8');

    long currentTime = datetime.now().getTime()/1000;
    long expiryTime = datetime.now().addHours(1).getTime()/1000;

    ClaimSet claimSet = new ClaimSet();
    claimSet.iss = clientEmail;
    claimSet.scope = scope;
    claimSet.aud = 'https://oauth2.googleapis.com/token';
    claimSet.exp = expiryTime;
    claimSet.iat = currentTime;

    String clailSetJson = JSON.serialize(claimSet);
    String claimSetBaseEncode = EncodingUtil.base64Encode(Blob.valueOf(clailSetJson));
    System.debug('claimSetBaseEncode '+claimSetBaseEncode);
    claimSetBaseEncode = claimSetBaseEncode.replaceAll('=', '');  
    String claimSetBase64UrlEncode = EncodingUtil.urlEncode(claimSetBaseEncode, 'UTF-8');
    System.debug('claimSetBase64UrlEncode '+claimSetBase64UrlEncode);
      
    String algorithmName = 'RSA-SHA256';
    Blob privateKey = EncodingUtil.base64Decode(key);
    Blob input = Blob.valueOf(headerBase64UrlEncode+'.'+claimSetBase64UrlEncode);
    Blob signed = Crypto.sign(algorithmName, input, privateKey);
    String signedBase64Encode = EncodingUtil.base64Encode(signed);
    String signedStrBase64UrlEncode = EncodingUtil.urlEncode(signedBase64Encode, 'UTF-8');

    String jwt = headerBase64UrlEncode+'.'+claimSetBase64UrlEncode+'.'+signedStrBase64UrlEncode;
    System.debug('jwt'+jwt);  
    return jwt;
  }

  private class ClaimSet{

    private String iss;
    private String scope;
    private String aud;
    private long exp;
    private long iat;
  }

  private class Token{

    private String access_token;
    private String token_type;
    private String expires_in;
  }

}

This class is used to generate and retrieve an OAuth2 token from the Google API. The token can be used to make authorized API calls to Google services.


The class contains three private static final strings for storing the Google API client key, scope, and email. It also contains a constructor that generates the JSON web token (JWT) using the private "generateJWT" method, and then uses it to retrieve the OAuth2 token using the private "getToken" method.


The "generateJWT" method is used to create the JWT by encoding the header, creating a claim set with the necessary parameters, and signing the JWT using the private key. The "getToken" method is used to send an HTTP POST request to the Google OAuth2 API endpoint, passing the JWT as an "assertion" parameter in the request body.


The following code was the key to make it to properly work:

claimSetBaseEncode = claimSetBaseEncode.replaceAll('=', '');


Note: how the pattern in Salesforce is:

EncodingUtil.base64Encode()
EncodingUtil.urlEncode()

Finally, the class contains two private inner classes, "ClaimSet" and "Token", which are used to deserialize the response JSON string into a token object. It also includes debugging statements for logging and testing purposes.


It should be noted that the client key should not be stored in the code as shown, as it poses a security risk. Instead, it should be stored in a secure location outside of the code, such as a protected custom setting, and accessed using a callout or other secure method.




13 views0 comments

Recent Posts

See All

Salesforce Certificate Order

We need 3 Certifcates 1.SSL Certificate. 2.CA Intermediate Certiticate. 3.Root Certifcate. If you dont got the root certitifcate from the...

29 Side Hustles

Dog walking or pet sitting Online tutoring or teaching Freelance writing or editing Graphic design Event planning or coordinating Virtual...

Comments


bottom of page