Resaving authentication provider results in website crash

GuzzleHttp\Exception\ClientException: Client error: `POST https://login.salesforce.com/id/00D280000017WCeEAM/00528000007KJm3AAG` resulted in a `403 Forbidden` response: Bad_OAuth_Token in GuzzleHttp\Exception\RequestException::create() (line 113 of /mnt/www/html/drupal8rockcoteevga9as9qv/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php).

Comments

VladimirAus created an issue. See original summary.

dougvann’s picture

I feel your pain, Vladimir!
See my workaround for this below in bold type. However, I hope there is a better solution for our shared problem.

Routinely, the D8/SF integration stops working and I discover that authentication has failed.

GuzzleHttp\Exception\ClientException: Client error: `POST https://test.salesforce.com/id/00D0t0000000uEaEAI/005f4000002oCbvAAE` resulted in a `403 Forbidden` response: Bad_OAuth_Token in GuzzleHttp\Exception\RequestException::create() (line 113 of /code/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php).

I go to admin/config/salesforce/authorize/list then select Edit.Re-Auth on the default provider.
I see the form and resubmit it and get "website encountered an error." After checking logs, I see the Guzzle error that Vladimir posted.
WORKAROUND : I create a brand new profile but I use the exact same values. Upon saving the form. I am redirected to test.salesforce.com where I log in and complete the authentication process.
Once authenticated, the clock starts ticking. Will I need to re-authenticate the next day OR the next week or maybe a few hours later?
The auth is not stable and WILL fail within some amount of time. If no one uses the form for a few days, then I get a break.
Maybe I am doing something wrong here OR maybe my client's SF Vendor is doing something that breaks the auth?

onewhocodes’s picture

I have this same issue doug. We created a new one and literally 2 days later over the weekend it broke again

aaronbauman’s picture

I've heard reports of this elsewhere, and have seen it a few times myself, but haven't figured out root cause yet.

One idea: Do you have any mappings set up to pull, so that an API query is issued regularly during cron, and the access token refreshed? Only 2 modules implement hook_cron(), and thereby keep the token refreshed: salesforce_push and salesforce_pull. Of those, only salesforce_pull_cron() is guaranteed to issue an API query: salesforce_push_cron() won't do anything if there's no content that's been modified.

onewhocodes’s picture

Aaron i do believe we do not have anything running on cron we are runnning a contact form which pushes into salesforce. It worked on friday and then broke again.

aaronbauman’s picture

What is supposed to happen is that, when the API client gets a "access token expired" message from Salesforce, it refreshes the token using the "refresh token" which should be set up to never expire. Something is not working in that process, though I don't know exactly where the breakdown is. Traditional OAuth being so annoying and opaque is one of the big reasons I recommend using JWT OAuth instead.

I'm happy to try and help here, and put in a patch if we can figure out a fix. But I can't reliable recreate this scenario in order to get a handle on it, and don't have time to track it down myself.

onewhocodes’s picture

I see. We will get our client to look at their sales force set up to see how long the expiry is set for

onewhocodes’s picture

Hi aaron , it looks like they never expire they have set the token to 0 hours which we assume is infinite?

aaronbauman’s picture

Here's the relevant bit in RestClient where the access token gets refreshed:

    try {
      $this->response = new RestResponse($this->apiHttpRequest($url, $params, $method));
    }
    catch (RequestException $e) {
      // RequestException gets thrown for any response status but 2XX.
      $this->response = $e->getResponse();

      // Any exceptions besides 401 get bubbled up.
      if (!$this->response || $this->response->getStatusCode() != 401) {
        throw new RestException($this->response, $e->getMessage(), $e->getCode(), $e);
      }
    }

    if ($this->response->getStatusCode() == 401) {
      // The session ID or OAuth token used has expired or is invalid: refresh
      // token. If refresh_token() throws an exception, or if apiHttpRequest()
      // throws anything but a RequestException, let it bubble up.
      $this->authToken = $this->authManager->refreshToken();
      try {
        $this->response = new RestResponse($this->apiHttpRequest($url, $params, $method));
      }
      catch (RequestException $e) {
        $this->response = $e->getResponse();
        throw new RestException($this->response, $e->getMessage(), $e->getCode(), $e);
      }
    }

Maybe it should be re-authing on Bad_OAuth_Token in addition to 401?

onewhocodes’s picture

Its quite possible. We could try updating this section of the code to try it? what would the amend need to be

onewhocodes’s picture

Ive added a die to the rest client , when I try to reauth , it doesn't hit this file at all?

aaronbauman’s picture

Status: Active » Needs review
StatusFileSize
new2.77 KB

Try this patch

onewhocodes’s picture

Aaron how do we apply patch files? is there a guide somewhere? we inherited this site from another party.

aaronbauman’s picture

Really depends on your setup. The simplest way is to run this command from within the salesforce module directory:
curl https://www.drupal.org/files/issues/2021-01-26/salesforce_oauth-redirect_dance-3191597.patch | git apply

onewhocodes’s picture

To confirm that would be modules/contrib/salesforce/modules or modules/contrib/salesforce

sidenote:

tried locally in each dir , it didn't apply?

vladimiraus’s picture

StatusFileSize
new2.56 KB

Modified patch to apply. Also trying it on my installation in the next couple of days.

onewhocodes’s picture

What did you do to get this to work? It will not apply at all for me. Just keeps saying 0 changed files

vladimiraus’s picture

@onewhocodes

onewhocodes’s picture

We have applied the patch, it worked for one day then we still keep getting faced with the same issue?

onewhocodes’s picture

Hi all

we are now facing a new error after the patch

OAuth\OAuth2\Service\Exception\MissingRefreshTokenException

vladimiraus’s picture

Status: Needs review » Reviewed & tested by the community

Everything worked after I applied the patch.
I had to reauthenticate and set new authentication method as default.

onewhocodes’s picture

Hey @Vladimir and @Aaron

Do you have any suggestions about
OAuth\OAuth2\Service\Exception\MissingRefreshTokenException

I also deleted all old integrations and set up a new one

Now I have this error ?

Error when connecting to Salesforce. Please check your credentials and try again: cURL error 6: Could not resolve host: sobjects (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)

vladimiraus’s picture

@onewhocodes Make sureyou reauthenticate and that none other environment is using different OAuth key.
I broke my prod environment by refreshing token on dev,

onewhocodes’s picture

If we go to this url

admin/structure/salesforce/mappings/manage/website_contact_form/fields

we see the error Error when connecting to Salesforce. Please check your credentials and try again: cURL error 6: Could not resolve host: sobjects (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)

However the connection said successfully connected something has broken and I have no idea what.

venkatadapa’s picture

Hi @Vladimir @onewhocodes

I am also getting same issue for each site for every environment. Please check your credentials and try again: cURL error 6: Could not resolve host: sobjects (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)

For me, it is working when I re-authenticate (resubmit the form) from url admin/config/salesforce/authorize/edit/oauth_full_sandbox. The issue is resolved, but I had to do the same for all sites in each environment after the code has been deployed to higher environments.

Can this be automated ?

aaronbauman’s picture

Version: 8.x-4.1 » 8.x-4.x-dev

Keep in mind when changing environments: access and refresh tokens are stored in settings, not config.

If you're changing between salesforce orgs during deploy, your tokens will not be invalid and need to be revoked afterwards.
This can be done in the UI, or via `drush salesforce:revoke-token`

  • AaronBauman committed 9bfd9e7 on 8.x-4.x
    Issue #3191597 by AaronBauman, VladimirAus: POST https://login....
aaronbauman’s picture

Status: Reviewed & tested by the community » Fixed

Committed. Thanks for everyone's contributions

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.