DEV Community

Cover image for Fixing Better Auth in TanStack Start: How to Pass Headers in Server Functions
rogasper
rogasper

Posted on • Originally published at rogasper.com

Fixing Better Auth in TanStack Start: How to Pass Headers in Server Functions

If you are building a modern web application using TanStack Start and Better Auth, you might have hit a specific, frustrating wall.

You have your authentication set up, the client-side an active organization or updating a profile, the request fails or acts as if the user isn't logged in.

I recently spent hours debugging this exact issue while trying to implement an organization switcher. The solution is simple, but not immediately obvious if you are new to TanStack's server utilities: You need to manually forward the request headers.

The Problem: Missing Context

When you use Better Auth (or many other auth libraries), the server needs to know who is making the request. Usually, this information (session tokens or cookies) lives in the HTTP headeres.

In a standard client-side fetch, the browser handless cookies automatically. However, when you use a TanStack Start Server Function (createServerFn), you are running logic in an isolated server environment. If you make a call to your auth API from there without passing the original request's context, Better Auth sees an anonymous request.

The Solution: getRequest

To fix this, TanStack Start provides a utility called getRequest from @tanstack/react-start/server.
This allows you to access the incoming request object, extract the headers, and pass them along to Better Auth.

Here is the practical example that solved it for me. I wanted to create a server function to switch the user's active organization:

The code

import { getRequest } from "@tanstack/react-start/server";
import { createServerFn } from "@tanstack/start";
import { z } from "zod";
import { auth } from "./auth"; // Your Better Auth instance

export const switchOrganization = createServerFn().inputValidator(z.object({
    organizationId: z.string().min(1),
})).handler(async ({data}) => {
    // 1. Get the current request context
    const request = getRequest();

    // 2. Pass the headers to Better Auth
    const organization = await auth.api.setActiveOrganization({
        body: {
            organizationId: data.organizationId
        },
        // This is the magic line that makes auth work:
        headers: request.headers,
    })
    return organization;
})
Enter fullscreen mode Exit fullscreen mode

Why This Works

  1. getRequest(): This function retrives the standard Request object for the current server execution.
  2. headers: request.headers: By passing these headers into the auth.api.setActiveOrganization configuration, you are forwading the user's session cookies. Better Auth can now read those cookies, validate the session, and confirm that the user actually has permission to switch organizations.

Summary

When working with Server Functions (RPCs) in TanStack Start, never assume the context is passed automatically to third-party libraries.If you are getting "Unauthorized" erros or weird behaviors on server-side mutations, check if you are forwading the headers. It's a small addition to your code, but it's the bridge that makes TanStack Start and Better Auth work seamlessly together.

for more information you can visit my website

Top comments (0)