Custom plugins & Before Hooks (early return) & Redirecting #843

Closed
opened 2026-03-13 08:06:43 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @mishelen on GitHub (Mar 13, 2025).

Hi, I am trying to create a custom plugin for anonymous sessions.

So far I envision it as intercepting requests for /get-session

In which I will check for cookies (authenticated and anonymous) and if there are none, then I want to add an anonymous cookie and create a session in fast storage and return it to the user, and so on:

export const anonymousSessionPlugin = () => {
  return {
    id: "plugin-anonymous-session",
    hooks: {
      before: [
        {
          matcher: (context) => {
            return context.path === "/get-session";
          },
          handler: createAuthMiddleware(async (ctx) => {
            
            if (ctx.getCookie("better-auth")) {
              return { context: ctx };
            }
            
            if (await ctx.getSignedCookie("anon-auth")) {
              return ctx.json({ 
                session: await getAnonSession(ctx.getCookie("anon-auth")), 
                user: null 
              });
            }
            
            const sessionId = randomUUID();
            const session = await createAnonSession(sessionId);
            await ctx.setSignedCookie("anon-auth", sessionId);
            return ctx.json({ session, user: null });
          })
        }
      ]
    }
  };
};

How realistic is this approach, perhaps there are other ideas?
Can we even return early from the handler? It would be handy and similar to express middlewares & fastify plugins experience. I mean just return ctx.json().

Now I'm getting that:

 ⨯ [Error: No response is returned from route handler '....api/auth/[...all]/route.ts'. 
Ensure you return a `Response` or a `NextResponse` in all branches of your handler.]

Well, let's try another idea. Create separate endpoint (route handler) and use redirect from before get-session hook.

export const anonymousSessionPlugin = () => {
  return {
    id: "plugin-anonymous-session",
    endpoints: {
      getAnonymousSession: createAuthEndpoint(
        "/get-anonymous-session",
        { method: "GET" },
        async (ctx) => {
          return ctx.json({ session: null, user: null });
        }
      )
    },
    hooks: {
      before: [
        {
          matcher: (context) => {
            return context.path === "/get-session";
          },
          handler: createAuthMiddleware(async (ctx) => {
            
            if (!ctx.getCookie("better-auth")) {
              throw ctx.redirect("/api/auth/get-anonymous-session");
            }
          })
        }
      ]
    }
  };
};

And again problems, it is not possible because the redirect is not working properly.There is an endless chain of redirects going on.

The whole thing is that when redirecting context.path remains the same, hence the /get-session hook is triggered.

Originally created by @mishelen on GitHub (Mar 13, 2025). Hi, I am trying to create a custom plugin for anonymous sessions. So far I envision it as intercepting requests for `/get-session` In which I will check for cookies (authenticated and anonymous) and if there are none, then I want to add an anonymous cookie and create a session in fast storage and return it to the user, and so on: ```js export const anonymousSessionPlugin = () => { return { id: "plugin-anonymous-session", hooks: { before: [ { matcher: (context) => { return context.path === "/get-session"; }, handler: createAuthMiddleware(async (ctx) => { if (ctx.getCookie("better-auth")) { return { context: ctx }; } if (await ctx.getSignedCookie("anon-auth")) { return ctx.json({ session: await getAnonSession(ctx.getCookie("anon-auth")), user: null }); } const sessionId = randomUUID(); const session = await createAnonSession(sessionId); await ctx.setSignedCookie("anon-auth", sessionId); return ctx.json({ session, user: null }); }) } ] } }; }; ``` How realistic is this approach, perhaps there are other ideas? **Can we even return early from the handler?** It would be handy and similar to express middlewares & fastify plugins experience. I mean just `return ctx.json()`. Now I'm getting that: ``` ⨯ [Error: No response is returned from route handler '....api/auth/[...all]/route.ts'. Ensure you return a `Response` or a `NextResponse` in all branches of your handler.] ``` Well, let's try another idea. Create separate endpoint (route handler) and use `redirect` from before `get-session` hook. ```js export const anonymousSessionPlugin = () => { return { id: "plugin-anonymous-session", endpoints: { getAnonymousSession: createAuthEndpoint( "/get-anonymous-session", { method: "GET" }, async (ctx) => { return ctx.json({ session: null, user: null }); } ) }, hooks: { before: [ { matcher: (context) => { return context.path === "/get-session"; }, handler: createAuthMiddleware(async (ctx) => { if (!ctx.getCookie("better-auth")) { throw ctx.redirect("/api/auth/get-anonymous-session"); } }) } ] } }; }; ``` And again problems, it is not possible because the redirect is not working properly.There is an **endless chain** of redirects going on. The whole thing is that when redirecting `context.path` remains the same, hence the `/get-session` hook is triggered.
Author
Owner

@mishelen commented on GitHub (Mar 14, 2025):

Eventually figured it out, the infinite redirects in the second idea were due to a bug in hooks.before[].matcher

All that remains is to add hooks for sign-up & sign-in in which is possible to delete the cookie.

@mishelen commented on GitHub (Mar 14, 2025): Eventually figured it out, the infinite redirects in the second idea were due to a bug in `hooks.before[].matcher` All that remains is to add hooks for `sign-up` & `sign-in` in which is possible to delete the cookie.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#843