├── .gitignore ├── README.md ├── views ├── dashboard.pug ├── stories │ ├── index.pug │ ├── add.pug │ ├── edit.pug │ └── show.pug ├── profile.pug ├── index.pug ├── partials │ ├── _footer.pug │ └── _mixins.pug └── layout.pug ├── middlewares └── auth.js ├── routes ├── index.js ├── auth.js └── stories.js ├── package.json ├── helper.js ├── models ├── User.js └── Story.js ├── config └── passport.js ├── public ├── styles │ └── style.css └── img │ ├── public.svg │ └── myProfile.svg └── app.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | keys.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository is an experiment to try passport Google OAuth Authentication. 2 | -------------------------------------------------------------------------------- /views/dashboard.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | include partials/_mixins 3 | block content 4 | .container.mt-3 5 | .row 6 | .col-md-12 7 | +table(stories) 8 | 9 | -------------------------------------------------------------------------------- /views/stories/index.pug: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | include ../partials/_mixins 3 | block content 4 | if stories 5 | .container.mt-3 6 | .row 7 | each story in stories 8 | .col-md-3.mb-3 9 | +storyCard(story) -------------------------------------------------------------------------------- /middlewares/auth.js: -------------------------------------------------------------------------------- 1 | exports.loginAuth = (req, res, next) => { 2 | 3 | if(req.isAuthenticated()){ 4 | return next(); 5 | } 6 | res.redirect('/'); 7 | 8 | }; 9 | 10 | exports.guestCheck = (req, res, next) => { 11 | 12 | // if(req.isAuthenticated()){ 13 | // return res.redirect('/dashboard'); 14 | // } 15 | return next(); 16 | 17 | }; -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const { loginAuth, guestCheck } = require('../middlewares/auth'); 4 | const { Story } = require('../models/Story'); 5 | router.get('/', guestCheck, (req, res) => { 6 | res.render('index'); 7 | }); 8 | 9 | router.get('/dashboard', loginAuth, async (req, res) => { 10 | let stories = await Story.find({ 11 | user: req.user.id 12 | }).populate('user'); 13 | res.render('dashboard',{ 14 | stories 15 | }); 16 | }); 17 | 18 | 19 | module.exports = router; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "googleAuthNode", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node app.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "cookie-parser": "^1.4.4", 14 | "express": "^4.16.4", 15 | "express-session": "^1.15.6", 16 | "method-override": "^3.0.0", 17 | "moment": "^2.24.0", 18 | "mongoose": "^5.4.19", 19 | "passport": "^0.4.0", 20 | "passport-google-oauth20": "^2.0.0", 21 | "pug": "^2.0.3" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /helper.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const moment = require('moment'); 3 | 4 | exports.pre = (data) => { 5 | return `
${JSON.stringify(data)}`;
6 | };
7 |
8 | exports.serveSVG = (filename) => {
9 | return fs.readFileSync(`./public/img/${filename}.svg`)
10 | };
11 |
12 | exports.bodyPreview = (input) => {
13 | if (input) {
14 | let body = input.replace(/<(?:.|\n)*?>/gm, "");
15 | return body.length > 40 ? body.substring(0, 40) + '...' : body;
16 | }
17 | }
18 |
19 | exports.dateFormat = (date, format) => {
20 | return moment(date).format(format);
21 | };
--------------------------------------------------------------------------------
/views/profile.pug:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | //- != h.pre(stories)
5 | //- != h.pre(user)
6 | .container
7 | .profile.mb-3
8 | .profile__cover
9 | .profile__header.p-3(style=`background-image: url(${user.image})`)
10 | .profile__primary
11 | img.profile__image(src=user.image)
12 | p.lead.text-center.font-weight-bold.mt-3= user.firstName+' '+user.lastName
13 | .card.p-3(style="margin-top:140px")
14 | .row
15 | .col-md-3
16 | .stat
17 | | Total stories = #{stories.length}
--------------------------------------------------------------------------------
/models/User.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 |
4 | const userSchema = new mongoose.Schema({
5 | googleId: {
6 | type: String,
7 | required: true,
8 | unique: true
9 | },
10 | email: {
11 | type: String,
12 | required: true,
13 | unique: true
14 | },
15 | firstName: {
16 | type: String,
17 | required: true
18 | },
19 | lastName: {
20 | type: String,
21 | required: true
22 | },
23 | image: {
24 | type: String
25 | }
26 | });
27 |
28 | const User = mongoose.model('user',userSchema);
29 |
30 | exports.User = User;
31 | exports.userSchema = userSchema;
--------------------------------------------------------------------------------
/routes/auth.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const router = express.Router();
3 | const passport = require('passport');
4 |
5 | router.get('/google', passport.authenticate('google',{
6 | scope: ['profile', 'email']
7 | }));
8 |
9 | router.get('/google/callback',
10 | passport.authenticate('google', { failureRedirect: '/' }),(req, res) => {
11 | res.redirect('/stories');
12 | });
13 |
14 | router.get('/logout',(req, res) => {
15 | req.logout();
16 | res.redirect('/');
17 | });
18 |
19 | router.get('/verify',(req, res) => {
20 | if(req.user){
21 | console.log(req.user);
22 | } else {
23 | console.log('Not auth');
24 | }
25 | })
26 |
27 |
28 |
29 | module.exports = router;
--------------------------------------------------------------------------------
/views/index.pug:
--------------------------------------------------------------------------------
1 | extends layout
2 | include partials/_mixins
3 | block content
4 | +storiesNavbar
5 | .jumbotron.bg-light.rounded-0
6 | .container
7 | if !user
8 | .display-5
9 | span Sign in to live your life worthy
10 | br
11 | a.btn.btn-sm.btn-danger.mt-3.text-uppercase(href="/auth/google") Sign in with Google
12 | else
13 | .text-success
14 | .display-4
15 | | Welcome #{user.firstName},
16 | p.lead
17 | | Read the experiences of others to improve your life
--------------------------------------------------------------------------------
/models/Story.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 |
4 | const storySchema = new mongoose.Schema({
5 | title: {
6 | type: String,
7 | required: true,
8 | unique: true
9 | },
10 | body: {
11 | type: String,
12 | required: true,
13 | unique: true
14 | },
15 | status: {
16 | type: String,
17 | required: true
18 | },
19 | allowComments: {
20 | type: Boolean,
21 | required: true
22 | },
23 | comments: [{
24 | commentBody:{
25 | type: String,
26 | },
27 | commentDate:{
28 | type: Date,
29 | default: Date.now
30 | },
31 | commentUser:{
32 | type: mongoose.Schema.Types.ObjectId,
33 | ref: 'user'
34 | }
35 | }],
36 | user: {
37 | type: mongoose.Schema.Types.ObjectId,
38 | ref: 'user'
39 | },
40 | date: {
41 | type: Date,
42 | default: Date.now
43 | }
44 | });
45 |
46 | const Story = mongoose.model('story',storySchema);
47 |
48 | exports.Story = Story;
49 | exports.storySchema = storySchema;
--------------------------------------------------------------------------------
/views/stories/add.pug:
--------------------------------------------------------------------------------
1 | extends ../layout
2 |
3 | block content
4 | .container-fluid
5 | .row.my-3
6 | .col-md-6.mx-auto
7 |
--------------------------------------------------------------------------------
/config/passport.js:
--------------------------------------------------------------------------------
1 | const GoogleStrategy = require('passport-google-oauth20').Strategy;
2 | const passport = require('passport');
3 | const key = require('./keys');
4 | const { User } = require('../models/User');
5 |
6 | module.exports = function (passport) {
7 | passport.use(new GoogleStrategy({
8 | clientID: key.googleClientID,
9 | clientSecret: key.googleClientScret,
10 | callbackURL: "/auth/google/callback",
11 | proxy: true
12 | },
13 | async (accessToken, refreshToken, profile, done) => {
14 |
15 | const newUser = {
16 | googleId: profile.id,
17 | email: profile.emails[0].value,
18 | firstName: profile.name.givenName,
19 | lastName: profile.name.familyName,
20 | image: profile.photos[0].value
21 | };
22 |
23 | let user = await User.findOne({
24 | googleId: newUser.googleId
25 | });
26 | if (user) {
27 | done(null, user);
28 | }
29 | else {
30 | user = new User(newUser);
31 | await user.save();
32 | done(null, user)
33 | }
34 |
35 | }));
36 | passport.serializeUser(function (user, done) {
37 | done(null, user.id);
38 | });
39 |
40 | passport.deserializeUser(function (id, done) {
41 | User.findById(id, function (err, user) {
42 | done(err, user);
43 | });
44 | });
45 | };
--------------------------------------------------------------------------------
/views/partials/_footer.pug:
--------------------------------------------------------------------------------
1 |
2 | mixin footer
3 |
--------------------------------------------------------------------------------
/views/stories/edit.pug:
--------------------------------------------------------------------------------
1 | extends ../layout
2 |
3 | block content
4 | //- != h.pre(story)
5 | .container-fluid
6 | .row.my-3
7 | .col-md-6.mx-auto
8 | form(action=`/stories/${story.id}?_method=PUT` method="post")
9 | input(type="hidden" name="_method" value="PUT")
10 | 32 | | #{h.bodyPreview(story.body)} 33 |
34 | if user 35 | if story.user.id === user.id 36 | a.mr-2(href=`/stories/edit/${story.id}` class="btn btn-warning btn-sm") Edit 37 | a(href=`/stories/show/${story.id}` class="btn btn-success btn-sm") Read more 38 |