ssl certificate is valid but still showing error during passport js google authentication on heroku - node.js

Note: it is showing this error on google chrome and authentication doesn't work on firefox
Hi. I have implemented google authentication using passport js. I am using React JS on the front end. everything is working on my localhost but after I deployed it. during authentication, it shows the "Site is not secure" error. what shall I do now? I have been searching for answers.
site link: https://popupchat.herokuapp.com/
// server.js
import express from "express";
import dotenv from "dotenv";
import path from "path";
import session from "express-session";
import passport from "passport";
import { Strategy as GoogleStrategy } from "passport-google-oauth20";
dotenv.config();
const app = express();
app.use(express.json());
app.set("trust proxy", 1);
app.use(
session({
secret: "abcdsdfdfdfffd",
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
maxAge: 1000 * 60 * 60 * 24 * 7, // One Week
sameSite: "none",
secure: true,
},
})
);
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => {
return done(null, user);
});
passport.deserializeUser((user, done) => {
return done(null, user);
});
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback",
},
function (request, accessToken, refreshToken, profile, done) {
return done(null, profile);
}
)
);
app.get(
"/auth/google",
passport.authenticate("google", { scope: ["profile", "email"] })
);
app.get(
"/auth/google/callback",
passport.authenticate("google", {
failureRedirect: "/",
session: true,
}),
function (req, res) {
res.redirect("/");
}
);
app.get("/getuser", (req, res) => {
res.send(req.user);
});
app.get("/auth/logout", (req, res) => {
if (req.user) {
req.logout();
res.send("done");
}
});
// ================== deployment ==========================
const __dirname1 = path.resolve();
if (process.env.NODE_ENV === "production") {
app.use(express.static(path.join(__dirname1, "/frontend/build")));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname1, "frontend", "build", "index.html"));
});
} else {
app.get("/", (req, res) => {
res.send("API is running");
});
}
// ================== deployment ==========================
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log("server started on port 5000"));
// frontend
import { useEffect, useState } from "react";
import axios from "axios";
function Login() {
const google = () => {
window.open(`/auth/google`, "_self");
};
return (
<button type="button" onClick={google}>
Login with Google
</button>
);
}
export default Login;

Related

passport js is not saving cookies in the browser I upload frontend to Netlify

I am creating a mern stack chat application. I used google authentication using passport js. everything is working fine in the localhost. I can log in and the user get saved in the database but when I upload the frontend to Netlify it does not work. I can login and the user get saved in the Mongodb database but cookies doesn't get saved.
// passport.js middle ware
import * as dotenv from "dotenv";
import passport from "passport";
import { Strategy as GoogleStrategy } from "passport-google-oauth20";
import User from "./models/user.js";
dotenv.config();
passport.serializeUser((user, cb) => {
cb(null, user.id);
});
passport.deserializeUser((id, cb) => {
User.findById(id).then((user) => {
cb(null, user);
});
});
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.GOOGLE_CALLBACK_URL,
},
function (accessToken, refreshToken, profile, cb) {
console.log(" google strategy called");
User.findOne({ googleId: profile.id }).then((currentUser) => {
if (currentUser) {
// already have user
console.log("user find one called");
cb(null, currentUser);
} else {
// if not, create user in our db
new User({
name: profile.displayName,
googleId: profile.id,
email: profile.emails[0].value,
picture: profile.photos[0].value,
membership: "free",
})
.save()
.then((newUser) => {
cb(null, newUser);
});
}
});
}
)
);
// index.js
dotenv.config();
const app = express();
app.use(
cors({
origin: "https://taupe-starburst-7fab32.netlify.app",
methods: "GET,POST,PUT,DELETE",
credentials: true,
})
);
app.use(express.json());
Connection();
app.use(
cookieSession({
name: "session",
keys: [process.env.SESSION_SECRET],
// Cookie Options
domain: "https://taupe-starburst-7fab32.netlify.app",
maxAge: 24 * 60 * 60 * 1000, // 24 hour
secure: true,
httpOnly: true,
sameSite: "none",
})
);
// to solve session.regenarate issue
app.use(function (request, response, next) {
if (request.session && !request.session.regenerate) {
request.session.regenerate = (cb) => {
cb();
};
}
if (request.session && !request.session.save) {
request.session.save = (cb) => {
cb();
};
}
next();
});
app.use(passport.initialize());
app.use(passport.session());
app.use("/auth", router);
const server = app.listen(process.env.PORT || 5000, () =>
console.log("server running")
);
// auth.js
import express from "express";
import passport from "passport";
const router = express.Router();
//sunccess redirect
router.get("/login/success", (req, res) => {
if (req.user) {
res.status(200).json({
success: true,
message: "successfull",
user: req.user,
});
} else {
res.status(401).json({
success: false,
message: "Unauthorized: User is not logged in",
});
}
});
//failure redirect
router.get("/login/failed", (req, res) => {
res.status(401).json({
success: false,
message: "failure",
});
});
// authenticate
router.get(
"/google",
passport.authenticate("google", { scope: ["email", "profile"] })
);
// callback
router.get(
"/google/callback",
passport.authenticate("google", {
successRedirect: process.env.CLIENT_URL,
failureRedirect: "/login/failed",
})
);
//logout
router.get("/logout", (req, res) => {
req.logout(function (err) {
if (err) {
return next(err);
}
res.redirect(`${process.env.CLIENT_URL}/login`);
});
});
export default router;
// React Frontend
function Login() {
const google = () => {
window.open(`${process.env.REACT_APP_API_URL}auth/google`, '_self');
};
return (
<button type="button" onClick={google}>
Login with Google
</button>
);
}
export default Login;

Session-key changes on every request on hosting with GCP

Some minor information about the problem:
The problem does not occur when ran on localhost/develpoment.
Hosted on App engine with PostgresSQl and I can see that it adds session to Postgres Table in GCP.
I have a very weird problem regarding session. I am trying to implement a login for my web app using Steam-auth on the API. However, it only works to sign in when using Google chrome(not incognito mode). I have tried firefox and safari to but it wont work. The reason is that incognito mode and firefox sends different cookies or less cookies on every request.
I at first thought the problem might have been caused by no session store but after implementing connect-pg-simple it didn't fix it. So from what I can tell it must be a setting issue with the session.
I am sending all requests from with 'withCredentials:true'.
import axios from 'axios';
// config
// ----------------------------------------------------------------------
const HOST_API = process.env.NODE_ENV === "production" ? "https://www.norskins-api.com/api/v1/" : "http://localhost:3005/api/v1/";
const axiosInstance = axios.create({
baseURL: HOST_API,
withCredentials: true
});
axiosInstance.interceptors.response.use(
(response) => response,
(error) => Promise.reject((error.response && error.response.data) || 'Something went wrong')
);
export default axiosInstance;
The site is hosted at norskins.com if you wanna inspect network and see the changes in the cookies.
Server.js:
//Over this are just a lot of imports
app.use(cors(corsOptions));
//SESSION SETUP TOOLS
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
//DDOS PROTECTION
app.use(compression())
app.use(helmet())
app.use(limiter);
//SESSION SETTINGS
app.set('trust proxy', true);
app.use(
session({
...sessionSettings, store: new (require('connect-pg-simple')(session))({
pool: pool
}),
})
);
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
// Initiate Strategy
passport.use(
new SteamStrategy(
{
returnURL: BACKEND_URL + "/api/auth/steam/return",
realm: BACKEND_URL,
apiKey: "A SECRET", //this is obv correct
},
function (identifier, profile, done) {
process.nextTick(function () {
profile.identifier = identifier;
return done(null, profile);
});
}
)
);
app.use(passport.initialize());
app.use(passport.session());
app.get("/", (req, res) => {
res.send("Welcome to the most clever backend of all time");
});
app.get("/api/v1/user", (req, res) => {
console.log(req.session.steamuser)
if (req.session.steamuser) {
res.send(req.session.steamuser)
}
else {
res.send(false)
}
});
app.get(
"/api/v1/auth/steam",
passport.authenticate("steam", { failureRedirect: "/" }),
function (req, res) {
res.send(req.user);
}
);
app.get(
"/api/auth/steam/return",
passport.authenticate("steam", { failureRedirect: "/" }),
function (req, res) {
logon(req.user);
req.session.steamuser = req.user;
res.redirect(FRONTEND_URL);
}
);
app.post("/api/v1/logout", (req, res) => {
req.session.destroy();
res.status(200).send();
});
app.listen(port, () => {
console.log("Listening, port " + port);
});
Session Settings:
const rateLimit = require('express-rate-limit');
const isProduction = process.env.NODE_ENV === 'production';
const sessionSettings = {
secret: "ThisSuperSecretKeyThatStackWontSee", //obv something else
saveUninitialized: true,
resave: false,
cookie: {
maxAge: 24 * 60 * 60 * 1000, httpOnly: true, secure: isProduction, sameSite: isProduction ? "none" : "lax"
},
name: 'Session_Id',
};
const urlSettings = {
FRONTEND_URL: isProduction ? "https://www.norskins.no" : "http://localhost:3000",
BACKEND_URL: isProduction ? "https://www.norskins-api.com" : "http://localhost:3005"
}
const corsOptions = {
origin: [urlSettings.FRONTEND_URL],
credentials: true, //access-control-allow-credentials:true
methods: ['POST', 'PUT', 'GET', 'OPTIONS', 'HEAD']
};
const limiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1 minute
max: isProduction ? 1000 : 50000, // 5 requests,
});
I have never hosted something on GCP before, but I have no clue why it only works to sing into chrome normal. and why everything else have different session_id on each request.
logon()
async function logon(user) {
const users = await db.query("SELECT * FROM users WHERE id=$1", [user.id]);
if (users.rows.length > 0) {
return;
}
else {
const dateToday = new Date().toISOString().substring(0, 10);
await db.query("INSERT INTO users(id,steam_name,last_updated) values($1,$2,$3) returning *", [user.id, user.displayName, dateToday]);
return;
}
}

Correct session settings for Google cloud express app doesnt work in production using passport

Problem: Everything works fine in development but also in the normal google chrome browser. However when I try incognito and Firefox it sends two different session ids. I cant find a good reason why the session ID changes on the callback URL. I can see that the correct information gets stored, but when a user logs in on firefox the session key is different when the user is on the callback URL than what it is when the user on the home page. The key is however the same everytime I refresh the site but this does not help me as during login the session key is wrong. As I said it works perfect in development.
I have activated withCredentials on the front end.
I am just super confused as it works fine on google chrome but not on anything else.
Here is my code:
Server.js
... //a bunch of imports
app.use(cors(corsOptions));
//SESSION SETUP TOOLS
app.use(cookieParser());
app.use(express.json())
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.json())
//DDOS PROTECTION
app.use(compression())
app.use(helmet())
app.use(limiter);
//SESSION SETTINGS
app.set('trust proxy', true);
app.enable('trust proxy')
const sessionMemStore = () => {
if (isProduction) {
const firestore = new FirestoreStore({
dataset: new Firestore(),
kind: 'express-sessions',
});
return firestore
}
else {
return null
}
};
app.use(
session({
...sessionSettings,
store: sessionMemStore()
})
);
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
// Initiate Strategy
passport.use(
new SteamStrategy(
{
returnURL: BACKEND_URL + "/api/auth/steam/return",
realm: BACKEND_URL,
apiKey: "B14DD3E47A70AC859EE73AB2C656CB34",
},
function (identifier, profile, done) {
process.nextTick(function () {
profile.identifier = identifier;
return done(null, profile);
});
}
)
);
app.use(passport.initialize());
app.use(passport.session());
app.get(
"/api/v1/auth/steam",
passport.authenticate("steam", { failureRedirect: FRONTEND_URL + "/tos" }),
function (req, res) {
res.send(req.user);
}
);
app.get(
"/api/auth/steam/return",
passport.authenticate("steam", { failureRedirect: FRONTEND_URL + "/tos" }),
function (req, res) {
logon(req.user);
req.session.steamuser = req.user;
res.redirect(FRONTEND_URL);
}
);
app.listen(port, () => {
console.log("Listening, port " + port);
});
sessionsettings.
const sessionSettings = {
secret: "someRandomKey",
saveUninitialized: true,
resave: false,
cookie: {
maxAge: 24 * 60 * 60 * 1000, httpOnly: true, secure: true, sameSite: isProduction ? "none" : "lax"
},
name: "session"
};

Parse data from node server to react client - SteamOpenID

How can I send data from my node server to my react client? I use a steam login with node to be able to log in. The server is hosted at localhost:5000 and returns this data once logged in: {"provider":"steam","_json":{"steamid":"525218152" etc. But if you of course just view the website without logging in the webpage becomes empty as expected. How can I parse the data to my frontend? This is my code to fetch the data:
const express = require("express");
var passport = require("passport");
var session = require("express-session");
var passportSteam = require("passport-steam");
var SteamStrategy = passportSteam.Strategy;
var app = express();
// Let's set a port
var port = 5000;
// Spin up the server
app.listen(port, () => {
console.log("Listening, port " + port);
});
// Required to get data from user for sessions
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
// Initiate Strategy
passport.use(
new SteamStrategy(
{
returnURL: "http://localhost:" + port + "/api/auth/steam/return",
realm: "http://localhost:" + port + "/",
apiKey: "API_KEY",
},
function (identifier, profile, done) {
process.nextTick(function () {
profile.identifier = identifier;
return done(null, profile);
});
}
)
);
app.use(
session({
secret: "Whatever_You_Want",
saveUninitialized: true,
resave: false,
cookie: {
maxAge: 3600000,
},
})
);
app.use(passport.initialize());
app.use(passport.session());
// Routes
app.get("/", (req, res) => {
res.send(req.user);
});
app.get(
"/api/auth/steam",
passport.authenticate("steam", { failureRedirect: "/" }),
function (req, res) {
res.redirect("/");
}
);
app.get(
"/api/auth/steam/return",
passport.authenticate("steam", { failureRedirect: "/" }),
function (req, res) {
res.redirect("/");
}
);

Parse data from node server to react client

How can I send data from my node server to my react client? I use a steam login with node to be able to log in. The server is hosted at localhost:5000 and returns this data once logged in: {"provider":"steam","_json":{"steamid":"525218152" etc. But if you of course just view the website without logging in the webpage becomes empty as expected. How can I parse the data to my frontend? This is my code to fetch the data:
const express = require("express");
var passport = require("passport");
var session = require("express-session");
var passportSteam = require("passport-steam");
var SteamStrategy = passportSteam.Strategy;
var app = express();
// Let's set a port
var port = 5000;
// Spin up the server
app.listen(port, () => {
console.log("Listening, port " + port);
});
// Required to get data from user for sessions
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
// Initiate Strategy
passport.use(
new SteamStrategy(
{
returnURL: "http://localhost:" + port + "/api/auth/steam/return",
realm: "http://localhost:" + port + "/",
apiKey: "API_KEY",
},
function (identifier, profile, done) {
process.nextTick(function () {
profile.identifier = identifier;
return done(null, profile);
});
}
)
);
app.use(
session({
secret: "Whatever_You_Want",
saveUninitialized: true,
resave: false,
cookie: {
maxAge: 3600000,
},
})
);
app.use(passport.initialize());
app.use(passport.session());
// Routes
app.get("/", (req, res) => {
res.send(req.user);
});
app.get(
"/api/auth/steam",
passport.authenticate("steam", { failureRedirect: "/" }),
function (req, res) {
res.redirect("/");
}
);
app.get(
"/api/auth/steam/return",
passport.authenticate("steam", { failureRedirect: "/" }),
function (req, res) {
res.redirect("/");
}
);

Resources