2

Is it possible to use Google OAuth and have no UI ever?

My thought is: save the account credentials and refresh token into a custom setting and keep calling that every time. So the flow would look something like:

  1. We Authorize with this URL: https://accounts.google.com/o/oauth2/auth?client_id=123456789&response_type=code&scope=https://www.googleapis.com/auth/theappweareusing&redirect_uri=/apex/testHTMLPage&access_type=offline
  2. Rather then redirecting us when we are done to testHTMLPage and getting back the code parameter with the authorization code in the URL, is is possible to pass back the authorization code in another way? I do not want to have to display any pages in order to get the code.
  3. Save the authorization code into a custom setting
  4. We take the authorization code from the custom setting and use it to exchange for the authorization token and refresh token
  5. Save the refresh token in a custom setting
  6. Once I have both of these tokens, I call the https://accounts.google.com/o/oauth2/token and pass it the token, the key, and the secret (no need for the redirect uri)
  7. I should get back a response status code of 200 and can move on from there

My end goal is to have a Trigger callout to a google api without any user interaction. I would like everything to seamlessly run in the background.

5
  • 2
    Not sure why this is off topic - the user is asking about what is the best approach to making a callout to Google from Salesforce which is hard to do, and seems like a valid question. Commented Mar 22, 2018 at 15:56
  • 1
    A couple things: 1. You can't make a callout from a trigger; 2. You can use the same refresh token for all users in the org, this is a Named Principal pattern - rather than a per user approach. 3. You'll need to authorize and capture a token at least one time, maybe an admin sets it up once and then all users of the org share this token / identity at Google.
    – Mark Pond
    Commented Mar 22, 2018 at 16:17
  • Are you trying to do something like using Google's Geocoding API to enrich records?
    – Mark Pond
    Commented Mar 22, 2018 at 16:24
  • Yeah I don't follow why this question was closed as off topic.
    – Adrian Larson
    Commented Mar 22, 2018 at 16:41
  • @MarkPond I am using Googles Double Click API to track data on our leads
    – Olivia
    Commented Mar 22, 2018 at 18:36

1 Answer 1

4

That approach should work - I've made this work with the refresh token to retrieve Google Analytics data each night. I store the refresh token in a setting, and when I need to access GA, I get a new token as you described.

You'll need to put in place error handling for when the access token expires so you can get a new token, and I found Google's oAuth to be flaky, so worth putting in a second attempt to get the token if the first one fails.

One tip I also saw here was to use the Platform Cache feature to store the access token since that is available in batches etc...so store the token, and then check for expiration before you use it and only get a new one when you need it.

I have also been looking at implementing the Auth.JWT method with a certificate based on some other posts on StackEx. That seems to work fine in testing so that's another option, and then doesn't require storing refresh tokens e.g.

    String AUTH_ENDPOINT = 'https://www.googleapis.com/oauth2/v4/token';
    //Using a Custom Setting for values like scope, ISS & Certificate Name
    String SCOPE = gaSettings.JWT_Scope_Value__c;

            Auth.JWT jwt = new Auth.JWT();
            jwt.setAud(AUTH_ENDPOINT);
            jwt.setIss(gaSettings.ISS_Value__c);
            jwt.setAdditionalClaims(new Map<String, Object>{
                    'scope' => SCOPE
            });

            // Create the object that signs the JWT bearer token with the 
            certificate from Certificate Management
            Auth.JWS jws = new Auth.JWS(jwt, gaSettings.Certificate_Name__c);

            // Get the access token
            Auth.JWTBearerTokenExchange bearer;
            try {
               bearer = new Auth.JWTBearerTokenExchange(AUTH_ENDPOINT, jws);
                String token;
                if (test.IsRunningTest() == FALSE) {
                    token = bearer.getAccessToken();
                }
                else {
                    token = 'X123456';
                }
                sAccessToken = token;
                cacheAccessToken(sAccessToken);
            } catch (Exception Ex) {
                sAccessToken = 'Token Creation Error';
            }
            return sAccessToken;
            }
8
  • when you say this should work- if I remove the redirect URL, how will I obtain the authorization code? And then how would I save it to a custom setting?
    – Olivia
    Commented Mar 22, 2018 at 14:12
  • So from what I remember, you do the first part (steps 1-4 ) in the Google Console and save the refresh token from that flow. That way, you should just need to store the Refresh Token along with Secret and Id in your setting in SFDC As long as the refresh token is valid, you can use it to get a new access token in your code without needing to do the authorization piece again Commented Mar 22, 2018 at 14:17
  • So once we get a refresh token from one person and save it, will I ever need another refresh token again (even if multiple people are using the google api)? And to me this means that we do, in fact, need the UI at some point to be able to authorize. Is this correct?
    – Olivia
    Commented Mar 22, 2018 at 14:46
  • We just used the same google user to get the analytics data and it is still working fine, several years later...so you'd only need the UI available if that google user might change at some point? Commented Mar 22, 2018 at 14:52
  • okay great, the google user shouldn't change ever, so I need a one time authorization in chrome console, save the refresh token, and from there I can call for the refresh token every time the access token is expired?
    – Olivia
    Commented Mar 22, 2018 at 14:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .