I am completely new to Salesforce and its integration via REST API. I am writing a NodeJS server app to fetch and sync accounts and contacts data. I have configured my connected app with the following settings to get the refresh and access tokens (I need these to fetch account and contacts data via API) through the web server workflow of Salesforce. I have selected these OAuth scopes based on this link
The code I am trying where I should be able to get refresh_token and access_token, I should be able to get a new access_token using the refresh_token and I should be able to get accounts & contacts data with the access_token
Code - 1
const express = require('express');
const got = require('got');
const querystring = require('querystring');
const app = express();
const port = 3555;
app.get('/authorize', (req, res) => {
getAuthorizeCode(req, res);
})
app.get('/callback', (req, res) => {
processCallback(req, res);
})
app.listen(port, () => {
console.log(Example app listening on port ${port})
})
module.exports.getAuthorizeCode = async (req, res) => {
const opts = {
client_id: encodeURI(<ClientId>),
redirect_uri: https://5499-103-170-110-158.ngrok.io/callback,
response_type: code,
scope: encodeURI(refresh_token)
}
const installUrl = <DomainURL>/services/oauth2/authorize?${querystring.stringify( opts )};
res.redirect(installUrl);
}
module.exports.processCallback = async (req, res) => {
const url = <DomainURL>/services/oauth2/token;
const headers = {
accept: 'application/json'
};
const code = req.query.code;
const opts = {
grant_type: authorization_code,
code,
client_id: encodeURI(<ClientId>),
client_secret: <ClientSecret>,
redirect_uri: https://5499-103-170-110-158.ngrok.io/callback
}
const result = await got.post(url, {
headers,
searchParams: opts,
responseType: 'json',
});
const accessToken = await getAccessToken(result.body.refresh_token);
const accountsUrl = <DomainURL>/services/data/v55.0/sobjects/Account;
const accountsHeader = {
Authorization: Bearer ${accessToken},
}
const accountsList = await got(accountsUrl, {
headers: accountsHeader,
responseType: 'json',
})
console.log(accountsList.body);
res.redirect(result.body.instance_url)
}
async function getAccessToken(refToken) {
const url = https://login.salesforce.com/services/oauth2/token;
const headers = {
accept: 'application/json',
Authorization: Basic
};
const opts = {
grant_type: refresh_token,
client_id: encodeURI(<ClientId>),
client_secret: <ClientSecret>,
refresh_token: encodeURI(refToken)
}
const result = await got.post(url, {
headers,
searchParams: opts,
responseType: 'json',
});
return result.body.access_token;
}
Using the code - 1, I could get the refresh_token and access_token, also I could get a new access_token with the refresh_token.
But when I try to get the account data using the below endpoint, I get "This session is not valid for use with the REST API" with status code 401.
<DomainURL>/services/data/v55.0/sobjects/Account
Error detail of the above request
[
{
"message": "This session is not valid for use with the REST API",
"errorCode": "INVALID_SESSION_ID"
}
]
Interestingly, if I try not to get the refresh_token and when tried to fetch accounts data using the access_token that I got with the code below, it works and gives me the accounts data without any issue.
Code - 2
const express = require('express')
const got = require('got');
const querystring = require('querystring');
const app = express()
const port = 3555
app.get('/authorize', (req, res) => {
getAuthorizeCode(req, res);
})
app.get('/callback', (req, res) => {
processCallback(req, res);
})
app.listen(port, () => {
console.log(Example app listening on port ${port})
})
module.exports.getAuthorizeCode = async (req, res) => {
const opts = {
client_id: encodeURI(<ClientId>),
redirect_uri: https://5499-103-170-110-158.ngrok.io/callback,
response_type: code
}
const installUrl = <DomainURL>/services/oauth2/authorize?${querystring.stringify( opts )};
res.redirect(installUrl);
}
module.exports.processCallback = async (req, res) => {
const url = <DomainURL>/services/oauth2/token;
const headers = {
accept: 'application/json'
};
const code = req.query.code;
const opts = {
grant_type: authorization_code,
code,
client_id: encodeURI(<ClientId>),
client_secret: <ClientSecret>,
redirect_uri: https://5499-103-170-110-158.ngrok.io/callback
}
const result = await got.post(url, {
headers,
searchParams: opts,
responseType: 'json',
});
const accessToken = result.body.access_token;
const accountsUrl = <DomainURL>/services/data/v55.0/sobjects/Account;
const accountsHeader = {
Authorization: Bearer ${accessToken},
}
const accountsList = await got(accountsUrl, {
headers: accountsHeader,
responseType: 'json',
})
console.log(accountsList.body);
res.redirect(result.body.instance_url)
}
Code - 2 works fine. But I need refresh_token in order to renew the access_token when it is expired. Also, I need the refresh token that will not be expired until revoked.
I have tried some solutions suggested in the below links. But nothing seems to work for my case
- https://developer.salesforce.com/forums/?id=9062I000000g95nQAA
- https://stackoverflow.com/questions/71024834/salesforce-api-this-session-is-not-valid-for-use-with-the-rest-api-invalid-s
- session is not valid for use with the REST API
- How to resolve INVALID_SESSION_ID error on fetching Tooling API data
Can someone help me to understand what I am doing wrong or what I am missing?

