How to get State in the OAuth2 authorization callback?
I am passing in a state property into OAuth2.getAuthorizationUrl(...). The documentation does not detail how to get that state back when the Callback is performed. How does one access that stored state value? I need it so that in the callback I can redirect to the correct app once I get an id token from Salesforce.
SFDC adds it as a query parameter in the callback.
Assuming you are using express your route is configured as /callback
oauthRoutes.get('/callback', async (req: Request, res: Response) => {
const environment = req.query.state; // SFDC sets the scope as a query parameter
const conn = new jsforce.Connection({ oauth2: getOAth2(environment) });
conn.authorize(code, function(err, userInfo) {
// .... remaining logic
}
Hey, I'm having an issue where my state parameter is being passed within the callback url and then im receiving an uri mismatch error from salesforce. I havent been able to figure out work around because I need the state data inside the callback end point to do some other processes. Any suggestions?
@jaagaard01 - here is how I am doing it with https://getjetstream.app/
If you are getting uri mismatch, it is probably a mis-configuration with the connected app in Salesforce compared to what you are providing in redirectUri. The redirectUri must be explicitly configured in the connected app including the port and match exactly.
Happy to help you troubleshoot more if you get stuck, I usually have the sdfx discord app open @AustinT - you can ping me there.
// Simple helper method just to init the oauth connection
export function getJsforceOauth2(loginUrl: string) {
return new jsforce.OAuth2({
loginUrl,
clientId: ENV.SFDC_CONSUMER_KEY,
clientSecret: ENV.SFDC_CONSUMER_SECRET,
redirectUri: ENV.SFDC_CALLBACK_URL,
});
}
/** HANDLE REDIRECT TO SFDC FOR AUTH */
export function salesforceOauthInitAuth(req: express.Request, res: express.Response) {
const loginUrl = req.query.loginUrl as string;
const clientUrl = req.query.clientUrl as string;
const replaceOrgUniqueId = req.query.replaceOrgUniqueId as string | undefined;
const state = querystring.stringify({ loginUrl, clientUrl, replaceOrgUniqueId });
let options = {
scope: 'full refresh_token',
state,
prompt: 'login',
};
if (req.query.username) {
options = Object.assign(options, { login_hint: req.query.username });
}
res.redirect(getJsforceOauth2(loginUrl).getAuthorizationUrl(options));
}
/** HANDLE RESPONSE FROM SFDC */
export async function salesforceOauthCallback(req: express.Request, res: express.Response) {
try {
const user = req.user as UserProfileServer;
const state = querystring.parse(req.query.state as string);
const loginUrl = state.loginUrl as string;
const clientUrl = state.clientUrl as string;
const replaceOrgUniqueId = state.replaceOrgUniqueId as string | undefined;
// ERROR PATH
if (req.query.error) {
const errorMsg = req.query.error_description ? req.query.error_description : 'There was an error authenticating Salesforce.';
const errorObj = { message: errorMsg, error: req.query.error };
return res.redirect(`/assets/oauth?${querystring.stringify(errorObj as any)}`);
}
const conn = new jsforce.Connection({ oauth2: getJsforceOauth2(loginUrl as string) });
// ..... TRUNCATED //
@paustint awesome this helps me a lot thank you!