This is my first project using passport and I am new to Node in general. I am having trouble getting an endpoint recognized as authorized when running integration tests using Chai. The endpoint is protected by token authentication using the passport and jsonwebtoken libraries. Here are the other files imported to the tests;
const chai = require('chai');
const chaiHttp = require('chai-http');
const mongoose = require('mongoose');
const should = chai.should();
const { Session } = require('../models/practiceSession' );
const {User} = require('../models/user');
const { app, runServer, closeServer } = require('../app');
const { TEST_DATABASE_URL } = require('../config/mainConfig');
const {secret} = require('../config/mainConfig');
const jwt = require('jsonwebtoken');
chai.use( chaiHttp );
Here is the test for the endpoint;
//test the session endpoints
it( 'should return a session with proper request', function(){
const user = new User({
name: 'random2',
email: 'random2@random.com',
password: 'Password2'
});
user.save( (err) => {
if (err){
console.log( err.message);
}
});
const token = jwt.sign({
id: user._id,
userName: user.name,
level: 0
}, secret, {
expiresIn: 60 * 60
});
console.log( "user id: ", user._id);
console.log( 'token is: ', token );
const practiceRequest = {
operation: "+",
number: "10", ///this will possible need to be sent as a number
min: "1",
max: "200"
};
return chai.request(app)
.post('/api/session')
.set('Authorization', 'Bearer ' + token)
.send( practiceRequest )
.then( (res) => {
res.should.have.status(201);
})
});
});
The two console.log statements confirm that the user is being created and has an _id property, and that a valid token is being created (this was confirmed on jwt.io).
This is the code for the endpoint;
router.route("/session")
.post(passport.authenticate('jwt', { session: false }), jsonParser, ( req, res ) => {
console.log( req );
let practiceSession = [];
for ( let i = 0; i < req.body.number; i++ ){
let firstTerm = generateTerm( req.body.min, req.body.max );
let secondTerm = generateTerm( req.body.min, req.body.max );
const problem = {
operator: req.body.operation,
firstTerm,
secondTerm,
problem: `${ firstTerm } ${ req.body.operation } ${ secondTerm }`,
correctResponse: generateCorrectResponse( firstTerm, secondTerm, req.body.operation )
};
practiceSession.push( problem );
}
// save session into db sessions collection for use in the training-logic.js
Session
.create( {
userId: req.user._id,
problems: practiceSession
} )
.then(
session => res.status( 201 ).json( session) )
.catch( err => {
console.error( err );
res.status( 500 ).json( { message: 'Internal Server Error' } );
});
} );
The test of this endpoint fails with a 401 response and a simple Error: Unauthorized
That is not a lot of information
and I don't know where to continue trouble shooting. My understanding is that this means the initial passport.authenticate
at the endpoint is not recognizing the token as valid, even though it has been confirmed as valid on the jwt.io site. Is there
additional information I should be including when generating the token? If so how?
I have looked at several other examples using passport; one, two, three but I did not see how to apply any of these insights to my implementation.
Any help with this would be greatly appreciated. Thank you for your time.
UPDATE:
Based on the fact that a valid token is going up to the endpoint but it is still not being accepted I tried building a promise chain with an initial call to the user authentication endpoint and then used the token derived from there to test the session generation endpoint. This was the effort;
it( 'should return a session with proper request', function(){
let token;
return chai.request(app)
.post('/api/user/authenticate')
.send( {
email: 'random@random.com',
password: 'password2'
} )
.then( (res) => {
res.should.have.status(200);
res.should.be.json;
console.log( res.body );
token = res.body.token;
return token;
})
.catch( (err) => {
console.log( 'failed at user authentication' );
})
.then( ( err, data ) => {
console.log( 'token value is ', token );
chai.request( app )
.post( '/api/session' )
.set( 'Authorization', `${ token }` )
.send( {
operation: "+",
number: "10",
min: "1",
max: "200"
})
.then( res => {
console.log( 'second response is ', res );
res.should.have.status(201);
} )
.catch( err => {
console.log( 'second promise ', err.message );
})
})
});
It is still rejected as Unauthorized
. Something is missing from the request being sent to the session endpoint from the test. The console.log( req )
in the session endpoint confirms that it is receiving an object that has a great deal of information added to it, compared to what is being sent from the promise chain in the test. I had to use the token variable in the outer scope to pass the value between the chai.request(app)
commands. This is not the same data flow present in the working app. I am not sure how to test this; my understanding is that what I have tried so far does not give the endpoint enough data to validate the request.
Any help would be greatly appreciated. Thank you for your time.