Protecting resources with the token validation endpoint
The token validation endpoint on the IBM MobileFirst™ Platform Server validates tokens that are issued by the authorization server.
The token endpoint implements the OAuth 2.0 token introspection specification and validates access tokens and ID tokens. Using this endpoint, you can write a custom filter in any language to protect resources that are external to the MobileFirst Server. The filter delegates the token validation to the endpoint. An example of a custom filter in Node.js is shown at the end of this topic.
Figure 1. Custom token validation
The endpoint has the same processing logic as the built-in Node.js filter and TAI filter.
Usage
The URL pattern for accessing the endpoint is as follows:
http(s)://<server_ip>:<server_port>/<project_name>/authorization/v1/token/validation
The endpoint responds to a POST request with the following parameters:
- token
- Mandatory. The MobileFirst access token to be checked.
- id_token
- Optional. The MobileFirst ID token to be checked.
- required_scope
- Optional. If specified, the endpoint should ensure that the access token covers that scope.
Response
If the token validates successfully, the validation endpoint responds
with a JSON object that is in application/json format
and that has the following top-level members:
{
"active": true,
"exp" : timestamp,
"scope" : "scope1 scope2 scope3",
"user_id" : userid,
"security_context" : securityContext,
}
- active
- Indicates whether the token is valid or not.
- exp
- Indicates the expiration time of the token.
- scope
- Indicates the scopes of the token.
- user_id
- Indicates the unique identity of the token. If an ID token is provided, the value is a subfield of the ID token. If not, the value is the prn field in the access token.
- security_context
- Contains the decoded information from the access token and ID token. For more information, see The security context object.
In case of validation failure, the response conforms to the OAuth 2.0 specification, meaning that
the status is 40* and WWW-Authenticate is added to
the response header. The header looks like this:
WWW-Authenticate: Bearer realm="<realm name>", error="<error code>"[, error_description="<error description>"][, scope="<scope>"]
Example
The following example demonstrates a Node.js custom filter that uses the
endpoint:
var express = require('express');
var http = require('http');
// For sending the data as x-www-form
var querystring = require('querystring');
var app = express();
// TokenValidationEndpoint custom filter
app.get('/resource/test0', function(req, res) {
var authorizationHeader = req.headers["authorization"];
var path = "/Top/authorization/v1/token/validation";
var host = "9.148.225.200";
var port = 10080;
// Authorization header - Bearer <accessToken> <idToken>
var accessToken;
var idToken;
var tokenType;
if (typeof authorizationHeader != 'undefined') {
var tokenSplit = authorizationHeader.split(" ");
tokenType = tokenSplit[0];
accessToken = tokenSplit[1];
idToken = tokenSplit[2];
}
var form = {
token : accessToken,
id_Token : idToken,
token_type_hint : tokenType
}
var data = querystring.stringify(form);
var options = {
hostname : host,
port : port,
path : path,
method : 'POST',
headers : {
'Content-Type' : 'application/x-www-form-urlencoded',
'Content-Length' : Buffer.byteLength(data)
}
};
var reqToWL = http.request(options, function(resFromWL) {
resFromWL.on('data', function(chunk) {
var parsedData = JSON.parse(chunk);
if (!parsedData.active) {
console.log("Token is invalid");
var status = resFromWL.statusCode;
var wwwAuthenticate = resFromWL.headers["www-authenticate"];
// Set the header and send the response we got from the WL
// server
res.set("WWW-Authenticate", wwwAuthenticate);
res.status(401).send();
} else {
console.log("Token is valid");
// Send the response with the payload
res.send("hello, user");
}
});
});
reqToWL.on('error', function(e) {
console.log('problem with request to WL server: ' + e.message);
});
// write data to request body
reqToWL.write(data);
reqToWL.end();
});
app.listen(3000);
console.log("app is listening at " + 3000);