EDIT: for some reason my Vue frontend isn't setting the session cookie
Goal:
Implement Login with Twitch and have synced authenticated session between frontend and backend
Description:
I have a problem with making Passport.js authentication work when in development environment with my architecture described below. I'm trying to implement Login with Twitch (social website) using passport-twitch
Frontend: Vue.js, webpack
Backend: Node, Express, Passport
My Development Environment:
I run npm run dev and have a hot-reload server running my Vue.js client on localhost:8080. Note that this hot-reload server for reloading the frontend is only run when I'm developing.
I also have my Node backend serving some APIs while running on localhost:3000 and my local frontend will make HTTP requests to the local backend.
Production Environment
When preparing for production, I will run npm run build on my Vue.js frontend and it will be minified and placed in a dist folder as plain static HTML, CSS, and JS files.
My Node/Express backend server will serve these static files as well as supporting the backend APIs.
Code
This is my auth.js module that I import in my app.js file that npm start will start server with:
const passport = require('passport')
const TwitchStrategy = require('passport-twitch').Strategy
// Retrieve our encrypted secrets depending on the environment
const config = require('config')
// Postgresql connection
var knex = require('knex')({
client: 'pg',
connection: config.get('postgres')
});
passport.use(new TwitchStrategy({
clientID: config.get('twitch.clientID'),
clientSecret: config.get('twitch.clientSecret'),
callbackURL: config.get('twitch.authCallbackURL'),
scope: 'user_read'
}, (accessToken, refreshToken, profile, done) => {
// Upsert into users table
knex.raw(`
INSERT INTO users
(twitch_id)
VALUES
(${profile.id})
ON CONFLICT (twitch_id) DO UPDATE SET
updated_at = now() at time zone 'utc'
WHERE users.twitch_id = '${profile.id}'
RETURNING *`)
.then((rows, err) => {
return done(err, profile)
})
}))
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
module.exports = passport
I have these endpoints on localhost:3000 backend running to support passport-twitch
app.get('/auth/twitch', passport.authenticate('twitch'))
app.get('/auth/twitch/callback', passport.authenticate('twitch', { failureRedirect: '/'}), (req, res) => {
// Successful authentication, redirect home.
return res.redirect('/')
})
Problem when in Development Environment Workflow
I have 2 servers running in development environment.
When writing and testing frontend code in dev, I'm running hot-reloaded frontend at localhost:8080, and call the backend.
But I need to call localhost:3000/auth/twitch to redirect user to Login with Twitch page. However, when user finishes logging in, it will redirect me to localhost:3000/auth/callback, which redirects to localhost:3000/.
The authenticated sessions are disconnected at this point and frontend has no idea how to auth?
How do I sync the authenticated session in development mode between Vue.js client/frontend and the Node backend?
// This helps me get the current authenticated user in the session (returns empty hash in this case)
// Works fine in production mode since the Node backend gets to serve the minified frontend files
app.get('/self', (req, res) => {
res.json(req.user || {})
})