admin管理员组

文章数量:1404927

I'm following this tutorial to implement jwt authentication in hapijs v17.2.

I did everything according to the tutorial, but the following error is driving me crazy, even debugging didn't make any change.

error

Debug: internal, implementation, error
    TypeError: cb is not a function
    at Object.secretProvider [as key] (C:\Users\user\WebstormProjects\hapi-blog\node_modules\jwks-rsa\lib\integrations\hapi.js:30:14)
    at Object.authenticate (C:\Users\user\WebstormProjects\hapi-blog\node_modules\hapi-auth-jwt2\lib\index.js:123:87)
    at module.exports.internals.Manager.execute (C:\Users\user\WebstormProjects\hapi-blog\node_modules\hapi\lib\toolkit.js:35:106)
    at module.exports.internals.Auth._authenticate (C:\Users\user\WebstormProjects\hapi-blog\node_modules\hapi\lib\auth.js:242:58)
    at authenticate (C:\Users\user\WebstormProjects\hapi-blog\node_modules\hapi\lib\auth.js:217:21)
    at module.exports.internals.Request._lifecycle (C:\Users\user\WebstormProjects\hapi-blog\node_modules\hapi\lib\request.js:261:62)
    at <anonymous>

app.js

const hapi = require('hapi');
const mongoose = require('./db');
const hapi_auth_jwt = require('hapi-auth-jwt2');
const jwksa_rsa = require('jwks-rsa');
const dog_controller = require('./controllers/dog');

const server = new hapi.Server({
    host: 'localhost',
    port: 4200
});

const validate_user = (decoded, request, callback) => {
    console.log('Decoded', decoded);
    if (decoded && decoded.sub) {
        return callback(null, true, {});
    }

    return callback(null, true, {});
};

const register_routes = () => {
    server.route({
        method: 'GET',
        path: '/dogs',
        options: {
            handler: dog_controller.list,
            auth: false
        }
    });

    // Test
    server.route({
        method: 'POST',
        path: '/a',
        options: {
            handler: (req, h) => {
                return h.response({message: req.params.a});
            },
            auth: false
        }
    });

    server.route({
        method: 'GET',
        path: '/dogs/{id}',
        options: {
            handler: dog_controller.get
        }
    });

    server.route({
        method: 'POST',
        path: '/dogs',
        options: {
            handler: dog_controller.create
        }
    });

    server.route({
        method: 'PUT',
        path: '/dogs/{id}',
        handler: dog_controller.update
    });

    server.route({
        method: 'DELETE',
        path: '/dogs/{id}',
        handler: dog_controller.remove
    });
};

const init = async () => {
    await server.register(hapi_auth_jwt);

    server.auth.strategy('jwt', 'jwt', {
        key: jwksa_rsa.hapiJwt2Key({
            cache: true,
            rateLimit: true,
            jwksRequestsPerMinute: 5,
            // YOUR-AUTH0-DOMAIN name e.g 
            jwksUri: '/.well-known/jwks.json'
        }),
        verifyOptions: {
            audience: '/',
            issuer: '',
            algorithm: ['RS256']
        },
        validate: validate_user
    });

    server.auth.default('jwt');

    // Register routes
    register_routes();

    // Start server
    await server.start();

    return server;
};

init().then(server => {
    console.log('Server running at: ', server.info.uri);
}).catch(err => {
    console.log(err);
});

When I make a request to routes with auth: false, the handler works properly then I get the expected result, but requests to routes without auth return the following json :

{
    "statusCode": 500,
    "error": "Internal Server Error",
    "message": "An internal server error occurred"
}

More info:

node version: 8.9.4

npm version: 5.6.0

hapi version: 17.2.0

hapi-auth-jwt2: github:salzhrani/hapi-auth-jwt2#v-17

jwks-rsa: 1.2.1

mongoose: 5.0.6

nodemon: 1.15.0

I'm following this tutorial to implement jwt authentication in hapijs v17.2.

I did everything according to the tutorial, but the following error is driving me crazy, even debugging didn't make any change.

error

Debug: internal, implementation, error
    TypeError: cb is not a function
    at Object.secretProvider [as key] (C:\Users\user\WebstormProjects\hapi-blog\node_modules\jwks-rsa\lib\integrations\hapi.js:30:14)
    at Object.authenticate (C:\Users\user\WebstormProjects\hapi-blog\node_modules\hapi-auth-jwt2\lib\index.js:123:87)
    at module.exports.internals.Manager.execute (C:\Users\user\WebstormProjects\hapi-blog\node_modules\hapi\lib\toolkit.js:35:106)
    at module.exports.internals.Auth._authenticate (C:\Users\user\WebstormProjects\hapi-blog\node_modules\hapi\lib\auth.js:242:58)
    at authenticate (C:\Users\user\WebstormProjects\hapi-blog\node_modules\hapi\lib\auth.js:217:21)
    at module.exports.internals.Request._lifecycle (C:\Users\user\WebstormProjects\hapi-blog\node_modules\hapi\lib\request.js:261:62)
    at <anonymous>

app.js

const hapi = require('hapi');
const mongoose = require('./db');
const hapi_auth_jwt = require('hapi-auth-jwt2');
const jwksa_rsa = require('jwks-rsa');
const dog_controller = require('./controllers/dog');

const server = new hapi.Server({
    host: 'localhost',
    port: 4200
});

const validate_user = (decoded, request, callback) => {
    console.log('Decoded', decoded);
    if (decoded && decoded.sub) {
        return callback(null, true, {});
    }

    return callback(null, true, {});
};

const register_routes = () => {
    server.route({
        method: 'GET',
        path: '/dogs',
        options: {
            handler: dog_controller.list,
            auth: false
        }
    });

    // Test
    server.route({
        method: 'POST',
        path: '/a',
        options: {
            handler: (req, h) => {
                return h.response({message: req.params.a});
            },
            auth: false
        }
    });

    server.route({
        method: 'GET',
        path: '/dogs/{id}',
        options: {
            handler: dog_controller.get
        }
    });

    server.route({
        method: 'POST',
        path: '/dogs',
        options: {
            handler: dog_controller.create
        }
    });

    server.route({
        method: 'PUT',
        path: '/dogs/{id}',
        handler: dog_controller.update
    });

    server.route({
        method: 'DELETE',
        path: '/dogs/{id}',
        handler: dog_controller.remove
    });
};

const init = async () => {
    await server.register(hapi_auth_jwt);

    server.auth.strategy('jwt', 'jwt', {
        key: jwksa_rsa.hapiJwt2Key({
            cache: true,
            rateLimit: true,
            jwksRequestsPerMinute: 5,
            // YOUR-AUTH0-DOMAIN name e.g https://prosper.auth0.
            jwksUri: 'https://mrvar.auth0./.well-known/jwks.json'
        }),
        verifyOptions: {
            audience: 'https://mrvar.auth0./api/v2/',
            issuer: 'https://mrvar.auth0.',
            algorithm: ['RS256']
        },
        validate: validate_user
    });

    server.auth.default('jwt');

    // Register routes
    register_routes();

    // Start server
    await server.start();

    return server;
};

init().then(server => {
    console.log('Server running at: ', server.info.uri);
}).catch(err => {
    console.log(err);
});

When I make a request to routes with auth: false, the handler works properly then I get the expected result, but requests to routes without auth return the following json :

{
    "statusCode": 500,
    "error": "Internal Server Error",
    "message": "An internal server error occurred"
}

More info:

node version: 8.9.4

npm version: 5.6.0

hapi version: 17.2.0

hapi-auth-jwt2: github:salzhrani/hapi-auth-jwt2#v-17

jwks-rsa: 1.2.1

mongoose: 5.0.6

nodemon: 1.15.0

Share Improve this question asked Feb 19, 2018 at 7:55 Hooman LHooman L 1612 silver badges9 bronze badges 1
  • are you still facing the issue, and did you checked mine latest answer? – michalczukm Commented Aug 26, 2018 at 11:12
Add a ment  | 

2 Answers 2

Reset to default 5

Both libraries has support for hapi v.17

I also faced this issue, but surprisingly both libraries has support for hapi v.17, but all documentation is based on old versions or didn't use this bination ;)

How to use it

There are few things that has to be changed then using hapijs v.17

Verify that you're using libraries versions which support hapijs 17:

  • "jwks-rsa": "^1.3.0",
  • "hapi-auth-jwt2": "^8.0.0",

Use hapiJwt2KeyAsync instead of hapiJwt2Key.

Information about this new async method is hidden in node-jwks-rsa package documentation

validate function has now new contract

Please change your existing validate function to below type:

async (decoded: any, request: hapi.Request): {isValid: boolean, credentials: {}} 

Working example (with handled passing scopes)

const validateUser = async (decoded, request) => {
    if (decoded && decoded.sub) {
        return decoded.scope
            ? {
                isValid: true,
                credentials: {
                    scope: decoded.scope.split(' ')
                }
            }
            : { isValid: true };
    }

    return { isValid: false };
};

server.auth.strategy('jwt', 'jwt', {
    plete: true,
    key: jwksRsa.hapiJwt2KeyAsync({
        cache: true,
        rateLimit: true,
        jwksRequestsPerMinute: 5,
        jwksUri: env.auth.jwksUri
    }),
    verifyOptions: {
        audience: '/admin',
        issuer: env.auth.issuer,
        algorithms: ['RS256']
    },
    validate: validateUser
});

The validate function changed in hapi@17 to not have a callback function. Based on your example it should now look something like this:

const validate = async (decoded, request) => {
  if (decoded && decoded.sub) {
     return { isValid: true };
  }
  return { isValid: false };
};

Part of the returned object can also include credentials which would represent the user that is authenticated and you can also do a scope as part of the credentials.

Then if you want to you can access the credentials as part of the request object like request.auth.credentials

本文标签: javascriptcb is not a function in hapiauthjwt2NodejsStack Overflow