How to set equivalent of fetch's { credentials: "include" } in Redux Toolkit's createApi?

Nic*_*eat 7 express reactjs passport.js rtk-query

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`;
        },
      }),
    };
  },
});
Run Code Online (Sandbox Code Playgroud)

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}`);
});

Run Code Online (Sandbox Code Playgroud)

Why isn't deserializeUser() being called??

phr*_*hry 17

fetchBaseQuery只是一个fetch带有一些额外选项的包装。

所以要么是

  baseQuery: fetchBaseQuery({
    baseUrl: "http://localhost:4000",
    prepareHeaders(headers) {
      return headers;
    },
    credentials: "include"
  }),
Run Code Online (Sandbox Code Playgroud)

或者

        query: () => {
          return { url: `/getuser`, credentials: "include" };
        },
Run Code Online (Sandbox Code Playgroud)

  • 我遇到了类似的问题,我的 NestJS API 没有向托管我的 React 应用程序前端的浏览器传递会话 cookie。这个答案让我解锁了,谢谢! (3认同)