passport-auth-jwt

1.0.22 • Public • Published

passport-auth-jwt

A Passport strategy for authenticating with a JSON Web Token.

This module lets you authenticate endpoints using a JSON web token. It is intended to be used to secure RESTful endpoints without sessions.

Install

npm install passport-auth-jwt

Usage

Sorry this is a personal library for locking my system. And I to open the handler requirements.

The flow

User <-> Device <-> Provider

Note:

  • User This is your user
  • Device This is your application/website
  • Provider This is your system, RESTful endpoint

Configure

 
/**
* Config
*/
var passport = require('passport');
var passportAuthJWT = require('passport-auth-jwt');
config.passport.hook = require('./helper/auth-jwt-hook');
var PassportMoney = new passportAuthJWT(config.passport);
passport.use(PassportMoney.strategy());
 
// config.passport

{
            clientId: 'client_id',
            extractJwtOpts: {
                authScheme: 'AuthJWT',
                tokenBodyField: 'access_token',
                tokenQueryParameterName: 'access_token'
            },
            requestTokenEndpoint: '/auth/request-token',
            refreshTokenEndpoint: '/auth/refresh-token',
            tokenEndpoint: '/auth/token',
            ignoreRequestTokenUrl: ['/'],
            secret: '5f2c6556-2483-4254-a0e6-d8aec4069caa',
            accessTokenExpire: 7 * 86400, // 7 days = 7 * 24 * 3600;
            refreshTokenExpire: 10 * 365 * 86400, // 10 year
            requestTokenExpire: 3600 // 1h
        }

// ./helper/auth-jwt-hook
 
'use strict';
 
const mongoose = require('mongoose');
const uuid = require('node-uuid');
const jwt = require('jsonwebtoken');
const async = require('async');
const moment = require('moment');
const _ = require('lodash');
 
const PassportError = function (done, err) {
    if (err) {
        console.log(err);
    }
 
    return done({error: err}, false);
};
 
const ClientSchema = mongoose.model('ClientKey');
const UserSchema = mongoose.model('User');
const RefreshTokenSchema = mongoose.model('RefreshToken');
 
const Error = require('../config/error');
 
// restify get path;
var getPath = function (req) {
    return req.route ? req.route.path : req.path;
};
 
var urlRequireForRequestToken = ['/auth/token', '/facebook-register', '/google-register', '/register', '/forgot-password'];
 
var AuthJWTHook = {
    verify: function (config) {
        return function (req, jwt_payload, done) {
            console.log('payload', jwt_payload);
 
            // Logic
            if (req.authenticate.client === jwt_payload.client_id) {
                switch (jwt_payload.type) {
                    case 'request-token':
                        AuthJWTHook._verifyRequestToken(req, jwt_payload, done, config);
                        break;
                    case 'refresh-token':
                        AuthJWTHook._verifyRefreshToken(req, jwt_payload, done, config);
                        break;
                    case 'access-token':
                        done(null, jwt_payload);
                        break;
                    default:
                        PassportError(done);
                }
            } else {
                PassportError(done);
            }
        }
    },
 
    // Set userId to req
    passportCallback: function (req, res, next) {
        return function (err, user, info) {
            if (user) {
                req.userId = user.userId;
                next();
            } else {
                next(err || info);
            }
        };
    },
 
    requestTokenCallback: function (req, res, next) {
        return function (error, token) {
            res.send(token);
        }
    },
 
    /*
     more in req
     req.authenticate = {
     client: '14235l4tjgksdsjdlkfs',
     secret: '3o432492rjfksdfjslkdfjsdkl'
     };
 
     */
    generateRequestToken: function (req, res, next, config) {
        var clientInfo = req.authenticate;
 
        ClientSchema.findOne({
            client: clientInfo.client,
            secret: clientInfo.secret,
            isDisabled: false
        }, function (error, client) {
            if (client) {
                var token = AuthJWTHook._generateJWTToken(
                    'request-token', config.secret, `${config.requestTokenExpire}s`, {
                        clientId: client._id,
                        client_id: client.client
                    }
                );
                res.send({status: true, request_token: token});
            } else {
                res.send({
                    status: false,
                    message: Error['OAUTH_ERROR_CLIENT_SECRET_NOT_VALIDATE']
                });
            }
        });
    },
 
    generateAccessToken: function (req, res, next, config) {
        // Logic for generate token
        return function (error, tokenInfo) {
            if (tokenInfo && tokenInfo.type === 'request-token') {
                var client_id = tokenInfo.client_id;
                var clientId = tokenInfo.clientId;
                var postData = req.body;
 
                AuthJWTHook._login(clientId, client_id, postData, config, function (error, data) {
                    if (error) {
                        res.send({
                            status: false,
                            message: error
                        });
                    } else {
                        res.send({
                            status: true,
                            access_token: data.access_token,
                            expire: data.expire,
                            refresh_token: data.refresh_token
                        });
                    }
                });
            } else {
 
                res.send({
                    status: false,
                    message: Error['OAUTH_ERROR_CLIENT_SECRET_NOT_VALIDATE']
                });
            }
        };
    },
 
    generateRefreshToken: function (req, res, next, config) {
        return function (error, tokenInfo) {
            if (tokenInfo && tokenInfo.type === 'refresh-token') {
                AuthJWTHook._generateToken(
                    tokenInfo.clientId,
                    tokenInfo.client_id,
                    tokenInfo.userId,
                    config.secret,
                    tokenInfo.key,
                    config,
                    function (error, results) {
                        if (error) {
                            res.send({
                                status: false,
                                message: Error['']
                            });
                        } else {
                            res.send({
                                status: true,
                                access_token: results.access_token.token,
                                expire: results.access_token.expire,
                                refresh_token: results.refresh_token
                            });
                        }
                    },
                    tokenInfo.deviceKey
                );
            } else {
                res.send({
                    status: false,
                    message: Error['OAUTH_ERROR_CLIENT_SECRET_NOT_VALIDATE']
                });
            }
        };
    },
 
    _generateToken: function (clientId, client_id, userId, secret, key, config, callback, deviceKey) {
        async.parallel({
            refresh_token: function (callback) {
                AuthJWTHook._createRefreshToken(
                    clientId, client_id, userId, secret, config, callback, deviceKey
                );
            },
            access_token: function (callback) {
                AuthJWTHook._createAccessToken(
                    clientId, client_id, userId, secret, config, callback, deviceKey
                );
            },
            clean_refresh_token: function (callback) {
                if (key) {
                    AuthJWTHook._cleanRefreshToken(key, callback);
                } else {
                    callback(null, true);
                }
            }
        }, callback);
    },
 
    _createRefreshToken: function (clientId, client_id, userId, secret, config, callback, deviceKey) {
        var key = uuid.v4();
 
        var token = AuthJWTHook._generateJWTToken('refresh-token', secret, `${config.refreshTokenExpire}s`, {
            clientId: clientId,
            client_id: client_id,
            userId: userId,
            key: key,
            deviceKey: deviceKey
        });
 
        // logic more...
    },
 
    _cleanRefreshToken: function (key, callback) {
        // Logic for clean refresh token
 
    },
 
    _createAccessToken: function (clientId, client_id, userId, secret, config, callback, deviceKey) {
        var attachInfo = {
            clientId: clientId,
            client_id: client_id,
            userId: userId,
            code: deviceKey
        };
 
        var token = AuthJWTHook._generateJWTToken('access-token', secret, `${config.accessTokenExpire}s`, attachInfo);
 
        callback(null, {
            token: token,
            expire: AuthJWTHook._getExpire(config.accessTokenExpire)
        });
    },
 
    _verifyRequestToken: function (req, jwt_payload, done, config) {
        if (urlRequireForRequestToken.indexOf(getPath(req)) > -1) {
            done(null, jwt_payload);
        } else {
            PassportError(done);
        }
    },
 
    _verifyRefreshToken: function (req, jwt_payload, done, config) {
        // Valid refresh token
 
        console.log('OK');
 
        if (config.refreshTokenEndpoint === getPath(req) && jwt_payload.deviceKey) {
            // Logic for verufy refresh token
        } else {
            console.log(error);
            PassportError(done, error);
        }
    },
 
    _generateJWTToken: function (type, secret, expire, extraData) {
        extraData = extraData || {};
 
        var token_payload = {
            type: type,
            code: uuid.v4()
        };
 
        token_payload = Object.assign(token_payload, extraData);
 
        return jwt.sign(token_payload, secret, {
            expiresIn: expire
        });
    },
 
    _getExpire: function (day) {
        return moment().add(day, 's').format('X');
    },
 
    _login: function (clientId, client_id, postData, config, callback) {
        // Login function....
        AuthJWTHook._generateToken(...)
    }
};
 
module.exports = AuthJWTHook;

Authenticate requests

Use PassportMoney.authenticate() specifying 'JWT' as the strategy.

app.post('/profile', PassportMoney.authenticate({ session: false}),
    function(req, res) {
        res.send(req.user.profile);
    }
);

If you have any questions please create issues on Github. I will try to help

Package Sidebar

Install

npm i passport-auth-jwt

Weekly Downloads

3

Version

1.0.22

License

MIT

Last publish

Collaborators

  • cuongle