I am trying to authenticate to Salesforce in Chrome extension, but I am getting 400 error. If I try this code in Express.js server, it works.
background.js
console.log("Extension loaded");
let user_signed_in = false;
const clientId =
"xyz";
const callbackUrl = "https://dfghlbaebomdoihlfmegbpcmfkfgfno.chromiumapp.org";
const getSalesforceLoginLink = async () => {
const res = await fetch(
`https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id=${clientId}&redirect_uri=${callbackUrl}`
);
if (res.status === 200) {
// append login link
return res.url;
} else {
console.error("Not able to fetch login link");
}
};
const authenticateSalesforce = (salesforceLink) => {
chrome.identity.launchWebAuthFlow(
{
url: salesforceLink,
interactive: true,
},
function (redirect_url) {
const codeParam = searchParams.get('code');
let authCode = codeParam;
const loginUrl = `https://login.salesforce.com/services/oauth2/token?grant_type=authorization_code&redirect_uri=${
process.env.SALESFORCE_CALLBACK_URL
}&client_id=${process.env.SALESFORCE_CLIENT_ID}&client_secret=${
process.env.SALESFORCE_CLIENT_SECRET
}&code=${encodeURIComponent(authCode)}`;
const response = await fetch(loginUrl)
.then(function (response) {
return response?.json();
})
.then(function (data) {
return data;
});
if (chrome.runtime.lastError) {
sendResponse({ message: "fail" });
} else {
console.log({ redirect_url });
}
}
);
};
chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
if (request.message === "login") {
if (user_signed_in) {
console.log("User is already signed in.");
} else {
const salesforceLink = await getSalesforceLoginLink();
authenticateSalesforce(salesforceLink);
}
return true;
} else if (request.message === "logout") {
user_signed_in = false;
chrome.browserAction.setPopup({ popup: "./popup.html" }, () => {
sendResponse({ message: "success" });
});
return true;
}
});
manifest.json
{
"manifest_version": 3,
"name": "SF POC",
"description": "A quick way to browse top posts from DEV Community.",
"version": "0.0.1",
"action": {
"default_title": "SF POC"
},
"key": "xyz",
"background": {
"service_worker": "background.js"
},
"permissions": ["identity", "activeTab", "tabs", "windows"],
"host_permissions": ["https://login.salesforce.com/*"]
}
The issue you are encountering is due to the use of the fetch API to get the Salesforce login link. Chrome extensions follow the same-origin policy, so you cannot make cross-origin requests using the fetch API. In this case, you should directly use the URL constructed for Salesforce login as the URL parameter for chrome.identity.launchWebAuthFlow
.
Additionally, there seems to be an issue with the authenticateSalesforce function, as you are using the await keyword inside a non-async function. You should wrap the callback function with an async
function to avoid errors.
Here is the modified background.js
file:
console.log("Extension loaded");
let user_signed_in = false;
const clientId = "xyz";
const callbackUrl = "https://dfghlbaebomdoihlfmegbpcmfkfgfno.chromiumapp.org";
const getSalesforceLoginLink = () => {
return `https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id=${clientId}&redirect_uri=${callbackUrl}`;
};
const authenticateSalesforce = (salesforceLink) => {
chrome.identity.launchWebAuthFlow(
{
url: salesforceLink,
interactive: true,
},
async function (redirect_url) {
if (chrome.runtime.lastError) {
sendResponse({ message: "fail" });
} else {
const searchParams = new URLSearchParams(new URL(redirect_url).search);
const authCode = searchParams.get("code");
// Continue with your authentication flow using the authCode
console.log({ redirect_url });
}
}
);
};
chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
if (request.message === "login") {
if (user_signed_in) {
console.log("User is already signed in.");
} else {
const salesforceLink = getSalesforceLoginLink();
authenticateSalesforce(salesforceLink);
}
return true;
} else if (request.message === "logout") {
user_signed_in = false;
chrome.browserAction.setPopup({ popup: "./popup.html" }, () => {
sendResponse({ message: "success" });
});
return true;
}
});