Validating an Inbound Bearer Token¶
When an inbound API call carries a bearer token in the Authorization HTTP header, the natural-feeling place to validate it is the HTTP Listener's Custom Script authentication option. That does not work: Custom Script authentication only receives userIdIn and passwordIn extracted from the request's parameters or body, never the request headers. The token never reaches the script.
The workable pattern is to run validation in a preprocessor script on the HTTP Listener source. The preprocessor's bytesIn is the full XML-wrapped request including the <Headers> section, and the script can short-circuit the channel by setting responseBytes to an immediate 401, the message never enters the inbound queue. Valid requests pass through to normal channel processing unchanged.
Channel setup¶
On the HTTP Listener source node:
- Authentication: set to No Authentication. (Custom Script cannot see the header; QIE User would force browser login on API callers.)
- Preprocess Received Bytes: enabled, with the script below.
- Response: configure response handling as the channel requires for valid requests. The preprocessor's
responseBytesshort-circuits the channel only on rejection.
Preprocessor script¶
This validates the bearer token against a value stored in a QIE system variable. The same pattern works against a database lookup, a remote validation endpoint, or any other backend. Only the isTokenValid() body changes.
// Disable deprecated warnings
// jshint immed:false,newcap:false,noempty:false,laxbreak:true,laxcomma:true,sub:true
var requestText = new java.lang.String(bytesIn, 'UTF-8');
var requestXml = qie.parseXMLString(requestText);
var authHeader = requestXml.getNode('/Request/Headers/Authorization');
function rejectUnauthorized(message) {
var body = 'HTTP Status: 401\n\n' + message;
responseBytes = body.getBytes('UTF-8');
bytesOut = null;
}
function isTokenValid(token) {
var expected = qie.getVariable('inboundApiBearerToken');
return StringUtils.isNotBlank(expected) && StringUtils.equals(token, expected);
}
if (StringUtils.isBlank(authHeader)) {
rejectUnauthorized('Missing Authorization header.');
} else if (!StringUtils.startsWithIgnoreCase(authHeader, 'Bearer ')) {
rejectUnauthorized('Authorization header must use the Bearer scheme.');
} else {
var token = StringUtils.substring(authHeader, 'Bearer '.length()).trim();
if (!isTokenValid(token)) {
rejectUnauthorized('Invalid bearer token.');
} else {
bytesOut = bytesIn;
}
}
What each branch does:
- Missing or wrong-scheme header: return
401with a short body.bytesOut = nulldiscards the message so nothing enters the channel. - Header present but token invalid: same 401 path.
- Token valid: pass
bytesInthrough unchanged so the channel processes the request normally. The XML wrapper and original headers remain intact for downstream mapping nodes.
Picking a validation backend¶
The shape of isTokenValid() depends on where the source of truth lives:
- System variable (above) is fine for a single static token shared across deployments. Rotate by editing the variable.
- Database lookup: use a parameterized query against a table of issued tokens. Returning a row means the token is active; an empty result means reject.
- Remote auth service: call
qie.callRESTWebService(...)against the issuer's introspection endpoint. Cache successful results insharedCachefor a short window to avoid validating every request against the remote service.
Choosing between preprocessor and acknowledgement script¶
The preprocessor is the right place for token validation because it runs before the message enters the channel. Invalid requests are rejected with no further work, no queue entry, no audit trail of failed messages clogging history.
The acknowledgement script (configured under the HTTP Listener's response options) can also see the headers, via the XML-wrapped response binding, and can also set the status with qie.postMessageResponse(...) prefixed with HTTP Status: 401\n\n…. But by the time the acknowledgement script runs, the channel has already processed the message. That is the right place for response shaping (formatting the success body, adding response headers) not for authentication.
Always pair with HTTPS
A bearer token sent over plain HTTP is exposed to anyone on the network path. Enable the HTTP Listener's HTTPS option and present a valid server certificate so the token is only ever transmitted inside an encrypted session.
See the HTTP Listener source documentation for the full set of source-node options, and the Web Service Functions, System Variable Functions, and Parse String Functions sections of the Code Wizard reference for the bindings used above.