ServiceNow Digest Authentication: Secure Your External REST API Integrations
ServiceNow Digest Authentication: Secure Your External REST API Integrations
When you're building integrations between ServiceNow and external systems, Basic Authentication is often too weak for production, and OAuth 2.0 can be overkill — especially when you're dealing with a partner API that doesn't support it. Digest Authentication sits in a useful middle ground: it's standards-based, cryptographically sound, and far easier to implement end-to-end than OAuth.
This guide walks through how ServiceNow handles digest authentication for outbound REST calls, how to implement HMAC-SHA256 signing correctly, and the production patterns that keep integrations secure at scale.
How Digest Authentication Works in ServiceNow
ServiceNow's outbound REST capabilities are handled through the RESTMessageV2 API. When you configure digest authentication, ServiceNow generates an Authorization header that follows RFC 7617 — the HTTP Digest Access Authentication spec.
Unlike Basic Auth (which base64-encodes username:password and sends it in the clear), digest auth sends a response that's computed from:
- The API secret
- The HTTP method and request path
- A server-provided nonce
- A timestamp
- Optionally: the request body hash
The receiving server independently computes the expected digest. If they match, the request is authenticated and untampered.
Setting Up Digest Auth in a ServiceNow REST Message
Here's the basic pattern for configuring digest auth on an outbound REST message:
// 1. Create the REST message record
var rbt = new sn_ws.RESTMessageV2();
rbt.setHttpMethod('POST');
rbt.setEndpoint('https://api.partner-system.com/v1/orders');
rbt.setAuthentication('OAuth2'); // or 'Basic' or 'Digest' — we'll use custom for full control
// 2. For digest auth, we build the auth header ourselves for full control
var authHeader = buildDigestAuthHeader('POST', '/v1/orders', secretKey, timestamp, nonce);
rbt.setHeader('Authorization', 'Digest ' + authHeader);
rbt.setHeader('Content-Type', 'application/json');
// 3. Set the request body
rbt.setRequestBody(requestBodyJSON);
var response = rbt.execute();
Building the HMAC-SHA256 Digest
The core of digest auth is constructing the signed authorization string. Here's a clean implementation pattern:
function buildDigestAuthHeader(method, path, secretKey, timestamp, nonce) {
// Step 1: Create the string-to-sign
// This combines method + path + timestamp + nonce
var stringToSign = method.toUpperCase() + '\n' +
path + '\n' +
timestamp + '\n' +
nonce;
// Step 2: Generate HMAC-SHA256 signature
var secretBytes = new GlideStringUtil().decode(secretKey); // if base64 encoded
var sigBytes = new GlideRSA().hmacSha256(stringToSign, secretBytes);
var signature = GlideStringUtil().base64Encode(sigBytes);
// Step 3: Build the auth params string
var authParams = 'username="api-user", ' +
'timestamp="' + timestamp + '", ' +
'nonce="' + nonce + '", ' +
'signature="' + signature + '"';
return authParams;
}
function generateNonce() {
// Use GlideGuid for cryptographically random nonce
return new GlideGuid().generate();
}
Handling Nonce Expiration and Replay Protection
A nonce that's never validated is useless. Your receiving endpoint needs to track issued nonces and reject duplicates. Here's the server-side validation pattern (assuming you're building the receiving integration too):
// Server-side (Node.js / Express example) — adapt to your endpoint language
app.post('/v1/orders', (req, res) => {
var auth = parseDigestHeader(req.headers['authorization']);
// 1. Check timestamp freshness (within 5 minutes)
var now = Math.floor(Date.now() / 1000);
if (Math.abs(now - auth.timestamp) > 300) {
return res.status(401).json({ error: 'Request expired' });
}
// 2. Check nonce hasn't been replayed (use Redis or a DB Set)
if (nonceCache.has(auth.nonce)) {
return res.status(401).json({ error: 'Nonce replay detected' });
}
// 3. Recompute expected signature
var expectedSig = computeHmacSha256(
auth.username, auth.timestamp, auth.nonce, requestBody
);
if (expectedSig !== auth.signature) {
return res.status(401).json({ error: 'Invalid signature' });
}
nonceCache.add(auth.nonce); // mark as used
// Process the order...
});
The 5-minute window balances security against clock skew between ServiceNow and the external system. Going shorter risks rejecting valid requests; going longer increases replay vulnerability.
Token Management and Secret Rotation
Hardcoded secrets are a maintenance liability. Store your API credentials in ServiceNow's Credential Store (System Security > Credentials) and reference them in your REST message:
var credential = new sn_cc.CredentialStore().getCredentialsByType('generic');
// Returns: { user_name: '...', user_password: '...' }
For enterprise scenarios with multiple environments, use System Properties to configure per-instance secrets, then rotate them via update sets:
gs.getProperty('int.partner_api.secret_key'); // stored in sys_properties
gs.getProperty('int.partner_api.endpoint');
gs.getProperty('int.partner_api.timeout_ms');
Rotate secrets on a schedule — every 90 days is a reasonable baseline for partner API integrations.
Common Pitfalls
Character encoding mismatches are the most frequent cause of digest auth failures. Ensure your request body is encoded as UTF-8 before hashing and that the receiving server expects the same encoding. A single off-by-one character in the request body will produce a different hash and cause silent 401 failures.
Timestamp drift between ServiceNow and the external API is the second most common issue. Both systems should sync to NTP. If your ServiceNow instance runs on UTC and the partner API runs on a different timezone, explicitly normalize timestamps to UTC in your signing logic.
Missing Content-Type header — the digest signature should include the Content-Type when a body is present. Always set Content-Type explicitly before building the auth header.
When to Use Digest Auth vs. Alternatives
Digest auth with HMAC signing works well when:
- Both endpoints are server-side (no human in the loop for auth)
- You need cryptographic integrity guarantees (not just authentication)
- The external API doesn't support OAuth 2.0
- Latency matters — no extra round-trip for token exchange
Stick with OAuth 2.0 when:
- The external API mandates it
- You need token scoped permissions
- User delegation is required
- Token revocation is a requirement
Testing Your Integration
ServiceNow's REST API Explorer (System Web Services > REST API Explorer) is your best friend. Test the raw request first, then move to scripted calls. Enable Message Logging on your REST message to capture the full request and response — you'll see exactly what ServiceNow is sending, which makes debugging signature mismatches tractable.
For automated testing, consider a simple test endpoint that echoes back the computed signature — that way you can validate your client-side signing logic independently of the actual business API.
Digest authentication in ServiceNow isn't as flashy as AI Agents or Virtual Agent chatbots, but it's the kind of foundational integration skill that keeps production systems running securely. When Basic Auth is too risky and full OAuth is overkill, it's exactly the right tool for the job.
