2

I have a batch class that uses query locator to send data into the client's server. however, it must first authenticate and get access token and send that along with the data with all consecutive post request. Now my questions are,

  • what batch method should I use for my authentication call out? is it going to be the start method? or the execute method?

(I need to get one access token only once per batch run not for each call out, the token will be valid for 24hrs)

  • If you suggest using the execute method, please let me know about the best practices for making the authentication request only at the first batch run.

    Cheers!!

  • can someone please tell me the reason I've got a downvote? – Bahman.A Aug 9 at 19:15
  • 2
    I didn't downvote, but the question could have shown more research, what you've tried, and why you're stuck. – Thomas Taylor Aug 9 at 19:20
  • 2
    Thanks, @ThomasTaylor, I did do research and tried different ways but didn't want to make my question hard to follow by including all those, but I totally get your point and in the first chance I'll update my question based on your suggestions. – Bahman.A Aug 9 at 19:32
5

I would do something like,

1) Do callout in start method, and store the access token in a class-level variable.

2) In order to maintain state for a class level variable I would make Batch as Stateful

3) execute can use access token from class variable

4) Finish method can again do callout to invalidate the accesstoken. (Even if you dont do this, the session wont be stored anywhere so its safe to assume it wont be missussed and noone from the outside will be able to access it)

  • would you please help me find out the major differences a far as benefits and drawbacks between your suggested approach and the one from @Thomas Taylor? – Bahman.A Aug 9 at 19:36
  • 1
    For your scenario, I think Pranay's method is probably best. It's more secure, and you definitely won't end up re-authing during a batch run. But if there's any risk that the webservice would want you to re-auth during a batch run, it's harder to recover from that with Pranay's method. – Thomas Taylor Aug 9 at 19:50
5

I just had a similar requirement that I'm filling by using Platform Cache to hold the token and its expiration timestamp. It looks basically like this:

public class WSAuthentication {
    public static string getSessionToken() {
        String token = (String)Cache.org.get('wsToken');
        Datetime expires = (Datetime)Cache.org.get('wsExpiration');
        if (token != null && expires > Datetime.now().addMinutes(5)) {
            return token;
        } else {
            token = authAndCache();
            return token;
        }
    }
    private static String authAndCache() {
        HttpRequest req = new HttpRequest();
        req.setEndpoint('callout:webservice/Authenticate');
        req.setMethod('POST');
        req.setHeader('Content-Type','application/json'); 
        req.setBody('{"Username": "{!$Credential.UserName}",' +
            '"Password": "{!$Credential.Password}"}');
        Http http = new Http();
        HTTPResponse res = http.send(req);
        String wsToken;
        DateTime wsExpiration;
        // wsAuthResponse is a class that models the expected authentication JSON response
        wsAuthResponse authResponse = (wsAuthResponse)JSON.deserialize(res.getBody(),wsAuthResponse.class);
        if (res.getStatusCode() == 200) {
            wsToken = authResponse.session_token;
            wsExpiration = authResponse.session_token_expiration;
            Cache.Org.put('wsToken', wsToken, 3600, Cache.Visibility.ALL, true);
            Cache.Org.put('wsExpiration', wsExpiration, 3600, Cache.Visibility.ALL, true);
            return wsToken;
        } else {
            System.debug('Webservice Authorization failed!');
            System.debug(authResponse);
            return null;
        }
    }
}

I call the getSessionToken() method when I'm building the callout with the actual data payload. If the token is in the cache and hasn't expired, it's right there. But then it falls back to reauthenticating if it's not. This web service's tokens are good for an hour, so that's why I'm setting the cache TTL to 1 hour.

You could do similarly, and call the getSessionToken() from your execute() method. The first time, it will authenticate and cache the token. Subsequent batches will get the the cached token. Now, if there's a restriction that you only are allowed to auth once per 24 hours, this won't be a good fit, because Platform Cache gets can miss at any time, even within the TTL.

  • 2
    +1. Or clear cache in finish method. – Pranay Jaiswal Aug 9 at 19:29
  • 2
    Not applicable to my requirement, where I want the token to be reused across calls from a trigger to a queueable, but that would be more secure in the asker's batchable scenario. – Thomas Taylor Aug 9 at 19:32
  • great approach, thanks a lot! – Bahman.A Aug 9 at 19:35
  • 2
    It won't fail, or return null if there is a value stored in the Cache. But the cached item can be removed from the cache before its designated TTL has passed, The docs say "Cache misses can happen. We recommend constructing your code to consider a case where previously cached items aren’t found." – Thomas Taylor Aug 9 at 19:43
2

One approach would be to store the token and its expiration date in Platform Cache. In the batch execute method, you would check the token in the cache. If you need to get a new token, call your authentication method and store the token in cache.

  • GMTA, but some are slower than others. :-) – Thomas Taylor Aug 9 at 19:15
  • Meaning I posted my longer but equivalent response after your speedy one! – Thomas Taylor Aug 9 at 20:54
  • Yup, your code is a great example! – David Cheng Aug 10 at 0:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.