GithubHelp home page GithubHelp logo

hapi-auth-jwt's Introduction

hapi-auth-jwt

hapi JSON Web Token (JWT) authentication plugin

Build Status

JSON Web Token authentication requires verifying a signed token. The 'jwt' scheme takes the following options:

  • key - (required) The private key the token was signed with.
  • validateFunc - (optional) validation and user lookup function with the signature function(request, token, callback) where:
    • request - is the hapi request object of the request which is being authenticated.
    • token - the verified and decoded jwt token
    • callback - a callback function with the signature function(err, isValid, credentials) where:
      • err - an internal error.
      • isValid - true if the token was valid otherwise false.
      • credentials - a credentials object passed back to the application in request.auth.credentials. Typically, credentials are only included when isValid is true, but there are cases when the application needs to know who tried to authenticate even when it fails (e.g. with authentication mode 'try').
  • verifyOptions - settings to define how tokens are verified by the jsonwebtoken library
    • algorithms: List of strings with the names of the allowed algorithms. For instance, ["HS256", "HS384"].
    • audience: if you want to check audience (aud), provide a value here
    • issuer: if you want to check issuer (iss), provide a value here
    • ignoreExpiration: if true do not validate the expiration of the token.
    • maxAge: optional sets an expiration based on the iat field. Eg 2h

See the example folder for an executable example.

var Hapi = require('hapi'),
    jwt = require('jsonwebtoken'),
    server = new Hapi.Server();

server.connection({ port: 8080 });


var accounts = {
    123: {
        id: 123,
        user: 'john',
        fullName: 'John Doe',
        scope: ['a', 'b']
    }
};


var privateKey = 'BbZJjyoXAdr8BUZuiKKARWimKfrSmQ6fv8kZ7OFfc';

// Use this token to build your request with the 'Authorization' header.  
// Ex:
//     Authorization: Bearer <token>
var token = jwt.sign({ accountId: 123 }, privateKey, { algorithm: 'HS256'} );


var validate = function (request, decodedToken, callback) {

    var error,
        credentials = accounts[decodedToken.accountId] || {};

    if (!credentials) {
        return callback(error, false, credentials);
    }

    return callback(error, true, credentials)
};


server.register(require('hapi-auth-jwt'), function (error) {

    server.auth.strategy('token', 'jwt', {
        key: privateKey,
        validateFunc: validate,
        verifyOptions: { algorithms: [ 'HS256' ] }  // only allow HS256 algorithm
    });

    server.route({
        method: 'GET',
        path: '/',
        config: {
            auth: 'token'
        }
    });

    // With scope requirements
    server.route({
        method: 'GET',
        path: '/withScope',
        config: {
            auth: {
                strategy: 'token',
                scope: ['a']
            }
        }
    });
});


server.start();

hapi-auth-jwt's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hapi-auth-jwt's Issues

Unit testing query

I am trying to write my own unit tests modeled after the tests in the package...

my test script lives in a structure like this//
app_root
---- node_modules
---- server /
--- test/server/api/users.js ( this is my test script)

when i run npm test...i get the following error..."Cannot read property 'register' of undefined"...

Inside the test script in modules i see this line 'server.register(require('../'), function (err) {'

what should i change it to in my script so that it runs?? sorry this is more of a 'how do in..hapi js' query than a question specific to hapi-auth-jwt..

any pointers appreciated...

Error: Auth is not defined after having updated the hapi package

Hello,
I've upgraded an old Nodejs project to the latest Hapi version... I've read your documentation but I got this error when I start the Nodejs application...

Here's my code

const init = async () => {

    const server = Hapi.server({
        port: port,
        host: 'localhost',
        routes: { cors: { credentials: true } }
    });

   
   

    // include our module here ↓↓, for example, require('hapi-auth-jwt2')
    
    await server.register(require('hapi-auth-jwt2'));

    server.auth.strategy('jwt', 'jwt',
        {
            key: 'SECRETKEYIHAVE', 
            validateFunc: Auth.login_validate,
            verifyOptions: { algorithms: ['HS256'] }// validate function defined above
        });

    server.auth.default('jwt');

    server.route(routes);

    await server.start();
    logger.info('Server running on %s', server.info.uri);

    return server;
};

process.on('unhandledRejection', (err) => {

    logger.error(err.message);
    process.exit(1);
});

init();

and here's my package.json

{
  "name": "aaa-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "boom": "^4.2.0",
    "dotenv": "^8.2.0",
    "@hapi/hapi": "^20.0.1",
    "hapi-auth-jwt2": "^10.0.2",
    "joi": "^10.2.0",
    "minimist": "^1.2.0",
    "mssql": "^3.3.0",
    "request": "^2.81.0",
    "tedious": "^1.14.0",
    "winston": "^3.3.3",
    "winston-daily-rotate-file": "^4.5.0",
    "xmlbuilder": "^8.2.2",
    "uuid": "^8.3.1",
    "seq-logging": "^0.4.6"
  }
}

Any suggestion?
Thanks in advance

getting bad http header format erro

{
"statusCode": 400,
"error": "Bad Request",
"message": "Bad HTTP authentication header format"
}

kindly help me to resolve it i am new to hapi

Dynamically resolve key based on token

In order to easily support multi tenant scenarios, it would be useful to have optionally have a callback function take the JWT and return the key.

To keep the API simple the idea would be to keep the current behavior if key is not a function. If key is a function then this fragment would look like this:

var token = parts[1];

var key = isFunction(settings.key) ? settings.key(token) : settings.key;

jwt.verify(token, key, function(err, decoded) {

What do you think about it?

I'm working on a PR with the updated docs, implementation and tests.

Example not working

Hi, maybe it’s me, but I cannot make the example work. What is the purpose of this line? What should I put instead of the require('../index’) ?

server.register(require('../index'), function (error) {...

Thx!

npm still downloads 2.1

when you install through npm, it installs version 2.1 instead of 4.0. in the new version where validateFunc called, request object also passed, but in 2.1, it only passes token and callback.

Adding option to not validate jwt

The use case here is the hapi server is siting behind a gateway that is validating the jwt tokens, so by the time the request makes it to the hapi server we already know the token is valid. But we do want to access the jwt payload to use the information. Would you be open to a PR to allow this?
What I'm thinking is if key in the options has the value false the authenticate function would call jwt.decode instead of jwt.validate.

Validate Function should have access to request

Would it not be better if the validate function has access to the request object so that other plugins can be accessed and used for validation for. e.g. checking redis for token and fetching cached info?

Hapi 6.x has deprecated pack.require()

I get the error Hapi 6.x has deprecated pack.require() using the sample code on the readme

However when i switch it to the pack.register syntax I get

throw new Error(msgs.join(' ') || 'Unknown error');
^
Error: Missing plugin name

Underlying dependencies not async?

Do you think its cause for concern that the underlying implementation of node-jsonwebtoken is not built in an async manner? I'm not sure if this would impact performance or not, but if there is a high demand for signing and decrypting...

I just wanted to get your thoughts.

With regards,

Patrick

validateFunc has an incorrect function signature

The docs state that validateFunc is a function with the following signature
function (request, decodedToken, callback)
As of now, the signature is actually
function(decodedToken, callback)

Consider making changes in either the documentation to reflect this or making changes in validateFunc code.

var error in validate function

Hi,
sorry to bother you.
What's the purpose of var error in validate function
because afaik is always undefined.

var validate = function (decodedToken, callback) {

    var error,
        credentials = accounts[decodedToken.accountId] || {};

    if (!credentials) {
        return callback(error, false, credentials);
    }

    return callback(error, true, credentials)
};

Thanks in advance.

How to set scope?

Based on the sample code I would be using jsonwebtoken - however I do not see any mention of scope on that module. Your sample code shows scope use. How would I get that to work?

How to put token in blacklist

how can we put the Token in blacklist so it will be not accessible anymore same like require('express-jwt-blacklist')

Unable to get "TokenExpiredError"

Below is the verifyOptions I am using to verify the token sent
verifyOptions: { algorithms: ['HS256'], maxAge: 60 }

When using the below token payload, it does not throw the "TokenExpiredError"
{ iss: 'Online JWT Builder', iat: 1542859570, exp: 1574395630, aud: 'www.example.com',.....}

@ryanfitz Could you help me fix this?

jsonwebtoken - not found

When i require (jsonwebtoken). ..this is thrown Error: Cannot find module 'jsonwebtoken'.
I have hapi-auth-jwt installed....this is an excertp of my package.json

"dependencies": {
"bcrypt": "^0.8.3",
"boom": "^2.7.2",
"hapi": "^8.6.1",
"hapi-auth-basic": "^2.0.0",
"hapi-auth-jwt": "^2.1.2",
"hapi-auth-jwt2": "^4.4.0",
"joi": "^6.4.3",
"json-web-token": "^1.5.3",
"mongoose": "~3.8",
"mrhorse": "^1.1.0"
}

This is the output of npm version....
{ behapi: '1.0.0',
npm: '2.7.4',
http_parser: '2.3',
modules: '14',
node: '0.12.2',
openssl: '1.0.1m',
uv: '1.4.2-node1',
v8: '3.28.73',
zlib: '1.2.8' }

I added jwt=require('jsonwebtoken') at the top of server.js..this is my main js file.

What am i doing wrong. This is what i am trying to accomplish.

  1. set up hapi-auth-jwt in server.js
  2. Upon successful login....get a token by using jwt.sign(user, private key)..where 'user' is a mongoose model.

UPDATE:
It worked. Apparently i had the wrong jsonwebtoken module. I removed json-web-token and added jsonwebtoken and all is well.

Destroy/Delete active/valid token

I was wondering if there was a way to destroy/delete/deactivate/whatever a JWT thats been validated and currently in use.

Im moving my application over from CodeIgniter, which allows you to keep the sessions in a database, which makes it easy to terminate account sessions if needed. I was trying to get the same effect here, by destroying the users JWT token

Access to raw token in validateFunc

What if I need to perform additional checks against raw token during validate? At the moment we have only decodedToken, but if I need to check if that key exists in the Redis ( "blacklist" ) I can't do that because I don't have raw token..

Validating tokens..is this the right way?

My handler function looks like this. At the beginning of the file..i require'd 'jsonwebtoken'. I am wondering if this approach is correct. Any advice appreciated.

//------begin--------------------
exports.secretPage = {
handler : function(request, reply) {
var privateKey = Config.key.privateKey;

    if(hoek.contain(request.headers, 'authorization',{once: true}) === false ) 
        reply(Boom.forbidden("authorization header missing"));

    jwt.verify(request.headers.authorization.split(" ")[1], privateKey, function(err, decoded) {
        if(decoded === undefined) return reply(Boom.forbidden("invalid Token"));
        return reply("Here is your secret page");  //All is well...
    });
}

};
//------------END -------------

Trying to setup Hapi-auth-jwt as a plugin in an external JS file

I was able to get hapi-auth-jwt working just fine using the example JS code in the readme, but I would like to have the hapi-auth-jwt plugin written as an external HapiJS module.

Reading the Creating A Plugin tutorial on the Hapi website shows how to register a plugin, and how to do the same thing as an external module, which I've been able to do with everything else I have used thus far.

It shows you setup the module registration as the exports.register value:

exports.register = function (server, options, next) { /* Plugin stuff */ }

But in your readme example, its quite different

server.register(require('hapi-auth-jwt'), function (error) {

I understand how to work exports in NodeJS, im just not sure how I should structure the register export for this case

I'm sure this is something simple, I'm just new to HapiJS, but if you can provide an example of using this module as an external plugin, that would be very helpful.

Thanks

Does the plugin verify the token?

I am trying the plugin out and want to make sure expiresIn options works.
When I create a token:

var token = jwt.sign({accountId: 123}, privateKey, {expiresIn: '0'});

or

var token = jwt.sign({accountId: 123}, privateKey, {expiresIn: '-1'});

Then just run the code from the example, it doesn't show it as a wrong token, sends all the restricted data.

Am I doing something wrong?

validationFunc doesn't run

i've installed the module but can't seem to get the validation function to run, does it have to be called explicitly? or the validateFunc option will run automatically as long as there is a function supplied?

I am trying to parse the token ias to expire it after a certain time period.

Thanks :)

Custom header

I need two keys. One for api key (the vendor of the service with the scope) and the authorization key (the user's only).

how to generate secret key?

Apologies if this is mentioned elsewhere. The private key used for signing the tokens, is this the same as a private key generated using ssh-keygen?

Destroy JWT token

I don't know is there any way of deactivate a jwt token when user loggedout.
since 2 months I did not get any possible way of doing it.
Can anyone help me ?
My server configuration are below:-

const validate = async function (user,decoded, request) {
    // checks to see if the person is valid
    if (!user["_id"]) {
      return { isValid: false };
    }
    else {
      return { isValid: true };
    }
};
await server.register(require('hapi-auth-jwt2'));

    server.auth.strategy('jwt', 'jwt',
      { key: process.env.SECRET_KEY,
        validate:validate,
        verifyOptions: { algorithms: [ 'HS256' ] }
      });

`
At the time of login I am issuing jwt token from

const token = JWT.sign(user.toJSON(), process.env.SECRET_KEY);

Now I want to destroy that issued token
I am using hapi 17 with hapi-auth-jwt2 package
Please give me solution with code so that I can implement it .

validate method that performs user look up inside a callback

Hi

I'm a newbie so forgive me if this is a naive question.

I'm adding (JWT based) authentication (https://github.com/ryanfitz/hapi-auth-jwt) to my Hapi service. I think I've set it up correctly except one thing. My validate function looks like this:

`
const validate = function (request, decodedToken, callback) {
const originalToken = request.headers.authorization.split(' ')[1]
//return callback(null, true, {'id': decodedToken, 'name': 'vijay'});

globalTokenCache.get(originalToken, function (err, value, cached, log) {
    if (err) {
        return callback(err, false, value);
    }
    if (!value) {
        return callback(err, false, value);
    }
    if (decodedToken !== value['id']) {
        return callback(err, false, value);
    }
    return callback(err, true, value);
});

};

`

Validate function fails and I get a not authenticated error when in reality everything is alright.
I figured that this happens because the validate function returns before the cache.get callback is fired. If I (uncomment and ) return from the second line of the callback itself, authentication succeeds.
I know there isn't a synchronous version of server.cache.get but is there a workaround that I can employ when the user lookup happens inside of a callback?
I feel I'm doing something wrong for me to be stuck here - I don't see others complaining about this.

Add support for "jsonwebtoken" options

The current implementation has a security vulnerability: the attacker can use the 'none' algorithm and fake a token since the list of allowed algorithms is not specified (reference article).
The library used internally (jsonwebtoken) allows specifying the latter as an optional 3rd parameter, check jwt.verify.
So this is just a matter of exposing the functionality in the plugin's configuration.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.