Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invalid JWT token causes a 500 internal server error

Before the server starts, all plugins etc are registered. I create my strategy and set JWT as default authentication method for the server.

await server.register(require('hapi-auth-jwt2'));

await server.register(require('~/utils/jwt-key-signer'));

server.auth.strategy(
    'jwt', 'jwt',
    { key: process.env.API_KEY,     
    validate: true,  // Temporarily using true          
    verifyOptions: { algorithms: [ 'HS256' ] }
});

server.auth.default('jwt');

Here's my route. I pass the payload from the handler request into a plugin that signs my key and returns a token:

'use strict';
const Boom = require('boom');

exports.plugin = {
    name: 'user-create',
    register: (server, options) => {

        server.route({
            method: 'POST',
            path: '/user/create',
            options: { auth: 'jwt' },
            handler: async (request, h) => {

                const { payload } = await request;

                const { JWTKeySigner } = await server.plugins;
                const token = await JWTKeySigner.signKeyReturnToken(payload);

                const cookie_options = {
                    ttl: 365 * 24 * 60 * 60 * 1000, // expires a year from today
                    encoding: 'none',    // we already used JWT to encode
                    isSecure: true,      // warm & fuzzy feelings
                    isHttpOnly: true,    // prevent client alteration
                    clearInvalid: false, // remove invalid cookies
                    strictHeader: true   // don't allow violations of RFC 6265
                }


                return h.response({text: 'You have been authenticated!'}).header("Authorization", token).state("token", token, cookie_options);

            },
            options: {
                description: 'Creates a user with an email and password',
                notes: 'Returns created user',
                tags: ['api']
            }
        });

    }
};

Here's how I sign my key:

const jwt = require('jsonwebtoken');

exports.plugin = {

    name: 'JWTKeySigner',
    register: (server, options) => {

        server.expose('signKeyReturnToken', async (payload) => { 

            jwt.sign(payload, process.env.API_KEY, { algorithm: 'HS256' }, async (err, token) => {

                if (err) {
                    console.log(err)
                } 

                await console.log(`TOKEN${token}`); 

                return token;
            });

        })
    }
};

I then visit my route from Postman, then pass my user which contains an email address and password back to the round as JSON, and this is the response I get:

{
    "statusCode": 401,
    "error": "Unauthorized",
    "message": "Missing authentication"
}

Ok, so that proves my route is successfully being protected. I now proceed to add my token into Postman:

enter image description here

Then I get this error:

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

If I remove the token from postman, I get the "unauthorised" error.

All I'm trying to do is block outside access to my API, and only allow people who have permission to access it. This would be regular users who signup.

When I paste my token into JWT.io, I can see my data on the right hand side of the page, but JWT tells me it's an invalid signature.

I'd really appreciate some clarity here. I'm using hapi-auth-jwt2.

Thanks in advance

like image 832
LondonGuy Avatar asked Nov 27 '25 03:11

LondonGuy


1 Answers

Hmm, I was writing another message to you but then I checked hapi-auth-jwt2 docs for validate options and it says;

validate - (required) the function which is run once the Token has been decoded with signature 
    async function(decoded, request, h) where:
    decoded - (required) is the decoded and verified JWT received in the request
    request - (required) is the original request received from the client
    h - (required) the response toolkit.
    Returns an object { isValid, credentials, response } where:
        isValid - true if the JWT was valid, otherwise false.
        credentials - (optional) alternative credentials to be set instead of decoded.
        response - (optional) If provided will be used immediately as a takeover response.

Just try

server.auth.strategy(
    'jwt', 'jwt',
    { key: process.env.API_KEY,     
    validate: validate: () => ({isValid: true}),  // Temporarily using true          
    verifyOptions: { algorithms: [ 'HS256' ] }
});

Then let's see if 500 error continues.

Maybe some other thing in your code that throws an error. Did you enable debug on your server setup? You should see the details of that 500 error in your server console.

like image 166
metoikos Avatar answered Nov 29 '25 17:11

metoikos