Assistance with JWT generation with Grouper integration
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-18-2024 06:13 AM
Good Morning All,
We have been asked to attempt to integrate with the following application (Grouper) here:
The authentication method available is "Self Service JWT". Their team has provided us the Private Key string outlined in Step 1. Now, we are attempting to generate the JWT using this on our end.
While the following script looks to output a JWT, we are unclear if this is created and signed properly or what mechanisms ServiceNow has to handle these. We did see the documentation here (https://docs.servicenow.com/bundle/tokyo-platform-security/page/administer/security/concept/Scoped-A...) but as we are not setting them up as an Oauth provider I don't believe this is the path forward. There are also some signing references on the CertificateEncryption() API but again this looks to point to certificate records whereas we are just being provided a Key. We are also not using a MID server or importing external libraries at this time.
Here is the current Script Include and client call used:
var JWTGenerator = Class.create();
JWTGenerator.prototype = {
initialize: function() {},
generateJWT: function() {
try {
// Define the JWT Header
var header = {
alg: "RS256",
typ: "JWT"
};
// Define the JWT Payload
var payload = {
iss: "your-issuer",
sub: "your-subject",
aud: "your-audience",
exp: (new Date().getTime() / 1000) + 600, // Token expiration time (10 minutes from now)
iat: new Date().getTime() / 1000,
// Add additional claims here as needed
};
// Convert the header and payload to Base64
var encodedHeader = GlideStringUtil.base64Encode(JSON.stringify(header));
var encodedPayload = GlideStringUtil.base64Encode(JSON.stringify(payload));
encodedHeader.GlideStringUtil.replace(/=+$/, ''); //strips out == padding
//encodedPayload.GlideStringUtil.replace(/=+$/, '');
encodedPayload.replaceAll("(\=+$\)", "");
gs.info("Payload: " + encodedPayload);
var newb64EncodedText = encodedPayload.replaceAll("(\=+$\)", "");
gs.info("Java Payload: " + newb64EncodedText);
// Create the signature
var key = gs.getProperty('grouper_dev_key');
gs.info("Key is: " + key);
var dataToSign = encodedHeader + "." + newb64EncodedText;
var signature = GlideStringUtil.base64Encode(
GlideDigest.generate('SHA256', dataToSign, key)
);
// Return the complete JWT
var jwtuser = 'jwtUser_OWVmNzE4M2M3MGU4NDNkYmEwNTdiYzk3N2Q2ZTRjZDM=_';
return jwtuser + encodedHeader + "." + newb64EncodedText + "." + signature;
} catch (e) {
gs.error("Error generating JWT: " + e.message);
return null;
}
},
type: 'JWTGenerator'
};
Calling from a Background Script:
var jwtGen = new JWTGenerator();
var jwt = jwtGen.generateJWT();
gs.info("Generated JWT: " + jwt);
Any assistance or ideas would be greatly appreciated.
Thank you.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-23-2025 01:05 PM
For this step 2. Create a JWT Signing key and assign corresponding signing jks:
That Signing Key Password field would store the Grouper private key in this case?
same as the key store pwd, the grouper admin who generated the file for you should provide it too
you use the same for the Signing key
For step 4. Create a 3rd party Oauth provider in Application Registry. Configure JWT Provider and Signing Keys in ServiceNow:
use this documentation if they dont use OAuth2.0, you dont need step 4
use this to generate your token from a fixe script

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-23-2025 01:09 PM - edited 05-23-2025 01:10 PM
Go here to find examples of the JSON requests
$body = @"
{
"WsRestGroupSaveRequest":{
"wsGroupToSaves":[
{
"wsGroup":{
"extension":"test_cloud_group",
"description":"desc1",
"displayExtension":"test_cloud_group",
"name":"test:AutomationTest:test_cloud_group"
},
"wsGroupLookup":{
"groupName":"test:AutomationTest:test_cloud_group"
}
}
]
}
"@
$body = @"
{
"WsRestAddMemberRequest":{
"subjectLookups":[
{
"subjectSourceId":"Uperson",
"subjectId":"user_name"
},
{
"subjectSourceId":"UOFUperson",
"subjectId":"user_name"
},
{
"subjectSourceId":"UOFUperson",
"subjectId":"user_name"
},
{
"subjectSourceId":"FUperson",
"subjectId":"user_name"
}
]
,
"wsGroupLookup":{
"groupName":"test:AutomationTest:test_cloud_group"
}
}
}
"@
$body = @"
{
"WsRestAssignGrouperPrivilegesRequest":{
"allowed":"T",
"privilegeNames":[
"update",
"read"
]
,
"wsSubjectLookups":[
{
"subjectSourceId":"UOFUperson",
"subjectId":"user_name"
},
{
"subjectSourceId":"UOFUperson",
"subjectId":"user_name"
},
{
"subjectSourceId":"UOFUperson",
"subjectId":"user_name"
}
]
,
"wsGroupLookup":{
"groupName":"test:AutomationTest:test_cloud_group"
},
"privilegeType":"access"
}
}
"@
https://www.servicenow.com/docs/bundle/xanadu-api-reference/page/app-store/dev_portal/API_reference/NotifySMS/concept/NotifySMSAPI.html
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
07-07-2025 09:26 AM
Hi Emy,
I just wanted to provide a current update after going through these steps. This method has so far provided a signed valid JWT - we are however still receiving 401 Unauthorized 'The request has not been applied to the target resource because it lacks valid authentication credentials for that resource.' errors when attempting to call a known good endpoint.
I'll list our steps just to be sure we didn't miss anything:
1. Using the documentation provided (https://support.servicenow.com/kb?id=kb_article_view&sysparm_article=KB0717946) we created a self signed certificate. We did not change anything about the provided instructions below beyond inserting the key provided to us from Grouper into the certificate:
"Upload jks which has jwt signing key in sys certificate.Java keystore with a signing key (Private-Public key pair) is generated by customer. Use the below command in the terminal to generate a java keystore with a self signed certificate."
keytool -genkey -alias snclient -keyalg RSA -validity 365 -keystore jwtdemo.keystore -storepass [GROUPERPRIVATE KEY] -keypass [GROUPER PRIVATE KEY]
2. As this presented as a working valid keystore, we set up the JWT Keys as per the instructions:
3. Lastly we pointed the JWT Provider at this key. No particular claims were specified or provided but here is a shot of that configuration screen:
4. The next steps in (https://support.servicenow.com/kb?id=kb_article_view&sysparm_article=KB0717946) do not look to apply since there is no oauth provider. Next we use this script to generate the token. This points at the JWT Provider we just made:
This generates a JWT for us successfully:
And I can verify that this is a valid signed JWT on jwt.io. I can verify that modified claims come over, and the expiration sets correctly so it does look to be generating the correct information. I exported the public key for verification from the certificate created in Step 1 using:
keytool -exportcert -alias snclient -keystore C:/XXXX/XXXX/OneDrive/Desktop/jwtdemo.keystore -rfc -file C:/Users/XXXX/XXXX/Desktop/snclient-cert.pem
Finally, we attempt to use this in our test REST call against the known good endpoint:
Here we receive the 401 errors regarding authorization. I wanted to list all my steps clearly to see if there was anything clearly incorrect on our end or if you had any further insight.
Thanks so much,
Seth