Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using jsforce with client credentials workflow #1371

Open
poudelroshan opened this issue Oct 11, 2023 · 4 comments
Open

Using jsforce with client credentials workflow #1371

poudelroshan opened this issue Oct 11, 2023 · 4 comments
Labels
docs Documentation

Comments

@poudelroshan
Copy link

I couldn't find documentation for using jsforce with client credentials workflow. Is it supported?

Using postman, I do the following to receive access token:

POST https://custom-endpoint.com/oauth2/token HTTP/1.1
content-type: application/x-www-form-urlencoded
Authorization: Basic <clientID>:<clientSecret>
grant_type=client_credentials

Then I send requests using:

POST https://custom-endpoint.com/services/data/v53.0/sobjects/case/ HTTP/1.1
Authorization: Bearer <accessTokenReceivedInAboveStep>
Content-Type: application/json

{
    "someKey": "SomeValue"
}
@cristiand391
Copy link
Member

Hi @poudelroshan, if you are using jsforce v2, here's an example of how to use the client credentials flow:
#1331
we'll add this to the docs for v3.

If using v1, you could extend the OAuth2 class like this and call super._postParams with the right grant_type, this example does the same for JWT auth (before Shinichi added support for other grant types):

public jwtAuthorize(innerToken: string): Promise<any> {

@cristiand391 cristiand391 added the docs Documentation label May 13, 2024
@mindhaq
Copy link

mindhaq commented May 16, 2024

I'm just starting to use jsforce.

In the docs, there is still no example on how to get an access_token with just clientId and clientSecret and grant_type=client_credentials.

How can this be done? I have no username, no password and no JWT Bearer. Only what @poudelroshan described in the issue description.

I want to get an access_token for machine to machine communication.

@jordanbtucker
Copy link

jordanbtucker commented May 24, 2024

For reference, here is Salesforce's documentation on authenticating with the OAuth Client Credentials Flow.

https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_client_credentials_flow.htm&type=5

Here's an example of using it with jsforce in Deno, which should be easy enough to adapt to Node.js. Note that loginUrl is a string created from the My Domain URL in Salesforce settings. For example, if the My Domain URL is foo.my.salesforce.com, then loginUrl should be "https://foo.my.salesforce.com/".

import jsforce from "npm:jsforce@^3.2.0";
import { clientId, clientSecret, loginUrl } from "./config.ts";

const conn = new jsforce.Connection({
  oauth2: { clientId, clientSecret, loginUrl },
});

const userInfo = await conn.authorize({ grant_type: "client_credentials" });
console.log(userInfo);

const result = await conn.query(`SELECT Id, Name FROM Account LIMIT 1`);
console.log(result.records);

@jordanbtucker
Copy link

jordanbtucker commented May 24, 2024

Note that Salesforce does not support refresh tokens with the client credentials flow, so jsforce will not automatically obtain a new access token if the previous one expires or is revoked. Here's an example of initializing a Connection with a refreshFn.

const conn = new jsforce.Connection({
  serverUrl: loginUrl,
  oauth2: { clientId, clientSecret, loginUrl },
  async refreshFn(conn, callback) {
    try {
      await conn.authorize({ grant_type: "client_credentials" });
      callback(null, conn.accessToken!);
    } catch (err) {
      callback(err);
    }
  },
});

const result = await conn.query(`SELECT Id, Name FROM Account LIMIT 1`);
console.log(result.records);

Note that the serverUrl must also be set before the connection can attempt to make a request the first time. If the request needs to be authorized, then the refreshFn will be called. Alternatively, you can call authorize once before any requests are made to get the accessToken and instanceUrl, in which case the serverUrl is not required.

const conn = new jsforce.Connection({
  oauth2: { clientId, clientSecret, loginUrl },
  async refreshFn(conn, callback) {
    try {
      await conn.authorize({ grant_type: "client_credentials" });
      callback(null, conn.accessToken!);
    } catch (err) {
      callback(err);
    }
  },
});

await conn.authorize({ grant_type: "client_credentials" });

const result = await conn.query(`SELECT Id, Name FROM Account LIMIT 1`);
console.log(result.records);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Documentation
Projects
None yet
Development

No branches or pull requests

4 participants