Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using passportjs passport.authenticate() in Sapper route or sapper middleware

I used passportjs in the past with expressjs and currently I'm trying to incorporate it with Sapper app but I'm unable to figure out how to inlcude the passport.authenticate() in my route because it's a sapper route not an express route. Also if I try to run everything in my server.js file I run into the issue of how to integrate it with the sapper middleware. How do you use passport.authenticate() in/with Sapper middleware or sapper routes js files (which is the front not server routes)?

My server.js is typical:

const sirv = require('sirv');
import express from 'express';
var cookieParser = require('cookie-parser');
import * as sapper from '@sapper/server';
const session = require('express-session');
var passport = require('passport');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/passport', { 
 useNewUrlParser: true });
const MongoStore = require('connect-mongo')(session);
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());

app.use(session({
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: true,
    store: new MongoStore({ url: 'mongodb://localhost/passport' }),
    cookie: { secure: false, maxAge: 1000 * 60 * 60 * 24 * 7 }
}));
app.use(passport.initialize());
app.use(passport.session());

const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';

const assets = sirv('static', {
    maxAge: 31536000, // 1Y
    immutable: true
});

 app.use(assets, sapper.middleware({
    session: req => ({
        user: req.session && req.session.user
    })})).listen(process.env.PORT, err => { if (err) console.log('error', err); });

As you can see, Sapper is just a middleware so if I want to authenticate a user and send it to the front/sapper, I need to figure out how to run passport.authenticate() inside the middleware function, right?

If I want to use passport in the route JS file which is sapper front route:

//How to import passport.js here to make passport.authenticate() middleware available?
import passport from './passport';
import User from './mongoso';

export async function post(req, res, next) {

    res.setHeader('Content-Type', 'application/json');
    /* Retrieve the data */ 
    var data = req.body;


    req.session.user = data.email;
    console.log("Here's the posted data:", data);
    console.log("information in the session is:", req.session);

    /* Returns the result */
    return res.end(JSON.stringify({ Email: req.session.user }));
    //return res.json({ data: data });

}

Any ideas? Greatly appreciated if someone out there could help.

like image 984
Marco Avatar asked Oct 25 '19 13:10

Marco


People also ask

What does passport authenticate () do?

In this route, passport. authenticate() is middleware which will authenticate the request. By default, when authentication succeeds, the req. user property is set to the authenticated user, a login session is established, and the next function in the stack is called.

How do I pass additional parameters to passport authenticate?

You can use the request itself to transfer some additional parameters from and to the strategy function. In the following example the two parameters _toParam and _fromParam are used for this concern. app. get('/auth/facebook/:appId', function(req,res,next){ req.


2 Answers

You don't need to run passport.authenticate() inside the sapper.middleware. You need to add passport-local strategy firstly, then do serializeUser and deserializeUser, then create routes to do passport.authenticate and after that catch req.session.passport object in sapper.middleware. I don't use passport-local strategy, but here is my working server.js with passport-github strategy.

//server.js

import sirv from 'sirv';
import express from 'express';
import passport from 'passport';
import { Strategy } from 'passport-github';
import bodyParser from 'body-parser';
import session from 'express-session';
import sessionFileStore from 'session-file-store';
import compression from 'compression';
import * as sapper from '@sapper/server';

const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';

const FileStore = sessionFileStore(session);

passport.use(new Strategy({
    clientID: 'someClientID',
    clientSecret: 'someClientSecret',
    callbackURL: 'http://localhost:3000/auth/callback',
}, (accessToken, refreshToken, profile, cb) => {
    // console.log('success');
    return cb(null, profile);
}));

passport.serializeUser(function (user, cb) {
    cb(null, user);
});

passport.deserializeUser(function (obj, cb) {
    cb(null, obj);
});

const expressServer = express() 
    .use(passport.initialize())
    .use(bodyParser.json())
    .use(session({
        secret: 'conduit',
        resave: false,
        saveUninitialized: true,
        cookie: {
            maxAge: 31536000
        },
        store: new FileStore({
            path: `.sessions`
        })
    }))

    .get('/auth/login',
        passport.authenticate('github'))
    .get('/auth/callback',
        passport.authenticate('github', { failureRedirect: '/auth/login' }),
        (req, res) => {
            res.redirect('/');
            //console.log(req.user.username);
        })
    .get('/auth/logout', (req, res) => {
        req.logout();
        req.session.destroy( function (err) {
            res.redirect('/'); 
        });
    })

    .use(
        compression({ threshold: 0 }),
        sirv('static', { dev }),
        sapper.middleware({
            session: req => {
                const user = req.session.passport ? req.session.passport.user.username : null;
                // console.log(req.session.passport.user.username);
                return { user };
            }
        })
    )
if (dev) {
    expressServer.listen(PORT, err => {
        if (err) console.log('error', err);
    });
}

export { expressServer }

Аfter this, you can catch that this { user } object in your client sapper route component through Stores using const { session } = stores(); console.log($session) or you can get it via special preload function to apply before page is rendered, like this for example in index.svelte

<script context="module">
  export function preload(page, { user }) {
    return { user };
  }
</script>

<script>
  import { stores } from "@sapper/app";
  import { onMount } from "svelte";

  const { session } = stores();
  export let user;

  onMount(() => {
    console.log($session);
  });

</script>

<div>
  {#if !user}
    <p>Not logged in</p>
  {:else}
    <p>Logged in!</p>
  {/if}
</div>

Here i use two approaches same time, but most of time it will be enough to use preload, no need to direct access to session in stores. Hope this will help you. Good luck!

like image 180
DioXine Avatar answered Jan 01 '23 23:01

DioXine


I used the answer from DioXine to implement Google Auth.
The cookie is now also http only.

import sirv from "sirv";
import express from "express";
import bodyParser from "body-parser";
import session from "express-session";
import sessionFileStore from "session-file-store";
import compression from "compression";
import * as sapper from "@sapper/server";
import passport from "passport";
import { Strategy as GoogleStrategy } from "passport-google-oauth20";

const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === "development";

passport.use(
  new GoogleStrategy(
    {
      clientID: GOOGLE_CLIENT_ID,
      clientSecret: GOOGLE_CLIENT_SECRET,
      callbackURL: "http://localhost:3000/auth/google/callback",
    },
    function (accessToken, refreshToken, profile, cb) {
      // User.findOrCreate({ googleId: profile.id }, function (err, user) {
      //   return cb(err, user);
      // });
      return cb(null, profile);
    }
  )
);

passport.serializeUser(function (user, cb) {
  cb(null, user);
});

passport.deserializeUser(function (obj, cb) {
  cb(null, obj);
});

const FileStore = sessionFileStore(session);

const sessionConfig = {
  secret: "sefmvks4Fgblolf4sdJHBd",
  resave: false,
  saveUninitialized: true,
  cookie: {
    httpOnly: true,
    maxAge: 31536000,
  },
  //TODO: redis
  store: new FileStore({
    path: `.sessions`,
  }),
};

express()
  .use(passport.initialize())
  .use(bodyParser.json())
  .use(session(sessionConfig))

  .get("/auth/google", passport.authenticate("google", { scope: ["profile"] }))
  .get(
    "/auth/google/callback",
    passport.authenticate("google", { failureRedirect: "/auth/login" }),
    (req, res) => {
      res.redirect("/");
    }
  )
  .get("/auth/logout", (req, res) => {
    req.logout();
    req.session.destroy(function (err) {
      res.redirect("/");
    });
  })
  .use(
    compression({ threshold: 0 }),
    sirv("static", { dev }),
    sapper.middleware({
      session: (req) => {
        const user = req.session.passport ? req.session.passport.user.id : null;
        return { user };
      },
    })
  )
  .listen(PORT, (err) => {
    if (err) console.log("error", err);
  });

This is not changed:

<script context="module">
  export function preload(page, { user }) {
    return { user };
  }
</script>

<script>
  import { stores } from "@sapper/app";
  import { onMount } from "svelte";

  const { session } = stores();
  export let user;

  onMount(() => {
    console.log($session);
  });

</script>

<div>
  {#if !user}
    <p>Not logged in</p>
  {:else}
    <p>Logged in!</p>
  {/if}
</div>

If it only works after refresh check this: https://github.com/sveltejs/sapper/issues/567#issuecomment-542788270

like image 29
roeland Avatar answered Jan 01 '23 22:01

roeland