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 diagram shows how to perform custom token validation using the token endpoint.

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);