I have an express-react-typescript-redux-passport project where I am using createApi
from redux toolkit to call a /getuser
api on my backend.
I'm using passport-google-oauth20
strategy to authenticate users, and the user is successfully authenticated.
My issue is that passport js deserializeUser()
function is not called (even though the serializeUser()
is called, and the user is authenticated using google strategy), so the req.user
parameter is not set automatically when the front end sends requests to the back end.
I suspect that deserializeUser
isn't being called because the I haven't set axio's { withCredentials: true }
(or fetch's {credentials: "include"}
) parameter in my createApi
endpoint. How can I sent this parameter in RTK's createApi?
How do I specify credentials: include here?
Here is my createApi function
export const userApiSlice = createApi({
reducerPath: "api",
baseQuery: fetchBaseQuery({
baseUrl: "http://localhost:4000",
prepareHeaders(headers) {
return headers;
},
}),
endpoints(builder) {
// debugger;
return {
fetchUser: builder.query<IUser, number | void>({
query: () => {
debugger;
return `/getuser`;
},
}),
};
},
});
Here is my server index.js
import express from "express";
import mongoose from "mongoose";
import cors from "cors";
import session from "express-session";
import passport from "passport";
var GoogleStrategy = require("passport-google-oauth20").Strategy;
import { IGoogleAuthUser } from "./types/authTypes";
const PORT = process.env.PORT || 4000;
require("dotenv").config();
const app = express();
mongoose.connect(process.env.LOCAL_DB_ADDRESS, () => {
console.log("connected to mongoose db");
});
app.use(express.json());
app.use(cors({ origin: "http://localhost:3000", credentials: true }));
app.use(
session({
secret: process.env.SESSION_SECRET,
resave: true,
saveUninitialized: true,
})
);
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user: IGoogleAuthUser, done: any) => {
//send a cookie to browser to store user id in session
const { id} = user;
console.log("serializeUser called");
return done(null, id);
});
// why isn't this called???
passport.deserializeUser((userId: string, done: any) => {
//attaches the cookie id from session to req.user
console.log("deserializeUser userId : ", userId);
return done(null, userId);
});
//google strategy
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback",
},
function (accessToken: any, refreshToken: any, profile: any, done: any) {
//this is called on succesful authentication with the above Google Stratety
console.log("successful authorization");
done(null, profile);
}
)
);
//when user clicks on 'login with google' /auth/google is hit
app.get(
"/auth/google",
passport.authenticate("google", { scope: ["profile", "email"] }),
(req, res) => {
console.log("/auth/google called"); //this console.log does not get called, not sure why
}
);
app.get(
"/auth/google/callback",
passport.authenticate("google", {
successRedirect: "http://localhost:3000/profile",
failureRedirect: "http://localhost:3000/login",
}),
function (req, res) {
// console.dir(req);
// Successful authentication, redirect home.
console.log("redirect to profile"); //this does get called
res.redirect("http://localhost:3000/profile");
}
);
app.get("/", (req, res) => {
res.send("Hello world.");
});
app.get("/getuser", (req: any, res: any) => {
//req should have user thanks to serializer/deserializer
console.log(req.user); // => returns undefined even after successful authentication
res.send(req.user);
});
app.listen(PORT, () => {
console.log(`Server Started on ${PORT}`);
});
Why isn't deserializeUser()
being called??