IMAGE CREDITS
In this project, we simply use the passport google Strategy.
Passport is authentication middleware for Node.js. Extremely flexible and modular, a Passport can be unobtrusively dropped into any Express-based web application. A comprehensive set of strategies support authentication using a username and password, Facebook, Twitter, and more. reference
Before we get start assume that you have a good knowledge of JavaScript and Nodejs.
so without any further delay let's start π
Google credentials
First, we have to get Google's credentials.
To get credentials 'if donβt already have them ' go to Google developer Console
1)create a new project
2)Select the project and click credentials and then select OAuth client ID
3)Now Select Web Application in application type.
4)Input your app name or whatever else you like, in Authorized JavaScript origins add this linehttp://localhost:3000
and in Authorized redirect URIs field add this linehttp://localhost:5000/auth/google/callback
and click to create.
5)Now copy your Google client ID and Google client secret
HelpLets Initialize the New Project
To initialize the new project you just need to create a new folder "App name" and open a folder in visual studio (or any other IDE ) code or any other IDE and run the below code in the command line
npm init
Just fill in the project name and any other detail or just skip. After the package.json
file is generated.
Structure of the project
As with the reference of the above image create folders and files leave node_modules package-lock and package-json as they generate automatically.
Install Dependencies
These are the Dependencies we need to install for our project.
express
ejs
connect-mongo
dotenv
express-session
mongoose
passport
passport-google-oauth20
Install Dependencies by writing the below code in your terminal
npm i ejs connect-mongo dotenv express-session mongoose passport passport-google-oauth20
Setup App for a run
To start the server automatically we just need to install Nodemon which restart the server automatically when any change is detected
npm i -D nodemon
Setup application for developer run and normal run. Just change the Script section with the below code in package.json.
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
},
Start a local server
To start our app for testing/developer just simply type the following command in the command line:
npm run dev
The main work starts from there
You need to just put your google client id and secret in this file. And also the MongoDB URI like(mongodb://localhost:27017/
) if you are hosting MongoDB from your system. if you are using Mongodb Atlas it like(mongodb+srv://XXXX:XXXX@cluster0.obaan.mongodb.net/{DBNAME}?retryWrites=true&w=majority
)
file:config/config.env
PORT = 3000
MONGO_URI=mongodb+srv://XXXX:XXXX@cluster0.obaan.mongodb.net/{DBNAME}?retryWrites=true&w=majority
GOOGLE_CLIENT_ID = XXXXXXXXXX
GOOGLE_CLIENT_SECRET = XXXXXXXXXXXXXXXX
In my case we use Mongodb Atlas . you can refer this for getting mongodb atlas URI . and refer this for Google client id and secret if any problem occur .
Application
Its time code our app.js
file this is the main file and it will sit in the root of our website.
In this file we have to setup our server.
file:app.js
Import all the necessary modules.
const express = require('express');
const mongoose=require('mongoose');
const dotenv = require('dotenv')
const passport = require('passport')
const session = require('express-session')
const MongoStore = require('connect-mongo')(session)
require('./config/passport')(passport)
Connect to mongodb and set express template.
var app=express();
const PORT = process.env.PORT||3000;
dotenv.config({ path: './config/config.env' })
mongoose.connect(process.env.MONGO_URI,{
useNewUrlParser:true,
useUnifiedTopology: true
})
app.use(express.static('public'))
app.set('view engine','ejs');
Initialize middleware and setup database for storing sessions.
app.use(express.urlencoded({extended:true}))
app.use(
session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection }),
})
)
// Passport middleware
app.use(passport.initialize())
app.use(passport.session())
last part import routes
app.use(require("./routes/index"))
app.use('/auth', require('./routes/auth'))
app.listen(PORT,console.log(`listening at ${PORT}`))
Now our app.js
file is readyππ
Routes
Now its time to code our routes
we are to code 2 routes files one auth.js
for authentication and another one index.js
for redirecting between pages
Let's code out the auth.js
file.
file:auth.js
//Importing required modules
const express = require('express')
const passport = require('passport')
const router = express.Router()
send to google to do the authentication.
In scopes, profile gets us their basic information including their name and email gets their emails.
router.get('/google', passport.authenticate('google', { scope: ['profile','email'] }))
Callback after google has authenticated the user.
router.get(
'/google/callback',
passport.authenticate('google', { failureRedirect: '/' }),
(req, res) => {
res.redirect('/log')
}
)
For logout
router.get('/logout', (req, res) => {
req.logout()
res.redirect('/')
})
module.exports = router
Now our auth.js
file is readyππ
Before creating the index.js
file we have to create our middleware to ensure that the user is authenticated or not.
file:middleware/auth.js
module.exports = {
// if user is authenticated the redirected to next page else redirect to login page
ensureAuth: function (req, res, next) {
if (req.isAuthenticated()) {
return next()
} else {
res.redirect('/')
}
},
// if user is authenticated and going to login page then redirected to home page if not authenticated redirected to login page .
ensureGuest: function (req, res, next) {
if (!req.isAuthenticated()) {
return next();
} else {
res.redirect('/log');
}
},
}
Now our middleware is ready let's code our next router index.js
.
file:routes/index.js
const router = require('express').Router()
//importing middleware
const { ensureAuth, ensureGuest } = require('../middleware/auth')
router.get('/', ensureGuest ,(req, res) => {
res.render('login')
})
router.get("/log",ensureAuth, async(req,res)=>{
res.render('index',{userinfo:req.user})
})
module.exports=router;
Configure Passport's Google startegy
file:config/passport.js
// import all the things we need
const GoogleStrategy = require('passport-google-oauth20').Strategy
const mongoose = require('mongoose')
const User = require('../models/User')
module.exports = function (passport) {
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/callback',
},
async (accessToken, refreshToken, profile, done) => {
//get the user data from google
const newUser = {
googleId: profile.id,
displayName: profile.displayName,
firstName: profile.name.givenName,
lastName: profile.name.familyName,
image: profile.photos[0].value,
email: profile.emails[0].value
}
try {
//find the user in our database
let user = await User.findOne({ googleId: profile.id })
if (user) {
//If user present in our database.
done(null, user)
} else {
// if user is not preset in our database save user data to database.
user = await User.create(newUser)
done(null, user)
}
} catch (err) {
console.error(err)
}
}
)
)
// used to serialize the user for the session
passport.serializeUser((user, done) => {
done(null, user.id)
})
// used to deserialize the user
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => done(err, user))
})
}
User model
Now it's time to create our database model to user data in the database.
file:models/User.js
const mongoose = require('mongoose')
const UserSchema = new mongoose.Schema({
googleId: {
type: String,
required: true,
},
displayName: {
type: String,
required: true,
},
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
image: {
type: String,
},
email:{
type:String,
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
})
module.exports = mongoose.model('User', UserSchema)
Good news at that time all the routes, models, and middlewares are ready the only things is ready is our HTML(EJS) Pages.
Login and main pages
Now its time to create our login page using bootstrap.
file:views/login.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.0-2/css/all.min.css"
integrity="sha256-46r060N2LrChLLb5zowXQ72/iKKNiw/lAmygmHExk/o=" crossorigin="anonymous" />
<link rel="stylesheet" href="/css/style.css">
<title>Login</title>
</head>
<body>
<div class="container login-container">
<div class="card" style="margin-top:100px;">
<div class="card-content">
<div class="section" style="text-align: center;">
<a href="/auth/google" class="btn red darken-1">
<i class="fab fa-google left"></i> Log In With Google
</a>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</body>
</html>
Lets Create Main page which appear after user login.
file:views/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Done</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
</head>
<body>
<!-- As a link -->
<nav class="navbar navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="/"><img class="logo" src=<%=userinfo.image %> alt=""> <%=
userinfo.firstName %></a>
<a class="navbar-brand btn btn-danger btn-small" style="color: white;" href="/auth/logout">Logout</a>
</div>
</nav>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW"
crossorigin="anonymous"></script>
<script src="ejs.min.js"></script>
</body>
</html>
Preview
ππ
Our Google Authentication App is ready.
Now it's your time to use that amazing Middleware passport.js
Good Luck ππΆ
Live Preview
Here is the demo. I use the above code in my project Todo app
Live Preview.
Want to build a to-do app? refer to my this article.
Top comments (3)
Hey @atultyagi612
I ran the project on local with no modifications, looks like there is some error being thrown there:
I had faced this exact issue on my project as well. I came across your repo looking for a working example but unfortunately your repo is also giving the same error.
I tried your demo heroku app though, it is working fine. So I was wondering if that is running the same code or you had to do some fixes to get around the above error?
Thanks and awesome article ππ»
Hello,
Pardon my ignorance, I followed the tutorial step by step and used mongodb atlas as my db engine,now how do I run and access the app, I tried localhost:3000 in my web browser but it did not work. Thank you
Hi, thanks for using the diagram that I created. Please add a credit if you want to use it in your article. medium.com/@cheahpark/the-big-pict...