Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

July 28 - August 9 | Final Round of the Power BI Dataviz World Championships. This is your chance. Learn more

Reply
gilmore_staci
Helper II
Helper II

Query for Salesforce API connection

I have gone through salesforce help and they believe the issue is on the power bi side so checking here.

 

I have an external client app set up to api connect salesforce to power bi.  this is the code i'm using

 its giving me a DataSource.Error: Web.Contents failed to get contents from 'https://caterpillar.my.salesforce.com/services/oauth2/token' Bad Request  error. 

 

Am I missing something?

let
    // 1. Define Salesforce API credentials
    SalesforceUrl = "https://*Client*.my.salesforce.com",
    ClientId = "ClientKey",
    ClientSecret = "clientsecret",
    
    // 2. Request the OAuth2 Access Token
        TokenResponse = Json.Document(Web.Contents(SalesforceUrl & "/services/oauth2/token", [
        Content = Text.ToBinary("grant_type=client_credentials&client_id=" & ClientId & "&client_secret=" & ClientSecret),
        Headers = [#"Content-Type"="application/x-www-form-urlencoded"]
    ])),
    AccessToken = TokenResponse[access_token],

    // 3. Query the data using REST API (SOQL)
    DataResponse = Json.Document(Web.Contents(SalesforceUrl & "/services/data/v60.0/query", [
    Query =  [q="SELECT Id, Name, Email FROM User WHERE Profile.Name = 'System Administrator'"],
    Headers = [#"Authorization" = "Bearer " & AccessToken]
    ])),
    
    // 4. Parse the results into a table
    Records = DataResponse[records],
    Table = Table.FromList(Records, Record.FieldValues, {"Id", "Name", "Email"})
in
    Table
1 ACCEPTED SOLUTION
Prince0011
Solution Sage
Solution Sage

Hi,

Bad Request on the token endpoint almost always means Salesforce is rejecting the request itself (not a Power BI connectivity issue), so I'd look at these first:

1. Check the Connected App is actually set up for Client Credentials Flow This is the most common gotcha — just having a Client ID/Secret isn't enough. In Salesforce Setup, on your Connected App, you need "Enable Client Credentials Flow" explicitly turned on under OAuth settings, and there needs to be a "Run As" user assigned to it. If that's not configured, you'll get a Bad Request even with correct credentials.

2. Try capturing the actual error body, not just the status Right now you won't see Salesforce's actual error message because Power Query throws before you can inspect the response. Add ManualStatusHandling = {400} to your Web.Contents options so you can capture the response body:

TokenResponse = Web.Contents(SalesforceUrl & "/services/oauth2/token", [
    Content = Text.ToBinary("grant_type=client_credentials&client_id=" & ClientId & "&client_secret=" & ClientSecret),
    Headers = [#"Content-Type"="application/x-www-form-urlencoded"],
    ManualStatusHandling = {400}
]),
ResponseText = Text.FromBinary(TokenResponse)

Then just output ResponseText on its own to see what Salesforce is actually telling you (usually something like invalid_client_id or unsupported_grant_type which narrows it down immediately).

3. Double check there's no IP restriction issue If the Connected App or your Salesforce org has IP allowlisting/login IP ranges enforced, requests coming from Power BI's service (if this is going through the Power BI service rather than just Desktop) can get blocked at a level that also shows up as a generic Bad Request.

4. Confirm you're not mixing up Consumer Key/Secret with something else Sounds basic, but worth confirming ClientId/ClientSecret in your code are the actual Consumer Key and Consumer Secret from the Connected App's "Manage Consumer Details" page, not the connected app's Salesforce record Id or anything else.

Once you get the actual error text back from step 2, that'll tell you exactly which of these it is rather than guessing. Post that response back if you're still stuck and it'll be much easier to pin down.

View solution in original post

6 REPLIES 6
Divyaraj_Rathod
Helper II
Helper II

Bad Request from the token endpoint almost always hides a more specific error that Web.Contents swallows by default. First, add ManualStatusHandling = {400} to your Web.Contents options and parse the response body - that will show Salesforce's actual error code (e.g. invalid_client, unsupported_grant_type). Two common culprits: 1) The request body isn't URL-encoded - if your Client Secret has characters like +, /, or =, plain string concatenation will corrupt it. Build the body with Uri.BuildQueryString([grant_type="client_credentials", client_id=ClientId, client_secret=ClientSecret]) instead of manual string concatenation. 2) Client Credentials Flow needs to be explicitly enabled on your Connected App's OAuth policies with a designated "Run As" user - if that's not configured, Salesforce rejects the grant before it even checks your credentials. Worth confirming both of these with your Salesforce admin.

Prince0011
Solution Sage
Solution Sage

Hi,

Bad Request on the token endpoint almost always means Salesforce is rejecting the request itself (not a Power BI connectivity issue), so I'd look at these first:

1. Check the Connected App is actually set up for Client Credentials Flow This is the most common gotcha — just having a Client ID/Secret isn't enough. In Salesforce Setup, on your Connected App, you need "Enable Client Credentials Flow" explicitly turned on under OAuth settings, and there needs to be a "Run As" user assigned to it. If that's not configured, you'll get a Bad Request even with correct credentials.

2. Try capturing the actual error body, not just the status Right now you won't see Salesforce's actual error message because Power Query throws before you can inspect the response. Add ManualStatusHandling = {400} to your Web.Contents options so you can capture the response body:

TokenResponse = Web.Contents(SalesforceUrl & "/services/oauth2/token", [
    Content = Text.ToBinary("grant_type=client_credentials&client_id=" & ClientId & "&client_secret=" & ClientSecret),
    Headers = [#"Content-Type"="application/x-www-form-urlencoded"],
    ManualStatusHandling = {400}
]),
ResponseText = Text.FromBinary(TokenResponse)

Then just output ResponseText on its own to see what Salesforce is actually telling you (usually something like invalid_client_id or unsupported_grant_type which narrows it down immediately).

3. Double check there's no IP restriction issue If the Connected App or your Salesforce org has IP allowlisting/login IP ranges enforced, requests coming from Power BI's service (if this is going through the Power BI service rather than just Desktop) can get blocked at a level that also shows up as a generic Bad Request.

4. Confirm you're not mixing up Consumer Key/Secret with something else Sounds basic, but worth confirming ClientId/ClientSecret in your code are the actual Consumer Key and Consumer Secret from the Connected App's "Manage Consumer Details" page, not the connected app's Salesforce record Id or anything else.

Once you get the actual error text back from step 2, that'll tell you exactly which of these it is rather than guessing. Post that response back if you're still stuck and it'll be much easier to pin down.

@Prince0011 

#1 box is checked and user assigned is an api only salesforce integrated user

#2 i added the code to my query, cleared permissions and now when it asks how to connect it doesn't like the Anonymous i was using before.  Says its can't authenticate with the credentials provided

#3 this is a desktop connection, does the IP still apply?

#4 I re-entered the key and secret, using the copy button on salesforce instead of copy and pasting 

 

Any suggestions on #2?

Hi,

For #2, that's actually progress, Power BI is now treating the URL as needing real credentials since ManualStatusHandling changes how it handles the response. Try setting the connection to "Anonymous" again but do it through Data source settings (File > Options > Data source settings > find the URL > Edit Permissions), not the popup prompt, sometimes the popup defaults to a credential type that conflicts with what the query expects.

If that still fails, try clearing the cached credentials for that URL entirely first, then re-run the query so it prompts fresh.

On #3, yes, IP restrictions still apply even from Desktop if your org enforces login IP ranges at the org or profile level, not just for server-side calls, so worth ruling out

Hi @gilmore_staci,

Thanks for reaching out to the Microsoft Fabric Community forum. and thanks to @Prince0011 & @Murtaza_Ghafoor for sharing valuable insights.

 

Based on the official documentation, when the Content option is specified, the request is sent as an HTTP POST, and POST requests may only be made anonymously.

 

The documentation also explains that ManualStatusHandling only changes how Power Query handles the specified HTTP status codes. Instead of immediately raising a DataSource.Error, it allows the response to be processed so you can inspect details such as the response status.

 

Since Power BI is now indicating that it can't authenticate using Anonymous after adding

ManualStatusHandling and clearing the data source permissions, could you share the exact authentication error message (or a screenshot with any sensitive information removed)? That additional detail would help the community better understand what Power BI is reporting and assist with further troubleshooting.

 

For more details, please refer to the official documentation:

I hope this helps. Please feel free to reach out if you have any further questions.

Thank you.

 

Murtaza_Ghafoor
Super User
Super User

@gilmore_staci 

A 400 Bad Request from the Salesforce OAuth token endpoint typically specifies that the request is not properly formed rather than a Power BI issue.

Here are a few things to verify:

Ensure you're using the correct token endpoint for your org (production vs. sandbox), for example:

Production: https://login.salesforce.com/services/oauth2/token

Sandbox: https://test.salesforce.com/services/oauth2/token

If using a My Domain URL, confirm it's configured to accept OAuth token requests.

Check from Postman

Test the same OAuth request using Postman or cURL. If it also returns 400 Bad Request, the issue is with the OAuth request or Salesforce configuration rather than Power BI.

If this helps, ✓ Mark as Kudos | Help Others



Helpful resources

Announcements
Fabric Community Sticker Design Challenge Barcelona Carousel

Fabric Community Sticker Challenge - Barcelona 2026

If you love stickers, then you will definitely want to check out our community sticker challenge, Barcelona edition!

July Power BI Update Carousel

Power BI Monthly Update - July 2026

Check out the July 2026 Power BI update to learn about new features.

Power BI DataViz World Championships carousel

Power BI DataViz World Championships - June 2026

A new Power BI DataViz World Championship is coming this June! Don't miss out on submitting your entry.

Top Solution Authors