Search code examples
google-chromegoogle-chrome-extensionoauth-2.0oauthsalesforce

Authenticate to Salesforce in Chrome extension


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/*"]
}

enter image description here

enter image description here

enter image description here


Solution

  • 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;
      }
    });