How to get errors from Passport strategy to create json response? - node.js

I'm creating an JSON API with express and I'm using Passport with the HTTP Bearer strategy for authentication.
I've added passport.authenticate('bearer', {session: false}) as middleware. But whenever something is wrong with the session it simply responds with the body Unauthorized and status 401. The actual information is in the WWW-Authenticate header, in the form of a challenge, something like:
Bearer realm="Users", error="invalid_token", error_description="invalid token"
And when no authentication tokens where given:
Bearer realm="Users"
I'd like to change the response into json which includes the error information.
As I don't have a lot of experience writing things for the backend, I've been reading through the docs and code.
The Bearer strategy simply calls fail with 400 or a challenge string. Basically there is where my issue begins, since I don't want to write a parser for these challenge strings, why isn't this information passed as regular variables?
In Passport's authenticate middleware this challenge is then, depending on your config, passed to callback, req.flash, the session and/or the WWW-Authenticate header. Looking through this code it tries to actually retrieve challenge.type and challenge.message first. When failure handling is not delegated to the application it checks whether the challenges are strings and if so puts them into the WWW-Authenticate header. This might be the reason the bearer strategy returns the challenge as string?
So maybe in my case it makes sense to supply a callback, so that I can directly access these challenges?
But then still, bearer's challenge is a string which requires parsing?
Are people not using this bearer strategy for JSON API's?

The default failure response in passport is here:
https://github.com/jaredhanson/passport/blob/master/lib/middleware/authenticate.js#L174
However, if you provide an authenticate callback it will run this code:
https://github.com/jaredhanson/passport/blob/master/lib/middleware/authenticate.js#L107
So the solution is to provide a callback argument to authenticate(passport, name, options, callback). You can then you can intercept the authentication failures and respond to them as you please.
Note that the res object is not actually passed to your callback. You will have to wrap your call to authenticate like so to respond:
(req, res, next) => {
passport.authenticate('bearer', { /* options */ }, (err, user, challenges, statuses) => {
if (statuses) {
res
.status(401)
.json({
challenges,
statuses,
})
.end();
} else {
next(); // We are authenticated!
}
})(req, res, next);
}

Related

How to make HTML auth form and JSON Web Tokens communicate together in Ionic/Angular

I'm working on an Ionic application.
On the one hand I have an auth basic form in which people fill in their username and password. On the other hand I'd like to implement authentification with JSON Web Tokens and Node JS.
The workflow would be this one : as soon as a user fills in his credentials, they will be sent with a POST request. If these credentials are correct, the user can access to the application and gets an access token as a response.
The thing is that I'm a little bit lost with all that concepts. I built a form and sent informations with a POST request. I managed to create some APIs with Node JS and that's ok. I see how to build a authentified webservice too (e.g : https://github.com/jkasun/stack-abuse-express-jwt/blob/master/auth.js).
But I concretely don't understand the links between the html form and the authorisation check part..
To be clearer, how is it possible to make the html part and the Node JS scripts communicate together ?
Before posting that question I made many researches and found many stuff on building an authentified API. But there was very few advice on how to make it communicate with the client part (I mean the form), which is what I have to do.
If anyone has any ressources (document, Github examples..) on that, I'll greatly appreciate. But I would be very happy too if someone try to make me understand these concepts. I guess I have to improve my knowledge on all that so that I could test some POCs.
Many thanks in advance !
JWT General flow:
1- Authenticate using a strategy (You done it)
2- Deliver an accessToken along with response (You done it)
3- The client MUST store this accessToken (LocalStorage is the best place, not cookies: They are vulnerable to csrf attacks)
4- On every request you are going to make to a protected area (where user is supposed to be authenticated and authorized), make sure to send you accessToken along with it, you can put it on Authorization header, a custom header, directly in body of the request... Basicaly just make sure to send it properly.
5- On the server receiving client requests, you NEED to verify that token (You verify it by checking the signature of the accessToken).
6- If he is authorized, great, if not, send back an HTTP Unauthorized Error.
Here is my implementation using an accessToken on a header + passportjs-jwt:
Client code
To store token:
localStorage.setItem('accessToken', myAccessToken);
To send it:
const myAccessToken = localStorage.getItem('accessToken');
{
headers: {'Authorization', `Bearer ${myAccessToken}`}
}
Server code
1- Configure passport
passport.use('jwt', new JwtStrategy({
jwtFromRequest: jwtPassport.ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: myAccessTokenSecret,
passReqToCallback: true
}, (req, payload, done: (err?, user?) => void): void {
User
.findOne({where: {id: req.params.id}})
.then((user: User) => {
if (!user) {
return done(new Error(`No user found with id: ${req.params.id}`), null);
}
return done(null, user);
})
.catch((e: Error) => done(e, null));
}));
Pay attention to callback: If your callback is called, it means that passport has successfuly verified the token (It is valid). In my example, i get the user details in database and this is the user that will be returned and put in req.user object passed to my controller below:
2- Finally, the controller route (protected area):
.get('/users/:id', passport.authenticate('jwt'), (req, res, next) => {
// do stuff in protected area.
}
And that's it. If you want more security, check refreshTokens implementation.
I used passport because i found it relevant in my case, but you can write your own handler, by using jsonwebtoken and just calling its "verify" function.
You can find documentation of passport jwt strategy here => http://www.passportjs.org/packages/passport-jwt/

Apollo GraphQL Server authentication with passportJS

I am trying to authenticate a user before allowing access to my '/graphql' endpoint.
According to apollo-server documentation regarding setting a context I can do something like this.
app.use(
'/graphql',
bodyParser.json(),
graphqlExpress(req => {
// Some sort of auth function
const userForThisRequest = getUserFromRequest(req);
return {
schema: myGraphQLSchema,
context: {
user: userForThisRequest,
},
// other options here
};
}),
);
I am trying to use passportJS's authenticate() function in the placeholder for "Some sort of auth function", but I can't seem to understand how to utilize the 'req' parameter that I have access to. Should I call passport.authenticate() after the bodyParser middleware or inside the graphqlExpress method?
So my question is how can I use passportJS's authenticate mechanism in this context? Also, is this the best way to implement Authentication on Apollo-server?
There's a couple of different ways you could do this -- depending on the type of response you want to send back to your client when authentication fails and the how much you need to fine-tune the authentication process.
Passport's authenticate function is effectively just express middleware, so you can do something like:
app.use(
'/graphql',
bodyParser.json(),
authenticate(),
graphqlExpress(req => ({
schema: myGraphQLSchema,
context: {
user: getUserFromRequest(req),
},
}));
);
authenticate will send a response with a 401 status if authentication fails (the response itself depends on how you configured the verify callback in your passport strategy). That means if authentication fails, the Apollo server middleware will never be called.
Alternatively, you could avoid using authenticate and handle checking the authentication yourself. This can be done at the resolver level, or for all resolvers by utilizing graphql-tool's addSchemaLevelResolveFunction.
import { addSchemaLevelResolveFunction } from 'graphql-tools'
addSchemaLevelResolveFunction(executableSchema, (root, args, ctx, info) => {
if (!ctx.user) throw new CustomAuthenticationError()
})
The biggest difference is that your response will now return a 200 status, and will include a null data property and an errors array that includes the authentication error.
Of course, the second approach also lets you fine tune your authentication logic -- if you want to only limit a subset of queries or mutations to be only available to authenticated users, for example. Barring that, I don't know if either approach is necessarily better.

Custom authorization header headache in swagger 2.0

I am receiving my security tokens for my API using the Authorization header param sent like so:
Authorization: Bearer <SomeVeryLongTokenThatALegitLoginBegat>
The good news is that my node server receives the param allright; I receive it as args.Authorization.originalValue in each method in each service in the generated server stubs in /controllers. The bad news is that I have a large collection of API endpoints, and I would like to do the authorization of the request before the request gets routed into the controllers.
From what I read, the swagger-security middleware is supposed to do this, but I couldn't get that to work (didn't seem to get into that codeflow at all; see below for what I tried in $SWAGGER_API_HOME/index.js).
// code snippet from $SWAGGER_API_HOME/index.js
app.use(middleware.swaggerSecurity({
Authorization: function (req, def, scopes, callback) {
console.log ('INDEX.JS RECEIVED SOMETHING', req);
callback();
}
}));
So I do this the tiresome way now, for each method in file in /controllers/; an example of this repetitive way follows:
exports.userSomethingDELETE = function(args, res, next) {
/**
* Do something for user
* authorization String
* something SomethingDetails
* no response value expected for this operation
**/
console.log (args.Authorization.originalValue.substring(7));
var promiseOfAuthentication = performMyOwnAuthentication (args.Authorization.originalValue.substring(7));
promiseOfAuthentication.then (...)
...
}
I have a lot of methods (about 500 in all) and so doing the above is very bad way to do auth. I would like the req object to be parsed by one auth method and approve before it gets routed to the correct controller. Is there a way to do this? Any help is appreciated.
Thanks!
I raised this in swagger-codegen originally and provided an answer there. Hope my answer there helps someone.

Express Request Post-Processing

I haven't been able to find anything in express's documentation, but is there such thing as request post processing? I am using a custom token authentication scheme using passport and I would like the ability to automatically update the token in a response header after making a request, mostly a hashed timestamp for authentication purposes. For discussion purposes, let's say I want the following function to execute after each request:
function requestPostProcess(req, res){
if (res.status == 200)
{
res.token = updateToken();
}
}
Ideally, I'd like to be able to do this without having to call next() in each of my routes. Is that even possible?
If you want to add the token to the response,
1) You can create a middleware that adds the token as soon as the request comes, and before it is processed. Put this before request handlers.
Example,
app.use(function(req, res, next){
res.token = updateToken();
next();
})
The glitch here is that, the token will come with all the responses but that can be something you may accept, since it is a timestamp. Plus you can even handle errors using middlewares, and remove the token when the status is not 200.
Advantage: minimal changes required, with proper error handling it works great.
Disadvantage: it tells the time when request was received and not when the response was ready.
2) If you want to put the response after the process is completed, meaning the time when the response was ready, then you may need to create a utility function that sends back all the responses, and you always call that function. That utility function will check the status and appends the token.
function sendResponseGateway(req, res){
if (res.status == 200)
{
res.token = updateToken();
}
res.send()
}
Now whenever you are ready to send response, you can call this function.
Disadvantage: function needs to be called everywhere and you will not be writing "res.send" anywhere.
Advantage :you have a gateway of sending response, you can do additional stuff like encoding, adding more headers etc. in that function and all those response modification stuff happens at one place.

Accessing request object in serializeUser function in passport.js

I am writing simple app using node.js and passport.js for auth.
Can I get access to the request object in serializeUser?
It's actually pretty simple: req is added as the first parameter
passport.deserializeUser(function(req, id, done) {...
https://github.com/jaredhanson/passport/issues/111
If you do req.res.render('whatever' it works.
I think yttrium and laggingreflex questions are slightly different:
To answer yttrium:
To access the request object you have to do it inside an express middleware that will deal with authorization of your resource.
function authMethod(req, res, next) {
if (req.isAuthenticated())
{
console.log(req.user);
return next();
}
res.status(401).send({user:undefined});
}
app.get('/',authMethod,function(req,response)
{
res.status(200).send("OK");
}
If you have done the configuration right, Passaport will make modifications to your request object, so you can access the user information with req.user. You also have a method, req.isAuthenticated(), to check if the third-party auth was succeeded.
To answer laggingreflex:
You can't access the request object inside passport.deserializeUser and passport.serializeUser because those methods are made to deal with the serialization of the user information inside a session (Look at the github explanation). Those methods receive an object and a function as parameters. On serializeUser the first parameter is an object with user information that you will serialize and pass to the donefunction (callback). On deserializeUser the first parameter is an object that was serialized that you have to do the reverse operation.

Resources