Session ID from scheduled jobs
You will need to establish a session from within the Scheduled job.
As a proof of concept I managed to get this working by using the OAuth 2.0 Username-Password Flow. You make a HTTP POST request from Salesforce-to-Salesforce to request an Access Token which can then be used as a Session ID.
You will need to create a new Remote Access Application where you will get Consumer Key (client_id) and Consumer Secret (client_secret). You will also need to create a new Remote Site Setting for the Token Endpoint URL so a POST request can be sent to it.
public class UsernamePasswordFlow {
String username;
String password;
String clientId;
String clientSecret;
String tokenEndpoint = 'https://test.salesforce.com/services/oauth2/token';
public UsernamePasswordFlow(String username, String password, String clientId, String clientSecret) {
this.username = username;
this.password = password;
this.clientId = clientId;
this.clientSecret = clientSecret;
}
public String requestAccessToken() {
HttpRequest req = new HttpRequest();
req.setEndpoint(tokenEndpoint);
req.setMethod('POST');
req.setBody(buildHttpQuery(new Map<String, String> {
'grant_type' => 'password',
'username' => username,
'password' => password,
'client_id' => clientId,
'client_secret' => clientSecret
}));
Http http = new Http();
HttpResponse resp = http.send(req);
Map<String, Object> m =
(Map<String, Object>) JSON.deserializeUntyped(resp.getBody());
return (String) m.get('access_token');
}
static String buildHttpQuery(Map<String, String> queryParams) {
if (queryParams.isEmpty()) {
return '';
}
String[] params = new String[] {};
for (String k : queryParams.keySet()) {
String v = EncodingUtil.urlEncode(queryParams.get(k), 'UTF-8');
params.add(String.format('{0}={1}', new String[] { k, v }));
}
return String.join(params, '&');
}
}
Example Usage:
UsernamePasswordFlow upf = new UsernamePasswordFlow(
'[email protected]',
'mypassword',
'3MdPGzpc3Iwg5lcwtc7HAprnDCVG9JNJ1CQBISiBA9bE1WXe_xlItLNdlxckCVyIo',
'436267497522435674970'
);
String sessionId = upf.requestAccessToken();
Unfortunately the drawback to this approach is having the store the credentials, in my case I used a custom settings object to store them. So there are security concerns to take into consideration.
Here's my suggestion:
Use Outbound Messaging, which contains the capability to pass the Session ID for the purpose of you using it to call back.
Set up a workflow rule on a custom object to fire when a record is changed and send the outbound message.
Use your scheduled job to modify the custom object, thus firing the workflow rule and sending the outbound message and session id.