tokenmanager

3.1.4 • Public • Published

tokenmanager

This module helps with the management of JWT tokens used for API authentication. It allows encoding and decoding of the token itself, and the definition of authorizations rules.

NPMNPM

This package can be used in two modes:

  1. In a distributed architecture, by calling an external service that manages tokens (e.g. using microservices)
  2. In a monolithic application, by managing tokens locally

If used locally, you must manage tokens and authorizations with encode, decode, addRole, upgradeRole and downgradeRole methods.

Installation

Just install it in your Express project by typing:

npm install tokenmanager

Usage

Including tokenmanager

Require it like a normal package:

var tokenManager = require('tokenmanager');

Using tokenmanager

Tokenmanager provides a function configure for setting customizable tokenmanager params and and several middleware functions for token management.

function configure(config)

This function sets "tokenmanager" configuration properties:

var router = require('express').Router();
var tokenManager = require('tokenmanager');
tokenManager.configure( {
 "decodedTokenFieldName":"UserToken",
 "authorizationMicroserviceUrl":"http://localhost:3000",
 "authorizationMicroserviceToken":"4343243v3kjh3k4g3j4hk3g43hjk4g3jh41h34g3",
 "exampleUrl":"http://miosito.it",
 "tokenFieldName":"access_token",
 "secret":"secretKey"
});

configuration parameters

The configuration argument must be a JSON dictionary containing only the keys defined below:

decodedTokenFieldName (String)

The name of the parameter used to store the decoded token. The middleware decodes the client token and, if valid and authorized, adds to the request a field whose name is the value of key decodedTokenFieldName, containing the decoded token.

tokenFieldName (String)

The name of the parameter used to store the request token that the middleware must read and encode. By default the middleware expects this name to be "access_token"

secret (String)

If the middleware is used locally, this is the secret key used to encode/decode token in encode and decode functions

authorizationMicroserviceUrl (String)

URL of the external authorization service used to decode/validate the token and check the authorizations, e.g. http://example.com:3000/checkIfTokenIsAuth

authorizationMicroserviceEncodeTokenUrl (String)

URL of the external authorization service used to decode/validate the token, e.g. http://example.com:3000/decodeToken

authorizationMicroserviceToken (String)

Access token to be used to call an external authorization service.

exampleUrl (String)

String containing the domain of your application. It is used in middleware response messages.

checkAuthorization middleware

This middleware decodes, validates and verifies token authorizations. It reads the field (defined by tokenFieldName) set in header/body/query param, encodes and verifies the token and, if valid and authorized, in Express req param adds a field (defined by decodedTokenFieldName) containing the decoded result, as in:

{   
  "valid":true,  
  "token":{
           // token dictionary
  }
       
}

If an error occurs or the token is not valid or authorised to access that resource, the middleware itself sends a 4xx response containing an object defined in this way:

{  
  "valid":false,
  "error":"Containing error Type name"
  "error_message":"contain error code description"     
}

If this middleware is not used locally but calls an external token manager, this service must have an endpoint in POST method whose URL is set in authorizationMicroserviceUrl config param. This endpoint must accept three body params:

  params: {decode_token: token, URI: URI, method: req.method}

where:

  • decode_token: access token to be verified
  • URI: URI of the protected resource
  • method: HTTP method used to call the protected resource

The response of the external service must be like:

 {valid:"", error:"", error_message: ""}

where:

  • valid: Mandatory. If true, access_token can access the resource. Otherwise, unauthorised or expired
  • token: Optional. If valid==true, contains the decoded token
  • error: Optional. If valid==false, contains the error type description
  • error_message: If valid==false, contains the error message.

######checkAuthorization example:

var router = require('express').Router();
var tokenManager = require('tokenmanager');
tokenManager.configure( {
    "decodedTokenFieldName":"UserToken",
    "authorizationMicroserviceUrl":"localhost:3000",
    "authorizationMicroserviceToken":"4343243v3kjh3k4g3j4hk3g43hjk4g3jh41h34g3jhk4g",
    "exampleUrl":"http://miosito.it"
});
router.get('/resource', tokenManager.checkAuthorization, function(req,res){
    // if you are in here the token is valid and authorized
    console.log("Decoded TOKEN:" + req.UserToken); // print the decode results
});

checkAuthorizationOnReq middleware

This middleware behaves like checkAuthorization. It differs in just one aspect. If an error occurs, it does not respond directly to the client with the error message. Instead, it propagates the error to the Express req param.

######checkAuthorizationOnReq example:

var router = require('express').Router();
var tokenManager = require('tokenmanager');
tokenManager.configure( {
    "decodedTokenFieldName":"UserToken",
    "authorizationMicroserviceUrl":"localhost:3000",
    "authorizationMicroserviceToken":"4343243v3kjh3k4g3j4hk3g43hjk4g3jh41h34g3jhk4g",
    "exampleUrl":"http://miosito.it"
});
router.get('/resource', tokenManager.checkAuthorizationOnReq, function(req,res){
    // if you are in here the token might not be valid or authorized
    if (req.UserToken.valid) {
        //here token is valid
    }
    else {
        //here token is not valid
    }
    console.log("Decoded TOKEN:" + req.UserToken); // print the decode results
});

checkTokenValidity middleware

This middleware behaves like checkAuthorization. It differs only by the fact that it checks only token validity, not authorizations. If this middleware is not used locally but calls an external token manager, this service must have an endpoint in POST method whose URL is set in authorizationMicroserviceEncodeTokenUrl config param. This endpoint must accept one body param:

  params: {decode_token: token}

where:

  • decode_token: access token to be verified

The response of the external service must be like:

 {valid:"", error:"", error_message: ""}

where:

  • valid: Mandatory. If true, access_token is valid
  • token: Optional. If valid==true, contains the decoded token
  • error: Optional. If valid==false, contains the error type description
  • error_message: If valid==false, contains the error message.

######checkTokenValidity example:

var router = require('express').Router();
var tokenManager = require('tokenmanager');
tokenManager.configure( {
    "decodedTokenFieldName":"UserToken",
    "authorizationMicroserviceEncodeTokenUrl":"localhost:3000",
    "authorizationMicroserviceToken":"4343243v3kjh3k4g3j4hk3g43hjk4g3jh41h34g3jhk4g",
    "exampleUrl":"http://miosito.it"
});
router.get('/resource', tokenManager.checkTokenValidity, function(req,res){
    // if you are in here the token is valid. We can't say nothing about authorization
    console.log("Decoded TOKEN:" + req.UserToken); // print the decode results
});

checkTokenValidityOnReq middleware

This middleware behaves like checkTokenValidity. It differs in just one aspect. If an error occurs, it does not respond directly to the client with the error message. Instead, it propagates the error to the Express req param.

######checkTokenValidityOnReq example:

var router = require('express').Router();
var tokenManager = require('tokenmanager');
tokenManager.configure( {
    "decodedTokenFieldName":"UserToken",
    "authorizationMicroserviceEncodeTokenUrl":"localhost:3000",
    "authorizationMicroserviceToken":"4343243v3kjh3k4g3j4hk3g43hjk4g3jh41h34g3jhk4g",
    "exampleUrl":"http://miosito.it"
});
router.get('/resource', tokenManager.checkTokenValidity, function(req,res){
    // if you are in here the token might not be valid
        if (req.UserToken.valid) {
            //here token is valid. We can't say nothing about authorization
        }
        else {
            //here token is not valid
        }
    // if you are in here the token is valid. 
    console.log("Decoded TOKEN:" + req.UserToken); // print the decode results
});

Token and authorization management

If checkAuthorization middleware is used locally, you need to manage tokens (encode/decode) and set API endpoints roles. This can be accomplished with this suite of functions:

encodeToken(dictionaryToEncode,tokenTypeClass,validFor)

This function creates a token, which contains the dictionary defined in dictionaryToEncode param. It accepts 3 parameters:

  • dictionaryToEncode : Dictionary to be encoded inside the token, e.g.:
    {
      "userId":"80248",
      "Other" : "........."
    }
  • tokenTypeClass : Encoded token type, e.g. admin for admin user
  • validFor : Object containing information about token life. It has 2 keys called unit and value. unit is the time unit measure, and value the amount of time. unit can be:
Unit Value Shorthand
years y
quarters Q
months M
weeks w
days d
hours h
minutes m
seconds s
milliseconds ms

######Example :

  // this sets token life to 7 days
  {
    unit:"days",
    value:7
  }

You can use this function to generate your token, like in:

var router = require('express').Router();
var tokenManager = require('tokenmanager');
tokenManager.configure( {
                         "decodedTokenFieldName":"UserToken",
                         "secret":"MyKey",
                         "exampleUrl":"http://miosito.it"
});
// dictionary to encode inside token
var toTokenize={
        "userId":"80248",
        "Other" : "........."
};
// now create a *TokenTypeOne* that expire within 1 hous.
var mytoken=tokenManager.encodeToken(toTokenize,"TokenTypeOne",{unit:"hours",value:1});
console.log(mytoken); // it prints a token as a string like :
                      //32423JKH43534KJ5H435K3L6H56J6K7657H6J6K576N76JK57

decodeToken(token)

This function decodes the token and returns the bundled data. The token parameter must have been generated with encodeToken function

######Example:

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');
 tokenManager.configure( {
          "decodedTokenFieldName":"UserToken",
          "secret":"MyKey",
          "exampleUrl":"http://miosito.it"
 });
 // dictionary to encode inside token
    var toTokenize={
            "userId":"80248",
            "Other" : "........."
    };
 // now create a *TokenTypeOne* that expire within 1 hous.
 var mytoken=tokenManager.encodeTokentoTokenize,"TokenTypeOne",{unit:"hours",value:1});
 console.log(mytoken); // it prints a token as a string like this:
                       //32423JKH43534KJ5H435K3L6H56J6K7657H6J6K576N76JK57
 // if you need information in the token then you can decode it.
 var decodedToken=tokenManager.decodeToken(mytoken);
 console.log(decodedToken); // it prints the unpack token information:
                            // "userId":"80248", "Other" : "........."

Authorization management

Set of functions to set roles and authorizations

addRole(roles)

This function must be used to set a new authorization role. Roles are used by checkAuthorization middleware to verify token authorization for a certain resource.

The roles param is an array of roles. A role is defined as:

// *************************************************************************
// defining a role where only  "admin, tokenTypeOne, TokenTypeTwo"
// tokens type are authorized to access the resource
// "/resource" called with method "GET"
// *************************************************************************
    {
        "URI":"/resource",
        "method":"GET",
        "authToken":[admin, tokenTypeOne, TokenTypeTwo],
    }

where:

  • URI: URI of the resource to protect
  • method: HTTP method used to call the resource to protect
  • authToken : An array of Strings containing the token types authorized by this role

######Example of roles object:

// *************************************************************************
//  defining a roles where:
//   1. only  "admin, tokenTypeOne, TokenTypeTwo" tokens type are authorized
//      to access the resource "/resource" called with method "GET"
//   2. only  "admin" tokens type are authorized to access the resource
//      "/resource" called with method "POST"
// *************************************************************************
var roles= [
        {
            "URI":"/resource",
            "method":"GET",
            "authToken":["admin","tokenTypeOne","TokenTypeTwo"]
        },
        {
            "URI":"/resource",
            "method":"POST",
            "authToken":["admin"]
        }
];

######Example of addRole(roles) usage

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');
 tokenManager.configure( {
      "decodedTokenFieldName":"UserToken",
      "secret":"MyKey",
      "exampleUrl":"http://miosito.it"
 });


 var roles= [
     {
        "URI":"/resource",
        "method":"GET",
        "authToken":["admin", "tokenTypeOne", "TokenTypeTwo"]
     },
     {
        "URI":"/resource",
        "method":"POST",
        "authToken":["admin"]
     }
 ];
 tokenManager.addRole(roles);


 // dictionary to encode inside token
 var toTokenize={
   "userId":"80248",
    "Other" : "........."
 };

 // now create a token of type  *TokenTypeOne* that expire within 1 hous.
 var mytoken=tokenManager.encodeToken(toTokenize,"TokenTypeOne",{unit:"hours",value:1});


//create authenticated endpoints using checkAuthorization middleware
router.get("/resource",tokenManager.checkAuthorization,function(req,res,next){

// *************************************************************************
// this is an authenticated endpoint, accessible only by
// "admin, tokenTypeOne, TokenTypeTwo" tokens as described by the role
// {"URI":"/resource", "method":"GET","authToken":[admin,tokenTypeOne,TokenTypeTwo]}
// *************************************************************************

 });

 router.post("/resource",tokenManager.checkAuthorization,function(req,res,next){

    // *********************************************************************************
    // this is an authenticated API accessible only with "admin" tokens as described
    // by the role
    // {"URI":"/resource","method":"GET","authToken":[admin,tokenTypeOne,TokenTypeTwo]}
    // *********************************************************************************

  });

 router.delete("/resource",tokenManager.checkAuthorization,function(req,res,next){

    // *********************************************************************************
    // This endpoint is unreachable due tokenManager.checkAuthorization respond with
    // Unauthorized 401 due no role set for DELETE "/resource"
    // *********************************************************************************
 });

// Unauthenticated endpoint
 router.put("/resource",function(req,res,next){

    // *********************************************************************************
    // this is an endpoint not authenticated so is reachable with or without token.
    // Through no role is set for PUT "/resource", an Unauthorized 401 response is
    // not sent due checkAuthorization middleware is not used, so it is an
    // unauthenticated endpoint
    // *********************************************************************************

 });

Be careful! The roles contained in roles array override the ones previously defined for that resource. This means that if you want to update a role list, you must call upgradeRole(roles) to add a role, and downgradeRole(roles) to remove a role.

upgradeRole(roles)

This function updates existing authorization roles, adding one or more roles.

The roles param is an array of role objects, defined as:

 // *********************************************************************************
 //  updating a role where only  "tokenTypeOne, TokenTypeTwo" tokens type are
 //  authorized to access the resource  "/resource" called with method "GET"
 // *********************************************************************************
   {
     "URI":"/resource",
     "method":"GET",
     "authToken":[tokenTypeOne, TokenTypeTwo],
   }

where:

  • URI: URI of the resource to protect
  • method: HTTP method used to call the resource to protect
  • authToken : An array of Strings containing the token types authorized by this role

######Example of roles object:

 // *********************************************************************************
 //  defining a roles where:
 //   1. Only  "admin, tokenTypeOne, TokenTypeTwo" tokens type are authorized to
 //      access the resource "/resource" called with method "GET".
 //   2. Only  "admin" tokens type are authorized to access the resource
 //      "/resource" called with method "POST"
 // *********************************************************************************
 var roles= [
     {
        "URI":"/resource",
        "method":"GET",
        "authToken":["admin", "tokenTypeOne", "TokenTypeTwo"]
     },
     {
        "URI":"/resource",
        "method":"POST",
        "authToken":["admin"]
     }
 ];

######Example of upgradeRole(roles) usage

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');
 tokenManager.configure( {
          "decodedTokenFieldName":"UserToken",
          "secret":"MyKey",
          "exampleUrl":"http://miosito.it"
 });


 var roles= [
     {
        "URI":"/resource",
        "method":"GET",
        "authToken":["admin", "tokenTypeOne", "TokenTypeTwo"]
     },
     {
        "URI":"/resource",
        "method":"POST",
        "authToken":["admin"]
     }
 ];
 tokenManager.addRole(roles);

 tokenManager.upgradeRole(
    { "URI":"/resource", "method":"POST",  "authToken":["newAdmin"]}
 );


 // dictionary to encode inside token
    var toTokenize={
            "userId":"80248",
            "Other" : "........."
    };

 // Create a *TokenTypeOne* that expire within 1 hour.
 var mytoken=tokenManager.encodeToken(toTokenize,"TokenTypeOne",{unit:"hours",value:1});

 //create authenticated endpoints using middleware
 router.get("/resource",tokenManager.checkAuthorization,function(req,res,next){

    // *********************************************************************************
    // This is an authenticated endpoint accessible only with
    // "admin, tokenTypeOne, TokenTypeTwo" tokens as described in the role
    // {"URI":"/resource","method":"GET","authToken":["admin","tokenTypeOne","TokenTypeTwo"]}
    // *********************************************************************************
  });

 router.post("/resource",tokenManager.checkAuthorization,function(req,res,next){

    // *********************************************************************************
    // This is an authenticated API accessible with "newAdmin" and "admin" tokens as
    // described by the first and second role
    // { "URI":"/resource", "method":"POST",  "authToken":["admin"]}
    // { "URI":"/resource", "method":"POST",  "authToken":["newAdmin"]}
    // *********************************************************************************

  });

downgradeRole(roles)

This function updates existing authorization roles, removing one or more roles.

The roles param is an array of role objects, defined as:

 // *********************************************************************************
 //  Updating a role where "tokenTypeOne, TokenTypeTwo" tokens type become not
 //  authorized to access the resource "/resource" called with method "GET"
 // *********************************************************************************
   {
     "URI":"/resource",
     "method":"GET",
     "authToken":["tokenTypeOne", "TokenTypeTwo"],
   }

where:

  • URI: URI of the resource to protect
  • method: HTTP method used to call the resource to protect
  • authToken : An array of Strings containing the token types authorized by this role

######Example of roles object:

 // *********************************************************************************
 //  defining a roles where:
 //    1. Remove "tokenTypeOne, TokenTypeTwo" from tokens list authorized to access the
 //       resource "/resource" called with method "GET"
 //    2. Remove  "admin" from tokens type list are authorized to access the
 //       resource "/resource" called with method "POST"
 // *********************************************************************************
 var roles=[
    {"URI":"/resource","method":"GET","authToken":["tokenTypeOne","TokenTypeTwo"]},
    {"URI":"/resource","method":"POST","authToken":["admin"]}
 ];

######Example of downgradeRole(roles) usage

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');
 tokenManager.configure( {
                          "decodedTokenFieldName":"UserToken",
                          "secret":"MyKey",
                          "exampleUrl":"http://miosito.it"
 });


 var roles= [
    {"URI":"/resource","method":"GET","authToken":["admin","tokenTypeOne","TokenTypeTwo"]},
    {"URI":"/resource","method":"POST","authToken":["admin","newAdmin"]}
 ];
 tokenManager.addRole(roles);

 tokenManager.downgradeRole({"URI":"/resource","method":"POST","authToken":["newAdmin"]});

 // dictionary to encode inside token
  var toTokenize={
    "userId":"80248",
    "Other" : "........."
  };

 // Create a *TokenTypeOne*  expiring within 1 hour.
 var mytoken=tokenManager.encodeToken(toTokenize,"TokenTypeOne",{unit:"hours",value:1});

 //create authenticated endpoints using middleware
 router.get("/resource",tokenManager.checkAuthorization,function(req,res,next){
    // *********************************************************************************
    // This is an authenticated endpoint accessible only with
    // "admin, tokenTypeOne, TokenTypeTwo" tokens as described in the role
    // {"URI":"/resource","method":"GET","authToken":["admin","tokenTypeOne","TokenTypeTwo"]}
    // *********************************************************************************
 });

 router.post("/resource",tokenManager.checkAuthorization,function(req,res,next){

     // *********************************************************************************
     // This is an authenticated API accessible only with "admin" tokens due
     // the first role
     // { "URI":"/resource", "method":"POST",  "authToken":["admin","newAdmin"]}
     // is downgraded by second role
     // { "URI":"/resource", "method":"POST",  "authToken":["newAdmin"]}.
     // *********************************************************************************

  });

getRoles()

Gets the list of roles used by checkAuthorization middleware.

######Example of getRoles(roles) usage

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');
 tokenManager.configure( {
              "decodedTokenFieldName":"UserToken",
              "secret":"MyKey",
              "exampleUrl":"http://miosito.it"
 });

 var roles= [
    { "URI":"/resource","method":"GET","authToken":["admin","tokenTypeOne","TokenTypeTwo"]},
    { "URI":"/resource", "method":"POST",  "authToken":["admin"]}
 ];
 tokenManager.addRole(roles);

 var rolesList= tokenManager.getRoles();

 console.log(rolesList) // print this:
                        // { "URI":"/resource","method":"GET", "authToken .......
                        // { "URI":"/resource", "method":"POST",  "authToken":["admin"]}

resetRoles()

Resets authorization roles, erasing all of them

######Example of resetRoles(roles) usage

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');
 tokenManager.configure( {
              "decodedTokenFieldName":"UserToken",
              "secret":"MyKey",
              "exampleUrl":"http://miosito.it"
 });

 var roles= [
    { "URI":"/resource","method":"GET","authToken":["admin","tokenTypeOne","TokenTypeTwo"]},
    { "URI":"/actions/resetRoles","method":"POST","authToken":["admin"]}
 ];

 // set roles
 tokenManager.addRole(roles);

 //reset roles
 tokenManager.resetRoles();

 // dictionary to encode inside token
 var toTokenize={
       "userId":"80248",
        "Other" : "........."
 };

 // now create a *TokenTypeOne* expiring within 1 hour.
 var mytoken=tokenManager.encodeToken(toTokenize,"TokenTypeOne",{unit:"hours",value:1});

 //create authenticated endpoints using middleware
 router.get("/resource",tokenManager.checkAuthorization,function(req,res,next){

    // *********************************************************************************
    // This point is unreachable, because tokenManager.checkAuthorization responds with
    // Unauthorized 401. No role set for GET "/resource" because resetRoles()
    // resets the role dictionary
    // *********************************************************************************

  });

testAuth(token, URI, method, callback)

Tests the authorization roles, checking if a token type can access a resource.

Parameters:

  • token: token under test
  • URI: URI of the resource to protect
  • method: HTTP method used to call the resource to protect
  • callback: callback function "function(err,responseOBJ)" with two parameters:
    • err: HTTP error string, e.g. 400, 401 ... or null if test passes
    • responseOBJ: response object. If test passes (err==null) contains decoded token information; if test fails (err!=null), contains an object with error_message field explaining test fail reason.

######Example of testAuth(token, URI, method, callback) usage

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');
 tokenManager.configure( {
          "decodedTokenFieldName":"UserToken",
          "secret":"MyKey",
          "exampleUrl":"http://miosito.it"
 });

 var roles= [
     { "URI":"/resource","method":"GET","authToken":["admin","tokenTypeOne","TokenTypeTwo"]},
     { "URI":"/actions/resetRoles", "method":"POST",  "authToken":["admin"]}

 ];

 // set roles
 tokenManager.addRole(roles);

 // dictionary to encode inside token
 var toTokenize={
    "userId":"80248",
    "Other" : "........."
};

 // Create a *TokenTypeOne* that expiring in 1 hour.
 var mytoken=tokenManager.encodeToken(toTokenize,"TokenTypeOne",{unit:"hours",value:1});

 //test if mytoken can access resource ""/resource" in get method
 tokenManager.testAuth(mytoken,"/resource","GET",function(err,response){

    if(err) ...... // test failed

    // if you are here test passed, so token is authorized.

    //......YOUR LOGIC ......
 });

Examples

tokenmanager is used locally in a monolithic application

In this example we are going to create:

  • Users.js to manage users and tokens
  • Contents.js to manage contents
  • test.js, a script showing how simple is to manage tokens with tokenmanager package.

######Example of Users.js:

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');

 tokenManager.configure( {
    "decodedTokenFieldName":"UserToken", // decoded token is added in UserToken field
    "secret":"MyKey",                    // secret key to encode/decode token
    "exampleUrl":"http://miosito.it"
 });

 // Set roles where only webUIToken token can call login resource and
 // admin, userTypeOne, userTypeTwo token can call get user by Id
 var roles= [
    { "URI":"/:id","method":"GET","authToken":["admin","userTypeOne","userTypeTwo"]},
    { "URI":"/login", "method":"POST",  "authToken":["webUIToken"]}
 ];

 // Set roles
 tokenManager.addRole(roles);

 router.get("/:id",tokenManager.checkAuthorization,function(req,res,next){

  // *********************************************************************************
  // Authenticated endpoints using checkAuthorization middleware
  // reachable only by admin, userTypeOne, userTypeTwo tokens as in set role
  // { "URI":"/:id","method":"GET","authToken":["admin","userTypeOne","userTypeTwo"]}
  // *********************************************************************************

    // return User and unpack token
    res.status(200).send({User:...., unpackedToken:req.UserToken);

   });

  router.post("/login",tokenManager.checkAuthorization,function(req,res,next){

    // *********************************************************************************
    // Authenticated endpoints using checkAuthorization middleware
    // reachable only by webUIToken tokens as in set role
    // { "URI":"/login", "method":"POST",  "authToken":["webUIToken"]}
    // *********************************************************************************

    // Your Login Logic ....

    var user={ content:"info about logged user"};

    // User is logged, so POST must return a User token.
    // Now creating a userTypeOne token that expires within 1 hour.
    // To do this use tokenManager.encode.
    var token=tokenManager.encodeToken(user,"userTypeOne",{unit:"hours",value:1});

       res.status(200).send({access_token:token}); // return token
    });

######Example of Contents.js

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');
 tokenManager.configure( {
    "decodedTokenFieldName":"UserToken", // add token in UserToken field
    "exampleUrl":"http://miosito.it"
 });

 // Set roles where only admin token can create contents and
 // admin, userTypeOne, userTypeTwo token can get all contents
 var roles= [
    {"URI":"/contents","method":"GET","authToken":["admin","userTypeOne","userTypeTwo"]},
    {"URI":"/contents","method":"POST","authToken":["admin"]}
 ];

 // set roles
 tokenManager.addRole(roles);

 router.get("/contents",tokenManager.checkAuthorization,function(req,res,next){

    // *********************************************************************************
    // Authenticated endpoints using checkAuthorization middleware
    // It is reachable only by admin, userTypeOne, userTypeTwo tokens as set in role
    // {"URI":"/contents","method":"GET","authToken":["admin","userTypeOne","userTypeTwo"]}
    // *********************************************************************************

    // YOUR LOGIC ....

    res.status(200).send("YOUR DATA....");

   });

  router.post("/contents",tokenManager.checkAuthorization,function(req,res,next){

    // *********************************************************************************
    // Authenticated endpoints using checkAuthorization middleware
    // It is reachable only by webUIToken tokens as set in role
    // { "URI":"/contents", "method":"POST",  "authToken":["admin"]}
    // *********************************************************************************

    // YOUR LOGIC ....

    // Save the resource
    var resource=new Resource(req.resource);

    res.status(200).send({createdResource:resource}); // return created resource
  });

The test script shows how to call both User and Contents services, which use tokenmanger to authenticate API. To test the application, you can either this script or an API client like Postman. The application runs on http://localhost:3000/

Steps:

  • create webUIToken. This step is mandatory to call user login
  • call the user login to get a user token as admin (because only admins can create contents)
  • create content as admin
  • read contents
var request=require('request');
var tokenManager = require('tokenmanager');

tokenManager.configure( {
      "secret":"MyKey"  // secret key to encode/decode token
});

// As set in roles, we need admin token to create resource and a webUIToken to login
// admin user and get its token.
// webUIToken is needed so create this token expiring in 10 seconds
var webUIToken=tokenManager.encodeToken(
        {
            subject:"generate token on fly"},"webUIToken",{unit:"seconds",value:10
});

// request params
var rqparams = {
    url: 'http://localhost:3000/login',
    headers: {
            'Authorization': "Bearer " + webUIToken , // set Token
            'content-type': 'application/json'
    },
    body:JSON.stringify({username:"admin@admin.com",password:"admin"}); //login data
};

var adminToken;
// make a login request
request.post(rqparams, function (error, response, body) {
    if error console.log(error);

    adminToken=JSON.parse(body).access_token; // admin token is now set

});

// You have the token so you can create a content
rqparams = {
    url: 'localhost:3000/contents',
    headers: {
        'Authorization': "Bearer " + adminToken , // set admin token
        'content-type': 'application/json'
    },
    body: JSON.stringify({... contents info ...}); // contents to create
};

// make a request to create content
request.post(rqparams, function (error, response, body) {
    if error console.log(error);
    console.log("Contents Created Successfully " + res.createdResource); // created resource
});

// now we can get contents with one of this tokens: 
// admin, userTypeOne, userTypeTwo
// so use admin token. I've already seen a previous login token

rqparams = {
    url: 'localhost:3000/contents',
    headers: {
    'Authorization': "Bearer " + adminToken , // set admin token
    },
};

// Make a request to get all contents
request.get(rqparams, function (error, response, body) {
if error console.log(error);    

    console.log("Contents: " + res.contents);
});

tokenmanger is used in a distributed architecture (e.g. using microservices)

Suppose we have three running microservices:

authms could also be a third party service. This external service must have a POST endpoint, already described in checkAuthorization function.

######Example of authms

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');
 tokenManager.configure( {
      "decodedTokenFieldName":"UserToken", // to add token in UserToken field
      "secret":"MyKey",                    // secret key to encode/decode token
      "exampleUrl":"http://miosito.it"
 });

 // set default roles for this ms. where only "msToken" 
 // token can access authms resources
 var roles= [
     {"URI":"/:id","method":"GET","authToken":[admin,userTypeOne,userTypeTwo]},
     {"URI":"/login","method":"POST","authToken":["webUIToken"]}
 ];

 // set roles
 tokenManager.addRole(roles);

 //create authenticated endpoints using checkAuthorization middleware
 //reachable only by "mstoken" tokens.

  
  router.post("/actions/createToken",tokenManager.checkAuthorization,function(req,res,next){

    // *********************************************************************************
    // It encodes token and wraps tokenManager.encode function  
    // *********************************************************************************
        
    // YOUR LOGIC
        
    var token=tokenManager.encodeToken(req.toTokenize,req.tokenType,req.tokenLife);

    res.status(200).send({access_token:token});

   });

  
  router.post("/actions/addRole",tokenManager.checkAuthorization,function(req,res,next){

    // *********************************************************************************
    // It adds token roles and wraps tokenManager.addRole function 
    // *********************************************************************************
                
    // YOUR LOGIC
        
    var token=tokenManager.addRole(req.roles);

   res.status(200).send({tokenManager.getRoles()}); // return roles list after new creation
  });

  
  router.post("/actions/upgradeRole",tokenManager.checkAuthorization,function(req,res,next){

    // *********************************************************************************
    // It upgrades token roles and wraps tokenManager.upgradeRole function
    // *********************************************************************************

    // YOUR LOGIC

    var token=tokenManager.addRole(req.roles);

    res.status(200).send({tokenManager.getRoles()}); // return roles list after new creation
  }

  // It downgrades token roles and wraps tokenManager.downgradeRole function
  router.post("/actions/downgradeRole",tokenManager.checkAuthorization,function(req,res,next){
  
    // *********************************************************************************
    // It upgrade token roles and wrap tokenManager.upgradeRole function
    // *********************************************************************************

    // YOUR LOGIC
  
     var token=tokenManager.addRole(req.roles);

    res.status(200).send({tokenManager.getRoles()}); // return roles list after new creation
  }

    //####################
    // Other Logic ......
    // .......
    //####################
 
   
   // *********************************************************************************
   // Endpoint that other microservice calls to encode and check token authorization
   // *********************************************************************************
   router.post("/checkAuthorization",tokenManager.checkAuthorization,function(req,res,next){

    var tokenToDecode=req.body.decode_token; // get token to decode
    var method=req.body.method; // get method
    var URI=req.body.URI; // get resource URI

    tokenManager.test(tokenToDecode,URI,method,function(err,retValue){
        if(err) return res.status(err).send(retValue);

        if (_.isUndefined(retValue.valid)) {
                return res.status(401).send(retValue);
        } else {
                if (retValue.valid == true) {
                    return res.status(200).send(retValue);
                } else {
                    return res.status(401).send(retValue);
                }
        }
    });

  });

######Example of userms

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');
 var request=require('request');

 tokenManager.configure( {
      "decodedTokenFieldName":"UserToken", // Add token in UserToken field      
      "exampleUrl":"http://miosito.it",
      "authorizationMicroserviceUrl":"http://authms.com/checkAuthorization"
 });

 // set roles where only webUIToken token can call login resource and
 //  admin, userTypeOne, userTypeTwo token can call get user by id
 var roles= [
     { "URI":"/:id","method":"GET","authToken":["admin","userTypeOne","userTypeTwo"]},
     { "URI":"/login", "method":"POST",  "authToken":["webUIToken"]}
 ];

 // set roles calling msauth
  var rqparams = {
         url: 'http://authms.com/addRole',
         headers: {
                 'Authorization': "Bearer " + MyToken , // set Token
                 'content-type': 'application/json'
         },
         body: JSON.stringify(roles);
  };
  
 // Make request to set roles 
 request.post(rqparams, function (error, response, body) {
     if error console.log(error);

     // Here roles are set

 });

  
 router.get("/:id",tokenManager.checkAuthorization,function(req,res,next){

   // *********************************************************************************
   // Authenticated endpoints using checkAuthorization middleware
   // reachable only by admin, userTypeOne, userTypeTwo tokens
   // *********************************************************************************
    
   // YOUR LOGIC
   
   res.status(200).send({User:...., unpackedToken:req.UserToken); // return User and unpack token
   });

 router.post("/login",tokenManager.checkAuthorization,function(req,res,next){

   // *********************************************************************************
   // creates authenticated endpoints using checkAuthorization middleware
   // reachable only by webUIToken tokens   
   // *********************************************************************************
   
   // YOUR LOGIC TO LOGIN
   
   // User is logged so User token must be returned,
   // Now creates a "userTypeOne" token expiring within 1 hour.
   // using tokenManager.encode.

    // encode token calling msauth
    var rqparams = {
         url: 'http://authms.com/createToken',
         headers: {
                 'Authorization': "Bearer " + MyToken , // set Token
                 'content-type': 'application/json'
         },    
         body: JSON.stringify({"toTokenize":user,"tokenType":"user","tokenLife":{unit:"hours",value:1}});
    };
    
    // make a request to create roken and return it.
    request.post(rqparams, function (error, response, body) {
        res.status(200).send({access_token:JSON.parse(body).token}); // return access_token
     });
  });

######Example of contentms

 var router = require('express').Router();
 var tokenManager = require('tokenmanager');
 
 tokenManager.configure( {
          "decodedTokenFieldName":"UserToken", //  add token in UserToken field
          "authorizationMicroserviceUrl": "localhost:3000", // authms check Authorization url
          "exampleUrl":"http://miosito.it"
 });

 // set roles
 var roles= [
     { "URI":"/contents","method":"GET","authToken":["admin","userTypeOne","userTypeTwo"]},
     { "URI":"/contents","method":"POST","authToken":["admin"]}
 ];

 // set roles calling msauth
 var rqparams = {
     url: 'http://authms.com/addRole',
     headers: {
             'Authorization': "Bearer " + MyToken , // set Token
             'content-type': 'application/json'
     },
     body: JSON.stringify(roles);
  };
 // Make a request to set Roles
 request.post(rqparams, function (error, response, body) {
     if error console.log(error);

    // here role are set
 });

  router.get("/contents",tokenManager.checkAuthorization,function(req,res,next){

        
    // *********************************************************************************
    // Authenticated endpoint using checkAuthorization middleware eachable only by:
    // admin, userTypeOne, userTypeTwo tokens
    // It gets all contents    
    // *********************************************************************************
    
    // YOUR LOGIC ... 
    
    res.status(200).send("YOUR DATA....");
   });

  //creates authenticated endpoints using checkAuthorization middleware
  //reachable only by webUIToken tokens
  router.post("/contents",tokenManager.checkAuthorization,function(req,res,next){
        
    // *********************************************************************************
    // Authenticated endpoint using checkAuthorization middleware reachable only by:
    // webUIToken tokens.
    // It creates a new content    
    // *********************************************************************************
        
    // YOUR LOGIC

    var resource=new Resource(req.resource);

    res.status(200).send({createdResource:resource});
  });

The test script shows how to call both User and Contents services, which use tokenmanger to authenticate API. To test the application, you can either this script or an API client like Postman. The application runs on http://localhost:3000/

Steps:

  • create webUIToken. This step is mandatory to call user login
  • call the user login to get a user token as admin (because only admins can create contents)
  • create content as admin
  • read contents
var request=require('request');
var tokenManager = require('tokenmanager');

tokenManager.configure( {
          "secret":"MyKey"  // secret key to encode/decode token
});

// make admin login to get token.
// to make a login, webUIToken is needed, so create this token expiring in 10 seconds
var webUIToken=tokenManager.encodeToken(
    {subject:"generate token on fly"},"webUIToken",{unit:"seconds",value:10}
);

// Set login request to userms
var rqparams = {
    url: 'http://userms.com/login',
    headers: {
            'Authorization': "Bearer " + webUIToken , // set Token
            'content-type': 'application/json'
    },
    body: JSON.stringify({username:"admin@admin.com" , password:"admin"});
};

var adminToken;
// Make a login request
request.post(rqparams, function (error, response, body) {
    if error console.log(error);

    // set admin token to next calls to contentms
    adminToken=JSON.parse(body).access_token;

});

// now I have the token so I can create a content
// prepare reqest to create content using admin token
rqparams = {
    url: 'localhost:3000/contents',
    headers: {
    'Authorization': "Bearer " + adminToken , // set admin token, webUIToken is not authorized
                'content-type': 'application/json'
    },
    body: JSON.stringify({... contents info ...});
};

// Make a request to create content
request.post(rqparams, function (error, response, body) {
    if error console.log(error);

    console.log("Contents Created Successfully " + res.createdResource);
});

// now I can get all contents with one of this tokens: admin, userTypeOne, userTypeTwo
// so use admin token. I've already seen a previous login token
// Set request
rqparams = {
    url: 'localhost:3000/contents',
    headers: {
        'Authorization': "Bearer " + adminToken , // set admin token
    },
};

// Make a request to get all contents
request.get(rqparams, function (error, response, body) {
    if error console.log(error);

    console.log("Contents: " + res.contents);
});

License - "MIT License"

MIT License

Copyright (c) 2016 aromanino

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Author

CRS4 Microservice Core Team (cmc.smartenv@crs4.it)

Contributors

Alessandro Romanino (a.romanino@gmail.com)
Guido Porruvecchio (guido.porruvecchio@gmail.com)

Versions

Current Tags

  • Version
    Downloads (Last 7 Days)
    • Tag
  • 3.1.4
    1
    • latest

Version History

Package Sidebar

Install

npm i tokenmanager

Weekly Downloads

1

Version

3.1.4

License

MIT

Unpacked Size

72.6 kB

Total Files

10

Last publish

Collaborators

  • aromanino