[GH-ISSUE #5705] Help Needed: Implementing Session-Based Authentication for Protected API Routes #27655

Closed
opened 2026-04-17 18:47:13 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @jason-ezenwa on GitHub (Oct 31, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/5705

Description

I'm working on an educational platform with authentication using Better Auth. User registration and login are working correctly, but I'm having trouble implementing proper session-based authentication for protected API routes.

The signup/signin flows work fine, but when I try to access protected endpoints, I'm getting unauthorized responses. I need guidance on how to properly configure the authentication headers and session handling.

Current Setup

Backend Configuration

Auth Configuration:

import { betterAuth } from 'better-auth';
import { mongodbAdapter } from 'better-auth/adapters/mongodb';
import { MongoClient } from 'mongodb';

const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/myapp-db';
const client = new MongoClient(mongoUri);
const db = client.db('myapp-db');

export const auth = betterAuth({
  baseURL: process.env.BETTER_AUTH_URL || 'http://localhost:3000',
  database: mongodbAdapter(db, { client }),
  emailAndPassword: {
    enabled: true,
  },
  trustedOrigins: [
    'http://localhost:5173',
    'https://myapp.example.com',
  ],
  user: {
    modelName: 'users',
    additionalFields: {
      role: {
        type: 'string',
        required: true,
        defaultValue: 'student',
        input: false,
      },
    },
  },
  account: {
    modelName: 'accounts',
  },
  session: {
    modelName: 'sessions',
  },
  token: {
    modelName: 'tokens',
  },
  verification: {
    modelName: 'verifications',
  },
});

Module Setup:

import { AuthModule } from '@thallesp/nestjs-better-auth';

AuthModule.forRoot({ auth: auth }),

Protected Route Example:

import { Controller, Post, Body, UseGuards } from '@nestjs/common';
import { AuthGuard, Session } from '@thallesp/nestjs-better-auth';
import type { UserSession } from '@thallesp/nestjs-better-auth';

@UseGuards(AuthGuard)
@Controller('onboarding')
export class OnboardingController {
  @Post()
  async completeOnboarding(
    @Session() session: UserSession,
    @Body() onboardingData: any,
  ) {
    return this.onboardingService.completeOnboarding(
      session.user.id,
      onboardingData,
    );
  }
}

Frontend Configuration

Auth Client:

import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient({
  baseURL: `${import.meta.env.VITE_API_URL || "http://localhost:3000"}/auth`,
});

API Client:

import axios, { type AxiosInstance } from "axios";

export const api: AxiosInstance = axios.create({
  baseURL: `${import.meta.env.VITE_API_URL || "http://localhost:3000"}`,
});

const completeOnboardingMutation = useMutation({
    mutationFn: (data: OnboardingData) =>
      api.post("/onboarding", data).then((res) => res.data),
    onSuccess: () => {
      navigate("/dashboard");
    },
    onError: (error) => {
      console.error("Error submitting onboarding data:", error);
      toast.error("An error occurred. Please try again.");
    },
  });

 const handleSubmit = () => {
    completeOnboardingMutation.mutate(onboardingData);
  };

What I'm Trying to Achieve

I want to be able to make authenticated API calls to protected routes like /api/onboarding. Currently, these calls return 401 Unauthorized. Even after signing in.

Questions

  1. How should I configure the API client to automatically include authentication headers?
  2. Should I use session tokens, JWT tokens, or another approach?
  3. What's the correct way to handle session management with Better Auth in a React/NestJS setup?
  4. Are there any specific interceptors or middleware I need to implement?

Environment

  • Frontend: React 18 + TypeScript + Vite + TanStack Query
  • Backend: NestJS + Better Auth + MongoDB + Mongoose
  • Auth: Better Auth v1.3.34 with thallesp/nestjs-better-auth 2.1.0

Any guidance on implementing proper session-based authentication for protected routes would be greatly appreciated!

Originally created by @jason-ezenwa on GitHub (Oct 31, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/5705 ## Description I'm working on an educational platform with authentication using Better Auth. User registration and login are working correctly, but I'm having trouble implementing proper session-based authentication for protected API routes. The signup/signin flows work fine, but when I try to access protected endpoints, I'm getting unauthorized responses. I need guidance on how to properly configure the authentication headers and session handling. ## Current Setup ### Backend Configuration **Auth Configuration:** ```typescript import { betterAuth } from 'better-auth'; import { mongodbAdapter } from 'better-auth/adapters/mongodb'; import { MongoClient } from 'mongodb'; const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/myapp-db'; const client = new MongoClient(mongoUri); const db = client.db('myapp-db'); export const auth = betterAuth({ baseURL: process.env.BETTER_AUTH_URL || 'http://localhost:3000', database: mongodbAdapter(db, { client }), emailAndPassword: { enabled: true, }, trustedOrigins: [ 'http://localhost:5173', 'https://myapp.example.com', ], user: { modelName: 'users', additionalFields: { role: { type: 'string', required: true, defaultValue: 'student', input: false, }, }, }, account: { modelName: 'accounts', }, session: { modelName: 'sessions', }, token: { modelName: 'tokens', }, verification: { modelName: 'verifications', }, }); ``` **Module Setup:** ```typescript import { AuthModule } from '@thallesp/nestjs-better-auth'; AuthModule.forRoot({ auth: auth }), ``` **Protected Route Example:** ```typescript import { Controller, Post, Body, UseGuards } from '@nestjs/common'; import { AuthGuard, Session } from '@thallesp/nestjs-better-auth'; import type { UserSession } from '@thallesp/nestjs-better-auth'; @UseGuards(AuthGuard) @Controller('onboarding') export class OnboardingController { @Post() async completeOnboarding( @Session() session: UserSession, @Body() onboardingData: any, ) { return this.onboardingService.completeOnboarding( session.user.id, onboardingData, ); } } ``` ### Frontend Configuration **Auth Client:** ```typescript import { createAuthClient } from "better-auth/react"; export const authClient = createAuthClient({ baseURL: `${import.meta.env.VITE_API_URL || "http://localhost:3000"}/auth`, }); ``` **API Client:** ```typescript import axios, { type AxiosInstance } from "axios"; export const api: AxiosInstance = axios.create({ baseURL: `${import.meta.env.VITE_API_URL || "http://localhost:3000"}`, }); const completeOnboardingMutation = useMutation({ mutationFn: (data: OnboardingData) => api.post("/onboarding", data).then((res) => res.data), onSuccess: () => { navigate("/dashboard"); }, onError: (error) => { console.error("Error submitting onboarding data:", error); toast.error("An error occurred. Please try again."); }, }); const handleSubmit = () => { completeOnboardingMutation.mutate(onboardingData); }; ``` ## What I'm Trying to Achieve I want to be able to make authenticated API calls to protected routes like `/api/onboarding`. Currently, these calls return 401 Unauthorized. Even after signing in. ## Questions 1. How should I configure the API client to automatically include authentication headers? 2. Should I use session tokens, JWT tokens, or another approach? 3. What's the correct way to handle session management with Better Auth in a React/NestJS setup? 4. Are there any specific interceptors or middleware I need to implement? ## Environment - **Frontend:** React 18 + TypeScript + Vite + TanStack Query - **Backend:** NestJS + Better Auth + MongoDB + Mongoose - **Auth:** Better Auth v1.3.34 with thallesp/nestjs-better-auth 2.1.0 Any guidance on implementing proper session-based authentication for protected routes would be greatly appreciated!
GiteaMirror added the locked label 2026-04-17 18:47:13 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Oct 31, 2025):

Below is a concise set of next steps and recommendations:

  1. Configure your API (axios) client so that it automatically sends the session cookie with every request. In an axios setup this means enabling credentials (for example, setting withCredentials: true either globally or on each request). This ensures the browser sends the cookie that Better Auth set during sign-in [1].

  2. Better Auth’s default session-based approach uses HTTP-only cookies rather than explicit tokens in headers. Because you’re using the session method, rely on cookies instead of manually attaching a JWT. If you do need to use tokens (for instance in a stateless API), you’d have to adjust your auth configuration and client accordingly, but for your project the session cookie is the intended method [2].

  3. On the backend (NestJS), continue protecting routes using the provided AuthGuard and the @Session decorator. Verify that the middleware for parsing cookies is properly configured and that your trustedOrigins list includes your client origin. Also double-check any CORS settings to ensure credentials (cookies) are allowed from your frontend’s origin [1], [2].

  4. If you’re using an interceptor on the client side, make sure it doesn’t unintentionally remove or override credentials. For instance, configuring an axios request interceptor can be useful to log or add custom headers—but ensure that withCredentials remains true and that any token override doesn’t conflict with the cookie-based session management [1].

With these steps, your React client will automatically include the session cookie—allowing Better Auth’s backend to properly validate the session and prevent the 401 Unauthorized issues on protected endpoints. If you continue to see issues, double-check the cookie settings (domain, SameSite, secure flag) and that your environment variables (especially trustedOrigins and baseURL) are correctly set.

I hope these pointers help you troubleshoot and correctly implement session-based authentication.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3474162632 --> @better-auth-agent[bot] commented on GitHub (Oct 31, 2025): Below is a concise set of next steps and recommendations: 1. Configure your API (axios) client so that it automatically sends the session cookie with every request. In an axios setup this means enabling credentials (for example, setting withCredentials: true either globally or on each request). This ensures the browser sends the cookie that Better Auth set during sign-in [[1]](https://github.com/better-auth/better-auth/issues/2639). 2. Better Auth’s default session-based approach uses HTTP-only cookies rather than explicit tokens in headers. Because you’re using the session method, rely on cookies instead of manually attaching a JWT. If you do need to use tokens (for instance in a stateless API), you’d have to adjust your auth configuration and client accordingly, but for your project the session cookie is the intended method [[2]](https://github.com/better-auth/better-auth/issues/5541). 3. On the backend (NestJS), continue protecting routes using the provided AuthGuard and the @Session decorator. Verify that the middleware for parsing cookies is properly configured and that your trustedOrigins list includes your client origin. Also double-check any CORS settings to ensure credentials (cookies) are allowed from your frontend’s origin [[1]](https://github.com/better-auth/better-auth/issues/2639), [[2]](https://github.com/better-auth/better-auth/issues/5541). 4. If you’re using an interceptor on the client side, make sure it doesn’t unintentionally remove or override credentials. For instance, configuring an axios request interceptor can be useful to log or add custom headers—but ensure that withCredentials remains true and that any token override doesn’t conflict with the cookie-based session management [[1]](https://github.com/better-auth/better-auth/issues/2639). With these steps, your React client will automatically include the session cookie—allowing Better Auth’s backend to properly validate the session and prevent the 401 Unauthorized issues on protected endpoints. If you continue to see issues, double-check the cookie settings (domain, SameSite, secure flag) and that your environment variables (especially trustedOrigins and baseURL) are correctly set. I hope these pointers help you troubleshoot and correctly implement session-based authentication. <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/better-auth) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/better-auth/better-auth)
Author
Owner

@jason-ezenwa commented on GitHub (Oct 31, 2025):

just needed to add withCredentials! thanks, better auth agent lol

Below is a concise set of next steps and recommendations:

  1. Configure your API (axios) client so that it automatically sends the session cookie with every request. In an axios setup this means enabling credentials (for example, setting withCredentials: true either globally or on each request). This ensures the browser sends the cookie that Better Auth set during sign-in [1].
  2. Better Auth’s default session-based approach uses HTTP-only cookies rather than explicit tokens in headers. Because you’re using the session method, rely on cookies instead of manually attaching a JWT. If you do need to use tokens (for instance in a stateless API), you’d have to adjust your auth configuration and client accordingly, but for your project the session cookie is the intended method [2].
  3. On the backend (NestJS), continue protecting routes using the provided AuthGuard and the @Session decorator. Verify that the middleware for parsing cookies is properly configured and that your trustedOrigins list includes your client origin. Also double-check any CORS settings to ensure credentials (cookies) are allowed from your frontend’s origin [1], [2].
  4. If you’re using an interceptor on the client side, make sure it doesn’t unintentionally remove or override credentials. For instance, configuring an axios request interceptor can be useful to log or add custom headers—but ensure that withCredentials remains true and that any token override doesn’t conflict with the cookie-based session management [1].

With these steps, your React client will automatically include the session cookie—allowing Better Auth’s backend to properly validate the session and prevent the 401 Unauthorized issues on protected endpoints. If you continue to see issues, double-check the cookie settings (domain, SameSite, secure flag) and that your environment variables (especially trustedOrigins and baseURL) are correctly set.

I hope these pointers help you troubleshoot and correctly implement session-based authentication.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3474185927 --> @jason-ezenwa commented on GitHub (Oct 31, 2025): just needed to add withCredentials! thanks, better auth agent lol > Below is a concise set of next steps and recommendations: > > 1. Configure your API (axios) client so that it automatically sends the session cookie with every request. In an axios setup this means enabling credentials (for example, setting withCredentials: true either globally or on each request). This ensures the browser sends the cookie that Better Auth set during sign-in [[1]](https://github.com/better-auth/better-auth/issues/2639). > 2. Better Auth’s default session-based approach uses HTTP-only cookies rather than explicit tokens in headers. Because you’re using the session method, rely on cookies instead of manually attaching a JWT. If you do need to use tokens (for instance in a stateless API), you’d have to adjust your auth configuration and client accordingly, but for your project the session cookie is the intended method [[2]](https://github.com/better-auth/better-auth/issues/5541). > 3. On the backend (NestJS), continue protecting routes using the provided AuthGuard and the @Session decorator. Verify that the middleware for parsing cookies is properly configured and that your trustedOrigins list includes your client origin. Also double-check any CORS settings to ensure credentials (cookies) are allowed from your frontend’s origin [[1]](https://github.com/better-auth/better-auth/issues/2639), [[2]](https://github.com/better-auth/better-auth/issues/5541). > 4. If you’re using an interceptor on the client side, make sure it doesn’t unintentionally remove or override credentials. For instance, configuring an axios request interceptor can be useful to log or add custom headers—but ensure that withCredentials remains true and that any token override doesn’t conflict with the cookie-based session management [[1]](https://github.com/better-auth/better-auth/issues/2639). > > With these steps, your React client will automatically include the session cookie—allowing Better Auth’s backend to properly validate the session and prevent the 401 Unauthorized issues on protected endpoints. If you continue to see issues, double-check the cookie settings (domain, SameSite, secure flag) and that your environment variables (especially trustedOrigins and baseURL) are correctly set. > > I hope these pointers help you troubleshoot and correctly implement session-based authentication. > > [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) > > [![Diagram](https://camo.githubusercontent.com/278c71f8bd0ffa762d381609b9758b6bf4e7793371f510c36591ac7fca3b0f2e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4469616772616d2d3262333133373f7374796c653d666c61742d737175617265)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://camo.githubusercontent.com/8a9575fbb02d0ccd0430ba84c6f263f2bedc76dce345f35a8e42bc3f5d733fe2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6a6f696e2d3538363546323f6c6f676f3d646973636f7264266c6f676f436f6c6f723d7768697465267374796c653d666c61742d737175617265)](https://discord.gg/better-auth) [![Star](https://camo.githubusercontent.com/9b5328a1d305f67c94b8ae6dc4bfb8c58b36148ac58f574cca7272d730f6b7a1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f737461722d3138313731373f6c6f676f3d676974687562266c6f676f436f6c6f723d7768697465267374796c653d666c61742d737175617265)](https://github.com/better-auth/better-auth)
Author
Owner

@better-auth-agent[bot] commented on GitHub (Oct 31, 2025):

Based on your description and the fact that you mentioned “just needed to add withCredentials! thanks, better auth agent lol,” the next steps are:

  1. On the client side (Axios), ensure that every protected API request includes credentials. That means setting up your axios instance with withCredentials set to true either globally or per request. For example:

  axios.create({ baseURL: yourBaseURL, withCredentials: true });

This ensures that the HTTP‑only session cookie is sent automatically with each request [1].

  1. On the backend, make sure your CORS configuration allows credentials (i.e., credentials: true) and your trusted origins list correctly includes your frontend’s origin. Both are necessary so that the browser is allowed to send cookies and the server accepts them [2].

  2. Continue using Better Auth’s cookie-based session management (instead of manually sending tokens) so that your AuthGuard in NestJS can properly verify the session using the cookie. Also double-check that any middleware responsible for parsing cookies is active and that no interceptors are inadvertently stripping credentials from the request [1], [2].

Following these steps should provide the correct session handling for your protected API routes. If you still run into issues, verify your cookie settings (domain, SameSite, secure flag) to confirm that the cookies are being set and returned appropriately.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3474187773 --> @better-auth-agent[bot] commented on GitHub (Oct 31, 2025): Based on your description and the fact that you mentioned “just needed to add withCredentials! thanks, better auth agent lol,” the next steps are: 1. On the client side (Axios), ensure that every protected API request includes credentials. That means setting up your axios instance with withCredentials set to true either globally or per request. For example:   axios.create({ baseURL: yourBaseURL, withCredentials: true }); This ensures that the HTTP‑only session cookie is sent automatically with each request [[1]](https://github.com/better-auth/better-auth/issues/2639). 2. On the backend, make sure your CORS configuration allows credentials (i.e., credentials: true) and your trusted origins list correctly includes your frontend’s origin. Both are necessary so that the browser is allowed to send cookies and the server accepts them [[2]](https://www.better-auth.com/docs/integrations/nestjs). 3. Continue using Better Auth’s cookie-based session management (instead of manually sending tokens) so that your AuthGuard in NestJS can properly verify the session using the cookie. Also double-check that any middleware responsible for parsing cookies is active and that no interceptors are inadvertently stripping credentials from the request [[1]](https://github.com/better-auth/better-auth/issues/2639), [[2]](https://www.better-auth.com/docs/integrations/nestjs). Following these steps should provide the correct session handling for your protected API routes. If you still run into issues, verify your cookie settings (domain, SameSite, secure flag) to confirm that the cookies are being set and returned appropriately. <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/better-auth) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/better-auth/better-auth)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#27655