Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Rest Message From scripted rest API

eyal abu hamad
Mega Sage

I have a rest message with OAuth token of third party vendor
when I try with the test button in the rest message it works fine
but when I try with the scripted rest api I got this
"errorCode":"AUTHORIZATION_INVALID_TOKEN","message":"The access token provided is expired, revoked or malformed."}

this is my script

(function process(request, response) {
  var J = new global.JSON();

  // --- get IDs from your payload (adapt as needed) ---
  var raw = (request.body && request.body.dataString) || "";
  var p = {};
  try { p = raw ? J.decode(raw) : {}; } catch(e){}
  var accountId  = (p.accountId  || p.data && p.data.accountId  || "").trim();
  var envelopeId = (p.envelopeId || p.data && p.data.envelopeId || "").trim();

  if (!accountId || !envelopeId) {
    gs.error("[DS] Missing accountId/envelopeId. accountId=" + accountId + " envelopeId=" + envelopeId);
    response.setStatus(400); return;
  }

  // ---- use your REST Message + Method ----
  var r = new sn_ws.RESTMessageV2('Docusign Auth', 'Get Envelope');

  // 🔒 1) FORCE the OAuth profile BY SYS_ID (no ambiguity across scopes)
  //    How to get it: open your OAuth Entity Profile record → right-click header → Copy sys_id
  var OAUTH_PROFILE_SYS_ID = 'bc873919875cb25040f210273cbb3582';
  r.setAuthenticationProfileId('oauth2', OAUTH_PROFILE_SYS_ID);

  // 2) Vars must match your method's variable names exactly
  r.setStringParameter('accountid',  accountId);
  r.setStringParameter('envelopeid', envelopeId);

  // 3) Helpful logs
  gs.info("[DS] Endpoint -> " + r.getEndpoint());

  var resp = r.execute();
  var code = resp.getStatusCode();
  var body = (resp.getBody() || "") + "";
  var errm = resp.getErrorMessage();

  gs.info("[DS] HTTP " + code + (errm ? (" | err=" + errm) : ""));
  gs.info("[DS] Body preview: " + body.substr(0, 1500));

  // 🔁 Fallback: if 401, manually fetch token from that SAME profile and retry once
  if (code === 401) {
    gs.info("[DS] 401 -> retry with manual Bearer from OAuth profile");
    var oauth = new sn_auth.GlideOAuthClient();
    var tok   = oauth.getTokenByProfileId(OAUTH_PROFILE_SYS_ID);
    var access = tok && tok.getAccessToken();
    if (!access) { gs.error("[DS] Could not fetch access token. Re-authorize profile (Get OAuth Token)."); response.setStatus(500); return; }

    var r2 = new sn_ws.RESTMessageV2('Docusign Auth', 'Get Envelope');
    r2.setStringParameter('accountid',  accountId);
    r2.setStringParameter('envelopeid', envelopeId);
    r2.setRequestHeader('Authorization', 'Bearer ' + access);

    gs.info("[DS] Endpoint (retry) -> " + r2.getEndpoint());
    var resp2 = r2.execute();
    gs.info("[DS] HTTP (retry) " + resp2.getStatusCode() + " | " + (resp2.getErrorMessage() || ""));
    gs.info("[DS] Body preview (retry): " + (resp2.getBody() || "").substr(0,1500));
  }

  response.setStatus(200);
})(request, response);
8 REPLIES 8

I created oAuth profile

eyalabuhamad_0-1759147341316.png

and linked it with the rest message

eyalabuhamad_1-1759147418452.png

 

@eyal abu hamad 

then simply use REST Message and don't give any OAuth profile etc as REST Message already has linked OAuth profile

try this once

(function process(request, response) {
    var J = new global.JSON();

    // --- get IDs from your payload (adapt as needed) ---
    var raw = (request.body && request.body.dataString) || "";
    var p = {};
    try {
        p = raw ? J.decode(raw) : {};
    } catch (e) {}
    var accountId = (p.accountId || p.data && p.data.accountId || "").trim();
    var envelopeId = (p.envelopeId || p.data && p.data.envelopeId || "").trim();

    if (!accountId || !envelopeId) {
        gs.error("[DS] Missing accountId/envelopeId. accountId=" + accountId + " envelopeId=" + envelopeId);
        response.setStatus(400);
        return;
    }

    // ---- use your REST Message + Method ----
    var r = new sn_ws.RESTMessageV2('Docusign Auth', 'Get Envelope');

    // 🔒 1) FORCE the OAuth profile BY SYS_ID (no ambiguity across scopes)
    //    How to get it: open your OAuth Entity Profile record → right-click header → Copy sys_id
    var OAUTH_PROFILE_SYS_ID = 'bc873919875cb25040f210273cbb3582';

    // 2) Vars must match your method's variable names exactly
    r.setStringParameter('accountid', accountId);
    r.setStringParameter('envelopeid', envelopeId);

    // 3) Helpful logs
    gs.info("[DS] Endpoint -> " + r.getEndpoint());

    var resp = r.execute();
    var code = resp.getStatusCode();
    var body = (resp.getBody() || "") + "";
    var errm = resp.getErrorMessage();

    gs.info("[DS] HTTP " + code + (errm ? (" | err=" + errm) : ""));
    gs.info("[DS] Body preview: " + body.substr(0, 1500));

    // 🔁 Fallback: if 401, manually fetch token from that SAME profile and retry once
    if (code === 401) {
        gs.info("[DS] 401 -> retry with manual Bearer from OAuth profile");
        var oauth = new sn_auth.GlideOAuthClient();
        var tok = oauth.getTokenByProfileId(OAUTH_PROFILE_SYS_ID);
        var access = tok && tok.getAccessToken();
        if (!access) {
            gs.error("[DS] Could not fetch access token. Re-authorize profile (Get OAuth Token).");
            response.setStatus(500);
            return;
        }

        var r2 = new sn_ws.RESTMessageV2('Docusign Auth', 'Get Envelope');
        r2.setStringParameter('accountid', accountId);
        r2.setStringParameter('envelopeid', envelopeId);
        r2.setRequestHeader('Authorization', 'Bearer ' + access);

        gs.info("[DS] Endpoint (retry) -> " + r2.getEndpoint());
        var resp2 = r2.execute();
        gs.info("[DS] HTTP (retry) " + resp2.getStatusCode() + " | " + (resp2.getErrorMessage() || ""));
        gs.info("[DS] Body preview (retry): " + (resp2.getBody() || "").substr(0, 1500));
    }

    response.setStatus(200);
})(request, response);

If my response helped please mark it correct and close the thread so that it benefits future readers.

Regards,
Ankur
Certified Technical Architect  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

hey, tried this also but still same issue for the token
401 - Invalid username/password combo
 {"errorCode":"AUTHORIZATION_INVALID_TOKEN","message":"The access token provided is expired, revoked or malformed."}

Ravi Gaurav
Giga Sage
Giga Sage

Hi @eyal abu hamad 

Why "Test" works but Scripted call fails

Test button uses the linked OAuth Entity Profile (from Application Registry). When you test, ServiceNow fetches/refreshes the token properly before making the call.

  1. Scripted REST API → your script may be:

    • Not binding the correct OAuth profile sys_id.

    • Using a cached/expired token from the wrong profile.

    • Overriding the Authorization header incorrectly

Revised Code :-

(function process(request, response) {
var J = new global.JSON();
var raw = (request.body && request.body.dataString) || "";
var p = {};
try { p = raw ? J.decode(raw) : {}; } catch(e){}

var accountId = (p.accountId || "").trim();
var envelopeId = (p.envelopeId || "").trim();

if (!accountId || !envelopeId) {
gs.error("[DS] Missing accountId or envelopeId");
response.setStatus(400);
return;
}

var OAUTH_PROFILE_SYS_ID = 'bc873919875cb25040f210273cbb3582';

// Always fetch the latest token
var oauth = new sn_auth.GlideOAuthClient();
var tok = oauth.getTokenByProfileId(OAUTH_PROFILE_SYS_ID);
if (!tok) {
gs.error("[DS] Could not fetch access token. Re-authorize profile.");
response.setStatus(500);
return;
}
var access = tok.getAccessToken();

// Call REST API with fresh token
var r = new sn_ws.RESTMessageV2('Docusign Auth', 'Get Envelope');
r.setStringParameter('accountid', accountId);
r.setStringParameter('envelopeid', envelopeId);
r.setRequestHeader('Authorization', 'Bearer ' + access);

var resp = r.execute();
var code = resp.getStatusCode();
var body = resp.getBody();
gs.info("[DS] HTTP " + code + " | body: " + body.substr(0,1000));

response.setStatus(code);
response.setBody(body);

})(request, response);

--------------------------------------------------------------------------------------------------------------------------


If you found my response helpful, I would greatly appreciate it if you could mark it as "Accepted Solution" and "Helpful."
Your support not only benefits the community but also encourages me to continue assisting. Thank you so much!

Thanks and Regards
Ravi Gaurav | ServiceNow MVP 2025,2024 | ServiceNow Practice Lead | Solution Architect
CGI
M.Tech in Data Science & AI

 YouTube: https://www.youtube.com/@learnservicenowwithravi
 LinkedIn: https://www.linkedin.com/in/ravi-gaurav-a67542aa/