Auth0 documentation describes how to set up express-jwt middleware to protect endpoints. The trouble is that the documentation doesn't seem to cover how you get a valid JWT in the first place.
On the angular side, there's documentation on using angular plugins to implement a login page, that's fine. How would one implement a route using express that would take a username/password and return to the client the appropriate JWT such that subsequent requests would be authorized?
I think I may be missing a basic concept about JWT here; via Auth0, when using Username-Password-Authentication, my guess is that Auth0 acts as the repo for those credentials. There's documentation out there about wiring passport to auth0 and JWT, the problem with those is that this documentation assumes that the username/password database is some MongoDB instance locally...I want to avoid that type of setup which was an initial attraction with auth0.
Are there sample projects that cover this, showing how to get a valid JWT on a back-end, without some separate front-end angular app requesting it first?
I use passport.js built in local strategy for authentication and store user information in a JWT that I read on routes that require authorization.
User id's can be serialized/deserialized into and out of the express sessionto obtain the user identifier using the auth token (JWT) in the request. This is in my opinion the best approach since it limits the amount of data stored on the client and provides better security than storing any user information. Here's an example of this in express:
//Set a session secret
var secrets = { sessionSecret: process.env.secret || 'my secret string'};
//Require express-jwt and set a secret for the cookie
var expressJwt = require('express-jwt');
var validateJwt = expressJwt({ secret: secrets.sessionSecret });
//Returns a jwt token signed by the app secret
var signToken = function(id) {
return jwt.sign({
id: id
}, secrets.sessionSecret, {
expiresInMinutes: 60 * 24 // 24 hours
});
};
//Set token cookie directly
var setTokenCookie = function(req, res) {
if (!req.user) {
return res.status(404).json({
message: 'Error during user validation'
});
}
var token = signToken(req.user.id, req.user.role);
res.cookie('token', JSON.stringify(token));
};
//Check to see if user is authenticated (call this when a route is requested)
var isAuthenticated = function(req, res, next) {
// allow access_token to be passed through query parameter as well
if (req.body && req.body.hasOwnProperty('access_token')) {
req.headers.authorization = 'Bearer ' + req.body.access_token;
}
// Validate jwt token
return validateJwt(req, res, next);
};
You can use these methods as middleware in express. Say the above code was token.js, you can force it to execute on each request to a route like this:
app.get('/employee', token.isAuthenticated, employeeController.getEmployees);
I haven't worked with angular but it works great on the backbone projects i've worked on and this process should work with any browser based client that can supply a X-auth cookie on each request. You can do this by using the ajax setup:
$(document).ajaxSend(function(event, request) {
var token = readCookie('token');
if (token) {
request.setRequestHeader('authorization', 'Bearer ' + token);
}
});
Here is an example of middleware that validates a users login and returns a token to the client that can be used on subsequent requests:
var validateLogin = function (req, res, next) {
var username = req.params.username;
// Authenticate using local strategy
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(404).json({
info: [{
msg: info.message
}]
});
}
// Send user and authentication token
var token = token.signToken(user.id, user.role);
res.cookie('token', token);
res.render('index', {token: token, user: user});
})(req, res, next);
};
#FrobberOfBits
This is to answer the follow-up Q posted by FrobberOfBits on Feb 6, 2016 at 3:04
I use auth0 for local + social media authentication.
The way auth0 works is, you hand over the approach to authenticate to auth0 ...either it be local with db or social media.
It is a bundled approach where local db and social media authentication is all bundled and provided as a service to you by auth0.
Hope this helps.
Related
I am using googleapis oauth2.0 for user registration on my website through through OAuth2.0. I get to the point where I get the access token and id token and save the new user in my database, from that point on I want to create a user session and I am trying to use passport for it but passport needs one of its strategies to implement which I do not need at this point because I already have verified user email and everything and have saved the user in my database all I now need to do is create a user session and send the user to the home page but there seems to be no way to just create user session without a strategy in passport.
here is my oauth2.0 redirect function where I get the access token etc.
router.get('/oauth-redirect', function (req, res, next) = > {
const data = await googleAuth.getToken(req.code);
const user = getUserInfoFrom(data);
const savedUser = save(user);
//here: use passport to create a session and send the user to home page ????
})
found the way to do it, there is req.login() function exposed by passport that you can use to manually log the user in.
router.get('/oauth-redirect', function (req, res, next) = > {
const data = await googleAuth.getToken(req.code);
const user = getUserInfoFrom(data);
const savedUser = save(user);
//this below is what will create a session and will set connect.sid cookie
req.login(savedUser, function(err) {
if (err) {
console.log(err);
}
return res.redirect('/home');
});
})
I am creating login module.
User will enter Username and Password.
If user validate successfully then Server will return JWT token.
I will use the JWT token to validate the different API call in React js.
Now my concern is that I found some article regarding this then I found that We can use http only cookie. How can we implement httponly cookie method to store JWT ? Is it safe?
HttpOnly cookies are safe in that they are protected from browser access via the Document.cookie API, and therefore are protected from things like XSS attacks.
When your user is successfully validated, the server should generate a jwt token and return it as a cookie to your client like so:
return res.cookie('token', token, {
expires: new Date(Date.now() + expiration), // time until expiration
secure: false, // set to true if you're using https
httpOnly: true,
});
The cookie will be accessible via incoming http requests from your client. You can check the jwt value of the cookie with an authorizing middleware function to protect your API endpoints:
const verifyToken = async (req, res, next) => {
const token = req.cookies.token || '';
try {
if (!token) {
return res.status(401).json('You need to Login')
}
const decrypt = await jwt.verify(token, process.env.JWT_SECRET);
req.user = {
id: decrypt.id,
firstname: decrypt.firstname,
};
next();
} catch (err) {
return res.status(500).json(err.toString());
}
};
Reference for more details: https://dev.to/mr_cea/remaining-stateless-jwt-cookies-in-node-js-3lle
I'm new to NodeJS and developing an API using it,
I want the API to be authenticated with an API token method (only people with a token stored in DB, created through a specific encryption should be able to access the API resource.)
I'm using an SQL server, NodeJS, and the Express framework.
Please guide me in what I should use to authenticate the API request.
Thanks in advance.
You could use passport.js with JwtStrategy. This is the idea:
mypassport.js
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const opts = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'yourSecret'
};
passport.use(new JwtStrategy(opts, (payload, done) => {
const user = findUserById(payload.id);
if (!user) {
return done('user not exists', null);
}
return done(null, user);
}));
server.js (using express)
require('./mypassport'); // <- initialize passport strategies
//you could also use passport with local strategy for this
app.post('login', (req, res) => {
const username = req.query.username;
const password = req.query.password;
if (validLogin(username, password)) {
const user = findUserByUsername(username);
const jwt = createTokenWithSecret(user, 'yourSecret'); // You can use jwt-simple for this
res.json({ token: jwt });
} else {
//send unauthorized
}
});
const requireLogin = passport.authenticate('jwt');
app.get('/something', requireLogin, (req, res) => {
//here, user is authenticated and available in 'req.user'
});
First, you must login with POST /login { username: 'john', password: '1234' }. That will return a JSON with the jwt token like this:
{ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' }
In subsequent requests, you must send a header Authorization with value: Bearer {token} so passportjs and JwtStrategy can authorize the request.
Hope it helps!
NOTE: I have not tested code above, it just shows the approach.
For API Authenication use Passport JS
You can use json web token (jwt) for API authorization. There are node modules available which provides authentication functionality and you can simply use.
Please have a look at this article: https://medium.freecodecamp.org/securing-node-js-restful-apis-with-json-web-tokens-9f811a92bb52?gi=89f3f4d89dfd
I'm a little new to this. I have REST API made with Node.js and Express.js. Some routes have authentication middleware. To use those routes, a header has to be set with the user's auth token which gets verified. I have been doing this with no problem with static sites using local storage. I'm making my first dynamic site now (using Express) and for certain routes I have middleware that loads all the data I need to display the page. How do I access and use auth tokens now that I don't have local storage's help?
EDIT(for clarification):
So here is one of my api routes that fetches all transactions from a database(mongoDB).
app.get('/transactions', authenticate, (req, res) => {
Transaction.find().then((transaction) => {
res.send({transaction});
}, (e) => {
res.status(400).send();
});
});
This is the authentication middleware that gets run.
var authenticate = (req, res, next) => {
var token = req.header('x-auth');
User.findByToken(token).then((user) => {
if (!user) {
return Promise.reject();
}
req.user = user;
req.token = token;
next();
}).catch((e) => {
res.status(401).send();
});
};
Now on my express webserver, I have a following route, where I use getTransactions to fetch all my data. (which I display with handlebars)
router.get('/orders', getTransactions, (req, res) => {
res.render('orders.hbs', {
transaction: req.transactions.data.transaction
});
});
and this is the middleware
var getTransactions = (req, res, next) => {
axios.get('https://serene-wave-28270.herokuapp.com/transactions')
.then((response) => {
req.transactions = response;
console.log(req.transactions.data.transaction);
next();
}).catch((e) => {
console.log(e);
})
}
So when I was just making a static site without using express as a webserver, I would just have the user sign in and save the auth token in local storage. Also, I should note that the first two blocks are from my api, and the bottom two from webserver, both hosted separately on Heroku. I'm not sure if that's standard design so I thought I should mention it.
There's not a whole lot of detail in your question for exactly what you're trying to do, but I can explain the general concepts available to you in Express:
The usual scheme for Express is to authenticate the user initially and then set a session cookie that indicates that user has been authenticated. Since the cookie is automatically stored by the browser and then automatically sent from the browser to the server with every request, you will have that cookie which the server can then use to identify a server-side session and then you can use any info you want from the session (user identify or other state you store in the session object) when creating pages or responding to API requests for that user.
The NPM module express-session handles much of this work for you as it will automatically create a session object, a session cookie and hook the two together on every request.
If, on the other hand, you already have an auth token in the client and you just want that to be automatically communicated to the server with every request, then you can just put that auth token into a cookie and have the server look for it in the cookie on each request. You can even make it a bit more secure by setting the cookie to HttpOnly so that the auth token cannot be accessed from client-side Javascript (this will not affect the server's ability to access it).
There is not much detail in your question but here are a few thoughts.
You can either use cookies (as detailed by #jfriend00 below) or use the requests' headers to check for a valid authorization token (which I describe below)
In Express you can access the headers through req.headers so you can just write a middleware that you will call before your current middleware loading all the data to ensure that the user is authorized to continue (calling next() to call the next middleware) or using a custom Error type to flag the authentication error if he is not (calling next(err) to skip all the other middleware and jump to your error middleware)
For example (assuming you have a subclass of Error named AuthorizationError defined somewhere):
const express = require('express');
const AuthorizaztionError = require('<some path>');
const app = express();
function checkAuthTokenMiddleware(req, res, next) {
if (req.headers && req.headers.authorization) {
let token;
const parts = req.headers.authorization.split(' ');
if (parts.length == 2) {
const [scheme, credentials] = parts;
if (/^Bearer$/i.test(scheme)) { // or any other scheme you are using
token = credentials;
}
if (token === undefined) {
// access token - missing
return next(new AuthorizationError(
"Invalid access token.", // error_description
"invalid_token" // error
));
}
// add something here to ensure the token is valid
return next();
}
} else {
// No authorization header => invalid credentials
return next(new AuthorizationError(
"Authorization header required.", // error_description
"invalid_request" // error
));
}
}
// Add this in your route declaration
app.use(
"/auth/test",
checkAuthTokenMiddleware,
function(req, res, next) {
// do something
}
);
// this must come last
app.use(function errorMiddleware(err, req, res, next) {
// return something
if (err instanceof AuthenticationError) {
// do something for example
res.status(401).send(err.error_description);
} else {
// generic error handling, for example
res.status(500).send("Error "+err);
}
})
// ...
I have implemented the OAUth 2.0 flow as single authentication method for my express application.
In real situation, once a user connected using OAuth, a session is created and accessible server-side in req.session.passport.
In this session, there is the OAuth access token that is required to perform authenticated requests on my REST API. To be able to do so, I wrote a middleware that copies the token from req.session.passport to the Authorization header.
app.use(function(req, res, next) {
if (req.session.passport) {
req.headers['Authorization'] = req.session.passport.user.accessToken;
}
next();
});
Now, I would like to test this middleware without going through the entire oauth flow. Ideally, I would like to create a session manually and inject test data inside req.session.passport, then call any protected endpoint of my API to check that it can correctly perform authenticated requests.
I tried to manually set data inside req.session in the following test
it('Should be able to make an authenticated request with session data',
function(done) {
var req = request(app).get('/api/SomeProtectedEndpoint');
req.session = {
passport: {
user: {
accessToken : 'eade123d3ffwhatever'
}
}
}
req.expect(200, function(err, res){
if (err) return done(err);
done();
});
});
But if I display the contents of req.session inside my middleware, the manual data is gone. I believe it is removed by express-session.
How can I manually inject session data in a request for testing purposes ?