next-forge icon indicating copy to clipboard operation
next-forge copied to clipboard

BetterAuth Middleware and Session errors

Open Ale1x opened this issue 11 months ago • 18 comments

Describe the bug I followed the guide in the next-forge docs then i'm getting the following errors

next-forge version 3.0.9 (latest)

To Reproduce Steps to reproduce the behavior:

  1. Follow guide on how to switch from clerk to betterauth

Expected behavior Error not happening

Screenshots {A662EF0F-4529-43D4-98B3-0245D0419ED0} {6BCE23DF-B6D6-4F2D-8F6E-950DBA002BAF}

Desktop (please complete the following information):

  • OS: Windows 11 PRO 24H2
  • Browser: brave 1.73.104

Ale1x avatar Jan 03 '25 13:01 Ale1x

@Ale1x Possibly resolved in the fix for #386. Would you be able to verify for me by checking out the latest migration docs?

haydenbleasel avatar Jan 04 '25 19:01 haydenbleasel

I'm seeing a number of other errors as well. This is with the latest from the docs

  ⨯ [Error: The Middleware "/middleware" must export a `middleware` or a `default` function]
│ TypeError: Cannot read properties of undefined (reading 'origin')
│     at authMiddleware (packages/auth/middleware.ts:9:63)
│     at <unknown> (apps/web/middleware.ts:22:30)
│    7 |
│    8 | export const authMiddleware = async (request: NextRequest) => {
│ >  9 |   const url = new URL('/api/auth/get-session', request.nextUrl.origin);
│      |                                                               ^
│   10 |   const response = await fetch(url, {
│   11 |     headers: {
│   12 |       cookie: request.headers.get('cookie') || '',
│  ⨯ unhandledRejection: TypeError: Cannot read properties of undefined (reading 'origin')
│     at authMiddleware (packages/auth/middleware.ts:9:63)
│     at <unknown> (apps/web/middleware.ts:22:30)
│    7 |
│    8 | export const authMiddleware = async (request: NextRequest) => {
│ >  9 |   const url = new URL('/api/auth/get-session', request.nextUrl.origin);
│      |                                                               ^
│   10 |   const response = await fetch(url, {
│   11 |     headers: {
│   12 |       cookie: request.headers.get('cookie') || '',
│  ⨯ unhandledRejection:  TypeError: Cannot read properties of undefined (reading 'origin')
│     at authMiddleware (packages/auth/middleware.ts:9:63)
│     at <unknown> (apps/web/middleware.ts:22:30)
│    7 |
│    8 | export const authMiddleware = async (request: NextRequest) => {
│ >  9 |   const url = new URL('/api/auth/get-session', request.nextUrl.origin);
│      |                                                               ^
│   10 |   const response = await fetch(url, {
│   11 |     headers: {
│   12 |       cookie: request.headers.get('cookie') || '',

mikestecker avatar Jan 07 '25 02:01 mikestecker

Screenshot 2025-01-06 at 6 50 45 PM

mikestecker avatar Jan 07 '25 02:01 mikestecker

Check out the Better Auth docs @ https://www.better-auth.com/docs/integrations/next#middleware

Lukem121 avatar Jan 15 '25 16:01 Lukem121

I believe this issue was fixed in https://github.com/haydenbleasel/next-forge/releases/tag/v3.2.26 for the app directory @haydenbleasel , alternatively, we might want to set the type in the auth package but not sure

@mikestecker @Ale1x just import the type and export the function as a NextMiddleware as shown below

import { NextMiddleware } from 'next/server';

export default authMiddleware(() => securityHeaders()) as unknown as NextMiddleware;

barsketis avatar Feb 18 '25 19:02 barsketis

@barsketis @haydenbleasel I'm still seeing an issue. I have even attempted to start from scratch with the latest build, followed the Better Auth migration steps and now I'm seeing the following error:

Image

mikestecker avatar Feb 20 '25 00:02 mikestecker

Do we have an update on this as I am still having this exact issue when trying to migrate to BetterAuth, it looks like a fantastic auth package but I just can't get it to work

sneddonisaac avatar Mar 02 '25 16:03 sneddonisaac

Same here...

RicSala avatar Mar 05 '25 16:03 RicSala

@RicSala & @haydenbleasel So I have managed to get it to work in my next forge application but it isn't pretty and much more of a machete solution than that of a scalpel. I will post how I did this a bit later on as currently busy :)

sneddonisaac avatar Mar 06 '25 11:03 sneddonisaac

@RicSala & @haydenbleasel So I have managed to get it to work in my next forge application but it isn't pretty and much more of a machete solution than that of a scalpel. I will post how I did this a bit later on as currently busy :)

please post :)

dmytrotree avatar Apr 03 '25 21:04 dmytrotree

@RicSala & @haydenbleasel So I have managed to get it to work in my next forge application but it isn't pretty and much more of a machete solution than that of a scalpel. I will post how I did this a bit later on as currently busy :)

Any updates on this

Charuru avatar May 23 '25 13:05 Charuru

Something like this should work (it works for me).

auth/middleware.ts:

import { getSessionCookie } from 'better-auth/cookies';
import { type NextRequest, NextResponse } from 'next/server';
export function authMiddleware(request: NextRequest) {
  const sessionCookie = getSessionCookie(request);
  const { pathname } = request.nextUrl;

  if (
    sessionCookie ||
    pathname.startsWith('/login') ||
    pathname.startsWith('/signup')
  ) {
    return NextResponse.next();
  }

  if (!sessionCookie) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  return NextResponse.next();
}

app/middleware.ts:

import { authMiddleware } from '@repo/auth/middleware';
import {} from '@repo/security/middleware';
import type { NextRequest } from 'next/server';

export default async function middleware(request: NextRequest) {
  // just remove security header middleware for now
  const authResponse = await authMiddleware(request);

  return authResponse;
}

export const config = {
  matcher: [
    // Skip Next.js internals and all static files, unless found in search params
    '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
    // Always run for API routes
    '/(api|trpc)(.*)',
  ],
};

Its not perfect, but this should get you going past the error.

claytonrothschild avatar May 26 '25 21:05 claytonrothschild

Tried the documented migration as well as the one on better-auth website—ran into similar errors.

One thing that help was to uncomment the server-only on the database (i had forgotten to do it). But yeah, seems like something is not quite right with the current docs.

Would be nice for the base version of next-forge to use better-auth and then have a migration to clerk—as this path might be easier than the otherway around.

jpvalery avatar Jun 03 '25 21:06 jpvalery

Same problem in 5.0.2

ph1losof avatar Jun 07 '25 17:06 ph1losof

for anybody interested in the solution, I have managed to get it to work using following packages/auth/middleware.ts:

import { getSessionCookie } from "better-auth/cookies";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";

export function authMiddleware(
  middlewareFn?: (
    _auth: { req: NextRequest; authorized: boolean },
    request: NextRequest,
  ) => Promise<Response> | Response,
) {
  return async function middleware(request: NextRequest) {
    const sessionCookie = getSessionCookie(request);
    const authorized = Boolean(sessionCookie);

    if (middlewareFn) {
      const response = await middlewareFn(
        { req: request, authorized },
        request,
      );

      if (
        response &&
        (!response.headers.get("x-middleware-next") ||
          response.headers.get("Location"))
      ) {
        return response;
      }
    }

    if (!sessionCookie) {
      return NextResponse.redirect(new URL("/sign-in", request.url));
    }

    return NextResponse.next();
  };
}

All other middlewares seem to work as expected, you don't have to change anything else

ph1losof avatar Jun 08 '25 14:06 ph1losof

Tried the documented migration as well as the one on better-auth website—ran into similar errors.

One thing that help was to uncomment the server-only on the database (i had forgotten to do it). But yeah, seems like something is not quite right with the current docs.

Would be nice for the base version of next-forge to use better-auth and then have a migration to clerk—as this path might be easier than the otherway around.

I agree that it should become the default, clerk is a third-party SaaS, such provider shouldn't be a part of open-source base package. Same thing applies for stripe integration.

Since it is too drastic of a change as of now, I think that there should be at least a CLI that does all migrations by itself at the stage of init

ph1losof avatar Jun 08 '25 14:06 ph1losof

@t3ntxcl3s thanks for sharing your solution! (I just finished recreating my /app from scratch from the better-auth nextjs demo 😂 alas, I'll likely stick to that version now).

Are there any other changes you made with your solution? Is your provided code based on the next-forge docs?

jpvalery avatar Jun 08 '25 15:06 jpvalery

@t3ntxcl3s thanks for sharing your solution! (I just finished recreating my /app from scratch from the better-auth nextjs demo 😂 alas, I'll likely stick to that version now).

Are there any other changes you made with your solution? Is your provided code based on the next-forge docs?

The provided code is not based on the next-forge docs, it was inspired from clerk middleware implementation. Basically, all it does - allows to receive and run middlewares, before running better-auth checks for cookies. The behavior is supposed to stay the same and support all current middlewares - packages/internationalization/middleware.ts and packages/security/middleware.ts

There are no other changes required, only changing packages/auth/middleware.ts to the one I sent, it should fix the issue.

ph1losof avatar Jun 08 '25 15:06 ph1losof