Having trouble retrieving the user-object within tRPC createContext using express

I'm encountering an issue with my tRPC configuration where it is unable to access the express session on the request object.

Currently, I am implementing passport.js with Google and Facebook providers. Whenever I make a request to a regular HTTP route (outside of the tRPC router), I am able to retrieve the user info by calling req.user.

Here is a snippet from my app.ts file:

import * as trpc from '@trpc/server';
import * as trpcExpress from '@trpc/server/adapters/express';

const appRouter = trpc
    .router()
    .mutation('addTodo', {
        input: z.string(),
        resolve: ({input, ctx}) => {
            // Add a todo
        },
    });

const app = express();
app.use(
    session({
        secret: 'use an env-variable here',
    }),
);
app.use(passport.initialize());
app.use(passport.session());

app.use(
    '/trpc',
    trpcExpress.createExpressMiddleware({
        router: appRouter,
        createContext: (ctx: trpcExpress.CreateExpressContextOptions) => {
            // === ISSUE OCCURS HERE ===
            console.log(ctx.req.user);
            //                   ^ RETURNS UNDEFINED
            return ctx;
        },
    }),
);

app.get("ping", (req, res) => {
    console.log(req.user);
    //                ^ RETURNS THE USER
    res.send("pong");
})

While it may seem like tRPC does not provide user information, there might be a workaround available. Any suggestions on how to address this challenge?

Answer №1

My familiarity lies more within the realm of express sessions rather than passport, so understanding how passport works is a bit uncertain for me. However, I believe the underlying concept might remain similar.

function createContext(opts: trpcExpress.CreateExpressContextOptions) {
  let user = {};
  if (opts.req.session.user) {
    user = opts.req.session.user;
  }

  return {
    user
  };
}

type Context = inferAsyncReturnType<typeof createContext>;
const t = initTRPC.context<Context>().create();
const appRouter = t.router({
  hello: t.procedure.query(({ ctx, input }) => {
    console.log("user", ctx.req?.session?.user);
    console.log({ input });
    return "Hello world";
  }),

  session: t.procedure.query(({ ctx, input }) => {
    console.log({ input });
    ctx.req.session.user = { name: "jane" };
    return "session created";
  }),
});

app.use(
  "/trpc",
  trpcExpress.createExpressMiddleware({ router: appRouter, createContext })
);

In conclusion, ensure to examine the req.session object for the user and subsequently include it in the context's returned object.

Answer №2

I encountered a similar issue, although mine was related to typescript. Upon further investigation, I realized that the request types were not aligned and needed to be adjusted in order for my session to be accessible.

For those utilizing typescript, consider typing your context as shown below:

import { CreateExpressContextOptions } from '@trpc/server/adapters/express'
import { Request } from 'express'
import session from 'express-session'

// Define a custom session type by extending the session type from 'express-session' and including additional properties like userId
export type Session = session.Session &
  Partial<session.SessionData> & { userId?: string }

// Update the ExpressRequest type to incorporate the custom session into the express request object
type ExpressRequest = Omit<CreateExpressContextOptions, 'req'> & {
  req: Request & { session: Session }
}

export const createContext = ({
  req,
  res,
}: ExpressRequest) => {
  return {
    req,
    res,
  }
}

export type Context = inferAsyncReturnType<typeof createContext>

Answer №3

I implemented this in my custom client-side fetcher for trpc integration

{
  credentials: "include"
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Converting an array into an object by using a shared property in each element of the array as the key

I have an item that looks like this: const obj = [ { link: "/home", title: "Home1" }, { link: "/about", title: "About2" }, { link: "/contact", title: "Contact1" } ] as const and I want to p ...

Encountering an error when attempting to iterate over an undefined property using an API

I am trying to fetch all classes and their assignments from Google Classroom. I successfully used Google's example code for listing the classes, but had to write my own code for listing the assignments. While the code runs as expected and lists the as ...

The 'GoogleAuthProvider' property cannot be found on the 'AngularFireAuth' type

When attempting to sign in with Google using 'AngularFireAuth', I encountered an error. Here is the code snippet from my auth.service.ts file: import { Injectable } from '@angular/core'; import { first } from 'rxjs/operators'; ...

Exploring the potential of the forkJoin operator in Angular 4's Observable

I'm currently facing a challenge that involves retrieving both administrators and professionals from the "users" collection using AngularFire's latest version. I am utilizing Observables for this task. My goal is to make two parallel requests an ...

Prisma unexpectedly updates the main SQL Server database instead of the specified database in the connection string

I have recently transitioned from using SQLite to SQL Server in the t3 stack with Prisma. Despite having my models defined and setting up the database connection string, I am encountering an issue when trying to run migrations. Upon running the commands: ...

Building a resolver to modify a DynamoDB item via AppSync using the AWS Cloud Development Kit (CDK)

After successfully creating a resolver to add an item in the table using the code provided below, I am now seeking assistance for replicating the same functionality for an update operation. const configSettingsDS = api.addDynamoDbDataSource('configSet ...

How to Add a Rule to an Existing Application Load Balancer Listener using AWS CDK

When I inherited a project, I discovered an application load balancer with a HTTPS Listener that was set up before I began using CDK. This listener currently has 13 rules in place that route requests based on hostname to different fargate instances, with ...

Mongoose: strange outcomes observed when trying to delete the final element from an array

Update: I made a change in my approach by filtering the array directly and saving it instead of using updateOne and $pull. Surprisingly, this fixed the issue of html elements getting removed. However, the same problem persists when deleting the last item i ...

The role of threads in an express application

I am currently working on an express backend application that receives http requests from a web application. The backend is hosted on AWS ECS Fargate. My question revolves around the usage of multithreading or worker-threads in Node.js for this applicatio ...

Angular Typescript filter function returning an empty arrayIn an Angular project, a

I have a filtering function in Angular that is returning an empty array. Despite trying similar solutions from previous questions, the issue persists. The function itself appears to be correct. Any assistance would be greatly appreciated. gifts represents ...

Headers cannot be set after cookies have been sent

This code is designed to verify if the user inputs from the login page exist in the database. It was functioning correctly until I attempted to set a cookie randomly to track their online state, which resulted in an error. Cannot set Headers after they ar ...

Definition file for mapbox-gl-draw in Typescript, also known as d.ts file

I attempted to define the mapbox-gl-draw project in a typed manner but unfortunately, I was unsuccessful. Can anyone provide some guidance on this? Here is how the javascript file looks: 'use strict'; var Setup = require('./src/setup&apos ...

Vercel encountered issues with "validating code quality and type correctness" during deployment but was successful when performed locally

Running "next build" locally and "vercel build" both work smoothly. However, once deployed to vercel, the "Linting and checking validity of types" fails during the build process. It seems like TypeScript is stricter when building on vercel even with the sa ...

Your search parameter is not formatted correctly

I am currently working on filtering a collection based on different fields such as name by extracting the values from the URL parameters. For example: http://localhost:3000/patient?filter=name:jack I have implemented a method to retrieve and convert these ...

The text inside the Mapbox GL popup cannot be highlighted or copied

I'm encountering an issue where the text in my popups is unselectable. Even though I can close the popups through various methods, such as clicking on them, the pointer remains as a hand icon when hovering over the text and doesn't change to the ...

What are the steps for executing an API and entering data into it?

I have developed an API using NodeJS, ExpressJS and MongoDB to filter and sort school data based on location and fees. The main code snippet looks like this: const express = require('express'); const bodyparser = require('body-parser') ...

Retrieving POST data from requests in Node.js

My goal is to extract parameters from a POST request and store them in the variable postData using the request module. I found helpful information on handling post requests with Express.js here. Additionally, I came across this useful thread on how to retr ...

Does DustJS configuration on the server side allow new lines without escaping them?

I am currently using DustJS in combination with ExpressJS and NodeJS. When ExpressJS renders my DustJS templates, it automatically escapes the new lines and white spaces. However, since I am incorporating JavaScript into my DustJS templates, I want to pre ...

Using React.Fragment in VS Code with TypeScript error 2605 while having checkJs enabled

While utilizing the JS type checking feature in VScode, I encountered an issue with React.Fragment that is being linted with an error: JSX element type 'ReactElement<any>' is not a constructor function for JSX elements. Type 'ReactEle ...

Creating dynamic Kafka topic names within a NestJS microservice

Currently in Nestjs, I have integrated Kafka as my message broker and specified the topic name like so: @MessagePattern('topic-name') async getNewRequest(@Payload() message: any): Promise<void> { // my implementation logic } I am curious ...