Acumatica Integration Losses Authentication

LeifZ

Customer
Joined
Feb 14, 2025
Messages
17
Reaction score
2
I have an integration that appears to work, however the authentication does not seem to stick. After a period, hours or days not sure yet, it loses authentication and silently fails. I run the Test function from the CRM Integration screen and I get the error

Server returned a non successful status code - HTTPStatusCode=BadRequest - Reason=Bad Request - Content={"error":"invalid_grant"}

The OAuth Method in the CRM is "Authorization Code", Refresh Token Mode "Absolute", 30 days.

Attached is the template. Do you have any suggestions?
 

Attachments

Hi,

Have you reached out to the Acumatica community, as they should be better able to help you figure this one out.

Best,
K.
 
  • Like
Reactions: Evolute IT
Most probably, the CRM is revoking the Refresh Token after some time. This is very common, for example Dynamics 365 does this as well. Every time you get an Access Token, the API probably returns a new Refresh Token. If you don't save it, you will keep using the Refresh Token obtained during authorization, and after some time it will stop working.

In order to save the Refresh Token, add the following line inside the Outputs element in your Auth scenario:
XML:
<Output Type="RefreshToken" Value="[RefreshToken]" />

That should fix your issue.
 
I do not think that helped, the first test works, the second now fails with

Server returned a non successful status code - HTTPStatusCode=BadRequest - Reason=Bad Request - Content={"error":"invalid_grant"}

This is my Auth Scenario now.
C#:
    <Scenario Id="Auth" Type="REST" EntityId="" EntityOrder="">
      <Request SkipIf="" Url="[Domain]/identity/connect/token" MessagePasses="0" Message="" RequestContentType="application/x-www-form-urlencoded" RequestEncoding="UrlEncoded" RequestType="Post" ResponseType="Json">
        <PostValues Key="" If="" SkipIf="">
          <Value Key="refresh_token" If="" SkipIf="" Passes="0" Type="String">[RefreshToken]</Value>
          <Value Key="grant_type" If="" SkipIf="" Passes="0" Type="String">refresh_token</Value>
          <Value Key="client_id" If="" SkipIf="" Passes="0" Type="String">[ClientId]</Value>
          <Value Key="client_secret" If="" SkipIf="" Passes="0" Type="String">[ClientSecret]</Value>
        </PostValues>
      </Request>
      <Rules>
        <Rule Type="Any" Ethalon="">access_token</Rule>
      </Rules>
      <Variables>
        <Variable Name="AccessToken" LookupValue="" Path="">access_token<Filter /></Variable>
        <Variable Name="ExpiresIn" LookupValue="" Path="">expires_in<Filter /></Variable>
        <Variable Name="RefreshToken" LookupValue="" Path="">refresh_token<Filter /></Variable>
      </Variables>
      <Outputs AllowEmpty="false">
        <Output Type="Bearer" Passes="0" Value="[AccessToken]" />
        <Output Type="BearerExpiration" Passes="0" Value="[ExpiresIn]" />
        <Output Type="RefreshToken" Value="[RefreshToken]" />
      </Outputs>
    </Scenario>

The first Test Works this is the Log

Code:
Started scenario with empty id
Started Auth
Request text: https://garypools.acumatica.com
Request form value refresh_token set to Mpo0ZAcmdJW1AYvtbQY-l-MtyIBvlIB7H6JOcAGWUFY
Request form value grant_type set to refresh_token
Request form value client_id set to 1FB6E748-3F59-8C9C-45ED-FD44BFAD7E1E@Gary Pools
Request form value client_secret set to pJS_xjYI7FPtbClfTZaZ-A
Response text: ********
Response finished
Variable AccessToken set to _GaTa7qAgxT0VtfM91g40dJzoqlNEjt7e_y5wzChMhU
Variable ExpiresIn set to 3600
Variable RefreshToken set to 3lfq8qNW8s6irO4dPVDQv38zwUYYEBM0IYosFug55HU
Finished Auth
Request text: https://garypools.acumatica.com
Request message: {"SearchPhone":{"Value":"8232894"}}
Response text: {"id":"2e6d9f17-0c74-4030-beaa-cc59c368be34","rowNumber":1,"note":null,"AccountName":{},"ContactID":{"value":46991},"CustomerID":{"value":"CUS043940"},"CustomerName":{"value":"Zars II, Leif & Brittany"},"Email":{"value":"[email protected]"},"FirstName":{"value":"Leif & Brittany"},"LastName":{"value":"Zars II"},"Phone1":{"value":"2108232894"},"Phone1Type":{"value":"Business 1"},"Phone2":{},"Phone2Type":{"value":"Business 2"},"Phone3":{},"Phone3Type":{"value":"Home"},"Phone4":{},"Phone4Type":{"value":"Fax"},"SearchPhone":{"value":"8232894"},"ThreeCXSearchCustomersDetails":[{"id":"512f3d8f-5d0a-442a-b4fb-ece7307385af","rowNumber":1,"note":null,"AccountName":{},"ContactID":{"value":46991},"CustomerID":{"value":"CUS043940"},"CustomerName":{"value":"Zars II, Leif & Brittany"},"FirstName":{"value":"Leif & Brittany"},"LastName":{"value":"Zars II"},"NoteID":{"value":"9dfe85b1-9b2f-ee11-8350-125aba3e7187"},"Phone1":{"value":"2108232894"},"Phone1Type":{"value":"Business 1"},"Phone2":{},"Phone2Type":{"value":"Business 2"},"Phone3":{},"Phone3Type":{"value":"Home"},"Phone4":{},"Phone4Type":{"value":"Fax"},"custom":{}}],"custom":{}}
Response finished
Variable EntityId set to 9dfe85b1-9b2f-ee11-8350-125aba3e7187
Variable CustomerID set to CUS043940
Variable FirstName set to Leif & Brittany
Variable LastName set to Zars II
Variable CompanyName set to
Variable Email set to
Variable Phone1 set to 2108232894
Variable Phone1Type set to Business 1
Variable Phone2 set to
Variable Phone2Type set to Business 2
Variable Phone3 set to
Variable Phone3Type set to Home
Variable Phone4 set to
Variable Phone4Type set to Fax
Finished scenario with empty id
Result obtained

The Second test fails

Code:
Started scenario with empty id
Started Auth
Request text: https://garypools.acumatica.com
Request form value refresh_token set to Mpo0ZAcmdJW1AYvtbQY-l-MtyIBvlIB7H6JOcAGWUFY
Request form value grant_type set to refresh_token
Request form value client_id set to 1FB6E748-3F59-8C9C-45ED-FD44BFAD7E1E@Gary Pools
Request form value client_secret set to pJS_xjYI7FPtbClfTZaZ-A
System.Exception: Server returned a non successful status code - HTTPStatusCode=BadRequest - Reason=Bad Request - Content={"error":"invalid_grant"}
   at Integration.Crm.Engine.ScenarioProcessorBase.ProcessRequest(Boolean authScenario, ScenarioRequest request, IValueManager customManager, HttpClient client, Boolean retry, CancellationToken token)
   at Integration.Crm.Engine.ScenarioProcessorBase.ProcessScenario(ProtocolScenario scenario, IValueManager customManager, SqlQueryParameter[] sqlQueryParameter, CancellationToken token)
   at Integration.Crm.Engine.ScenarioProcessorBase.Execute(ProtocolScenario scenario, SqlQueryParameter[] sqlQueryParameter, CancellationToken token)
   at Integration.Crm.Engine.ScenarioAuthHttpClientProvider.PerformScenarioIfNeeded(CancellationToken token)
   at Integration.Crm.Engine.ScenarioAuthHttpClientProvider.Create(CancellationToken token)
   at Integration.Crm.Engine.ScenarioProcessorBase.ProcessScenario(ProtocolScenario scenario, IValueManager customManager, SqlQueryParameter[] sqlQueryParameter, CancellationToken token)
   at Integration.Crm.Engine.ScenarioProcessorBase.Execute(ProtocolScenario scenario, SqlQueryParameter[] sqlQueryParameter, CancellationToken token)
   at Integration.Crm.Engine.CrmProcessor.GetContactInfoFromCrm(List`1 result, IEnumerable`1 scenariosToProcess, IValueManager customManager, SqlQueryParameter[] sqlQueryParameters, Func`2 filterResultsFunctor, Boolean exactMatch, CancellationToken token)
   at Integration.Crm.Engine.CrmProcessor.GetContactInfo(String contactNumber, InteractionTypes interactionType, CancellationToken token)
 
Hi,

Have you reached out to the Acumatica community, as they should be better able to help you figure this one out.

Best,
K.
I did talk with Acumatica. The have a dev instance that I pointed 3CX at and they reviewed with me the authentication process and showed that Acumatica was responding correctly. I am just not processing the RefreshToken correctly in 3CX.

I also used postman to query Acumatica with the exact same authentication schema, and it worked well.
 
I read once that there was a bug in 3CX that resulted in authentication errors in the testing method similar to what I am experiencing, but not in the general use of the CRM integration. And I think this is the case, because currently if I run the test twice, it fails due to authentication. However, in 3CX I can make multiple queries in the contacts list that return CRM results just fine.

However, after several hours the connection is lost and the CRM functionality stops.

I did a quick search for this old bug report, but I was unable to find it.
 
What version are you using? V20u6 fixes that problem. We reported it a while back.
 
Can you spot any difference when you compare the request sent by Postman and the request sent by 3CX? If the CRM dev team can help you, maybe they can tell you what they're receiving and what's causing that 400 error response? They will be able to tell you if the refresh_token being sent in the second request is correct or not.
 
  • Like
Reactions: Evolute IT
Okay, I will get some logs and submit them.