Background
I would like to connect to the REST API of a production org, from a sandbox org.
Configuration so far:
- Production Org has a
Connected App
- Sandbox Org has a
Auth. Provider
- Sandbox Org has a
Named Credential
- Apex code in the Sandbox org uses the
Named Credential
to access the Production Org REST API
1. Production Org – Connected App
- Connected App Name:
Sandbox
Enable OAuth Settings
is ticked- Callback URL:
https://x--x.cs83.my.salesforce.com/services/authcallback/Salesforce_REST_API
which is the sandbox - Selected OAuth Scopes:
full refresh_token
Require Secret for Web Server Flow
is ticked.- Noted the
Key
andSecret
for use later in the sandboxAuth. Provider
2. Sandbox Org – Auth. Provider
- Provider Type:
Salesforce
- Name:
Salesforce Production REST API
- URL Suffix:
Salesforce_REST_API
Consumer Key
set to the key from the Production Org Connected AppConsumer Secret
set to the Secret from the Production Org Connected AppAuthorize Endpoint URL
used the default valuehttps://test.salesforce.com/services/oauth2/authorize
Token Endpoint URL
uses the default valuehttps://test.salesforce.com/services/oauth2/token
3. Sandbox Org – Named Credential
- Label:
Salesforce Production REST API
- Name:
Salesforce_Production_REST_API
- URL:
https://xx.my.salesforce.com
which is the production org url - Identity Type:
Named Principle
- Authentication Protocol:
OAuth 2.0
- Authentication Provider:
Salesforce Production REST API
from step 2 - Scope:
full refresh_token
Start Authentication Flow on Save
is tickedGenerate Authorization Header
is tickedAllow Merge Fields in HTTP Header
is ticked
Saving starts the OAuth
process, and I successfully authenticate with my sandbox login details.
4. Apex code in the Sandbox org uses the Named Credential
The below code is called from a Lightning component which is running inside a publicly available community page.
public with sharing class ReportApi {
private final static String REPORTS_RESOURCE = '/services/data/v44.0/analytics/reports/';
private static HttpResponse get(String reportID) {
HttpRequest request = new HttpRequest();
request.setMethod(HttpMethod.GET);
request.setEndpoint('callout:Salesforce_Production_REST_API' + REPORTS_RESOURCE + reportID);
request.setTimeout(120000); // 2 Minutes
request.setHeader('Accept', 'application/json');
request.setHeader('Content-Type', 'application/json');
request.setHeader('Authorization','OAuth {!$Credential.OAuthToken}');
HttpResponse httpResponse = new Http().send(request);
return httpResponse;
}
}
Usage
HttpResponse response = ReportApi.get(reportId);
Yet I get this response from the production REST API:
{"message":"Session expired or invalid","errorCode":"INVALID_SESSION_ID"}
When I debug the HttpRequest I get this:
System.HttpRequest[Endpoint=callout:Salesforce_Production_REST_API/services/data/v44.0/analytics/reports/00O0O00000AYR0JUAX, Method=GET]
When I debug the HttpResponse I get this:
System.HttpResponse[Status=Unauthorized, StatusCode=401]
Question
- What is wrong with the above configuration?
- How should I configure the two orgs, to allow the Sandbox Org to access the Production Org's REST API?
Best Answer
The Sandbox Org
Auth. Provider
should have been configured to use:https://login.salesforce.com/services/oauth2/authorize
https://login.salesforce.com/services/oauth2/token
Which are the URLs for production login, allowing me to authenticate against the Production Org when using
OAuth