Adding Authentication to Mern App (In Progress)

Adding Authentication to Mern App (In Progress)

This is another simple guide that I am putting together for my future self.  As I make my latest app from the ground up I want to document my experiences.  This is not meant to be a thorough guide – it’s just a list of steps needed to accomplish the goal.

yarn add jsonwebtoken
yarn add passport passport-jwt passport-local


Perform this in the server folder.  This package contains the platform for various authentication methods that can be used.

passport-jwt will handle the protected route secret if the user is authenticated from a provider.  “local” handles the email/password scenario.

const passport = require("passport");
const LocalStrategy = require("passport-local");
const passportJWT = require("passport-jwt");

Create the corresponding variables in your server file (in my case, “/server.js”).

var apiRouter = require('./server/routes/api');
router.use('/api', apiRouter);

Put the api routes before the the declaration of the client-side public files (more information on the latter here).

const passport = require("passport");
const LocalStrategy = require("passport-local");
const passportJWT = require("passport-jwt");
JWTStrategy = passportJWT.Strategy;
const app = express();

Initializing the JWT strategy and passport instance.

The jwt token is split into three parts – header, payload and signature.  This is essentially an object encoded as a string.  The signature verifies that your token is legitimate.

const user = {
  id: "1",
  email: "",
  password : "password"
Create a dummy user for now to keep this simple.  Later on we will check mongodb for a real user.
passport.use(new JWTStrategy({
  jwtFromRequest: passportJWT.ExtractJwt.fromAuthHeaderAsBearerToken(),   // where are we getting JWT token from
  secretOrKey:"jwt_secret"  // make this more complex
}, (jwt_payload, done) => {  // payload coming back
    if ( === jwt_payload.user._id){
      return done(null, user)
    } else {
      return done(null, false, {
        message: "the user was not found"

In this step we look to see if the user in the incoming request matches a user.  For now we will compare it to the temporary user we created earlier.  Note that the jwt_secret is defined here – in my prod script this is moved to an environment variable (see here).

passport.use(new LocalStrategy({
}, (email, password, done) => {  // callback for authentication
    if (email === && password === user.password) {
      return done(null, user);
    } else {
      return done(mull, false)

Here we are handling the email/password scenario.  This is very similar to the previous code block – instead of extracting the JWT token from the authentication header we are comparing the username and password.

 <ThemeProvider theme={theme}>
          <Header value={value} setValue={setValue} selectedIndex={selectedIndex} setSelectedIndex={setSelectedIndex} />
            <Route exact path="/" component = {Dashboard} />
            <Route exact path="/login" component = {SignIn} />

Use browser router to handle client-side routing.

const server = process.env.REACT_APP_API_SERVER;
export const login = (email, password) => {
  return fetch(`${server}/api/login`, {
    method: "POST",
    body: JSON.stringify({
    headers: {
      "Content-Type": "application/json",
  }).then((res) => {
    if (res.status === 200) {
      return res.json().then((data) => {
        localStorage.setItem('token', data.token); // for testing only
        return data.token
    } else {
      const error = new Error(res.error);
      throw error;
export const getSecret = () => {};

I created this helper utility “api” to handle the call to the backend server.  It will be used in Login component.

 const history = useHistory();
  const onSubmit = async (event) => {
    try {
      const token = await login(,
    } catch (error) {
      alert("Error logging in please try again");

From the Login component.  Note that the onSubmit is attached to form in the html.  If successful login then route to the root of the app."/login", (req, res, next) => {
    passport.authenticate("local", (err, user) => {
        return next(err)
        return res.send("Wrong email or password")
      req.login(user, () => {
        const body = {_id:, email: }
        const token = jwt.sign({user: body}, "jwt_secret")
        return res.json({token})
    })(req, res, next)

We now need to account for the api call back to the express server in the api router file.  Note that I left the jwt_secret string in here for reference only – it comes from an environment variable in the real code.






Add a comment

*Please complete all fields correctly

Related Blogs