How to integrate better-auth library with Nuxt 4
I have configured better-auth on my Hono server and am now trying to set up authentication on my frontend that is on a separate port than the server. I currently have the auth-client set up as a plugin:
And I can succesfully use it in my login page.
Alongisde the auth-client I also set up a middleware to protect the users from accessing /dashboard routes when they are not signed in. The middleware currently looks like this:
No in my login page when the customer submits the login form then I send out
and navigate the user to /dashboard on success
The problem I am running into is that when the user succesfully submit the form I am redirected back to /auth/login for some reason. The user never reaches /dashboard
15 Replies
Hi @JJ. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
Based on your description and the provided code, the issue likely stems from how your middleware checks the session and handles navigation. In Nuxt, middleware runs both on the server and client, and improper handling of asynchronous session checks or navigation can cause unexpected redirects, such as being sent back to
Your middleware uses
Your middleware only checks for
Middleware runs on both server and client. If the session cookie is set on the client after login, but the middleware runs on the server before the cookie is available, the session will appear missing. Recommendations: - Check for session on all dashboard routes:
Use
If your session is set via a cookie, ensure the cookie is available before the middleware runs. Sometimes, a page reload after login is necessary to ensure the session is available on both server and client. - Return nothing if authenticated:
Only return a redirect if the user is not authenticated. If authenticated, simply return nothing to allow navigation to proceed. Example middleware adjustment: Additional tips: - If you still experience issues, try forcing a page reload after login to ensure the session cookie is available to the server-rendered middleware. - Make sure your login logic waits for the session to be established before navigating to
/auth/login even after a successful login.
Key points to consider:
1. Session Fetching in Middleware:Your middleware uses
await $authClient.useSession(useFetch). If the session is not immediately available (e.g., due to async cookie propagation or fetch timing), the middleware may not detect the session in time and redirect to /auth/login even though the user just logged in.
2. Redirection Logic:Your middleware only checks for
/dashboard, but if the user is navigating to a nested dashboard route (e.g., /dashboard/settings), the check will not trigger, and the user might get stuck in a redirect loop or be denied access incorrectly.
3. Middleware Execution Timing:Middleware runs on both server and client. If the session cookie is set on the client after login, but the middleware runs on the server before the cookie is available, the session will appear missing. Recommendations: - Check for session on all dashboard routes:
Use
to.path.startsWith('/dashboard') to protect all dashboard-related routes.
- Avoid async issues:If your session is set via a cookie, ensure the cookie is available before the middleware runs. Sometimes, a page reload after login is necessary to ensure the session is available on both server and client. - Return nothing if authenticated:
Only return a redirect if the user is not authenticated. If authenticated, simply return nothing to allow navigation to proceed. Example middleware adjustment: Additional tips: - If you still experience issues, try forcing a page reload after login to ensure the session cookie is available to the server-rendered middleware. - Make sure your login logic waits for the session to be established before navigating to
/dashboard.
References:
- Protect App Routes (Nuxt Auth Utils)
- When Middleware Runs
- Middleware Usage and Return Values
If you continue to have issues, please check if the session is correctly set and available in the middleware context after login, and consider adding debug logs to trace the session value during navigation.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@448498136198021134> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai The cookie seems to be set correctly but I think it is not yet available on the server side. How can I assure that the middleware checks the cookies at the correct time when they are actually available?
Let me check the knowledge base for you again. One moment! :books:
----------------------
You're correct that, in Nuxt, cookies set on the client (e.g., after a login request) are not immediately available to server-side middleware until the next full HTTP request. This is because server-side middleware only has access to cookies sent with the incoming request headers, and cookies set via JavaScript or in a response are not included until the browser makes a new request with those cookies attached.
Key points from the knowledge sources:
- When you set a cookie (e.g., after login), it is only sent to the server on subsequent requests, not immediately available in the current server-side context. This is a standard browser behavior and not specific to Nuxt.
- The Nuxt documentation and data fetching guide both confirm that cookies are only available to the server after a new request is made with those cookies in the headers. - This is also discussed in a Nuxt GitHub issue and PR, where it is noted that
After a successful login and cookie set, trigger a
You can skip the server-side middleware check for the initial navigation after login (e.g., by checking
You cannot make a cookie available to server-side middleware until the next request. The standard solution is to trigger a full page reload after login, so the cookie is sent to the server and available for authentication checks in middleware. If you need to avoid a full reload, you must handle the first navigation after login on the client only, and rely on server-side checks for all subsequent navigations. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
- The Nuxt documentation and data fetching guide both confirm that cookies are only available to the server after a new request is made with those cookies in the headers. - This is also discussed in a Nuxt GitHub issue and PR, where it is noted that
useCookie gets its value from the request headers, which are only updated on the next request.
What can you do?
- Force a full page reload after login:After a successful login and cookie set, trigger a
window.location.href = '/dashboard' instead of a Nuxt navigation. This ensures a new HTTP request is made, and the cookie is sent to the server, making it available to server-side middleware.
- Alternatively, handle the first redirect on the client:You can skip the server-side middleware check for the initial navigation after login (e.g., by checking
import.meta.client in your middleware and returning early), then rely on the middleware for subsequent navigations.
Example from the docs:
When we callAnd from a related GitHub PR:$fetchin the browser, user headers likecookiewill be directly sent to the API.
However, during Server-Side Rendering, due to security risks such as SSRF or Authentication Misuse, the$fetchwouldn't include the user's browser cookies, nor pass on cookies from the fetch response.
...
If you need to forward headers and cookies on the server, you must manually pass them.
Docs: Passing Headers and Cookies
becauseSummary:useCookieget value fromevent.node.req.headers.cookie, this value not set until next request
GitHub PR #21940
You cannot make a cookie available to server-side middleware until the next request. The standard solution is to trigger a full page reload after login, so the cookie is sent to the server and available for authentication checks in middleware. If you need to avoid a full reload, you must handle the first navigation after login on the client only, and rely on server-side checks for all subsequent navigations. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
<@448498136198021134> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai is The correct way to fetch a session in a middleware
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the provided knowledge sources, there is no explicit documentation or example for using
to fetch a session in Nuxt middleware. The official Nuxt authentication recipes and middleware examples use composables like
to fetch a session in Nuxt middleware. The official Nuxt authentication recipes and middleware examples use composables like
useUserSession() from nuxt-auth-utils to access session or authentication state in middleware, but do not show usage of a custom $authClient or a .useSession method in this context Protect App Routes.
Therefore, the knowledge sources do not contain enough information to confirm whether this is the correct or recommended way to fetch a session in middleware. If $authClient.useSession is a method provided by the better-auth library and it works as expected in your setup, it may be valid, but this approach is not covered in the official Nuxt documentation or examples provided above.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@448498136198021134> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai When calling my betterauth client from my login page the signin function correctly returns user data and I should be directed to /dashboard but the middleware redirects me abck to login for some reason
Let me check the knowledge base for you again. One moment! :books:
----------------------
Your issue—being redirected back to
- A common solution is to force a full page reload after login so that the cookie is sent to the server and the session is available to middleware.
- Your middleware logic is otherwise correct in checking the session and redirecting if not authenticated, but the timing of when the cookie is available is the problem Protect App Routes. What you can do: - After a successful login, instead of using Nuxt's
Your middleware is running before the session cookie is available to the server. To fix this, trigger a full page reload after login so the cookie is sent to the server and the session is recognized by your middleware. This is a standard approach for cookie-based authentication in Nuxt and is supported by the official documentation and community discussions Protect App Routes. If you need more advanced handling (such as SPA-only navigation), you would need to ensure the session is available on the client and possibly skip server-side checks for the first navigation after login, but this is not covered in the official Nuxt documentation. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
/auth/login after a successful login—is a common one when dealing with authentication in Nuxt apps where the session is stored in a cookie. The root cause is that, after logging in, the session cookie is not immediately available to server-side middleware until the next full HTTP request. This means that when you navigate to /dashboard right after login (using client-side navigation), the server-side middleware does not see the new cookie and thinks you are not authenticated, so it redirects you back to the login page.
Key points from the knowledge sources:
- Cookies set on the client are only available to the server on the next request. This is a standard browser behavior and is discussed in the Nuxt docs and related issues. After login, a client-side navigation does not trigger a new HTTP request, so the server does not see the updated cookie yet.- A common solution is to force a full page reload after login so that the cookie is sent to the server and the session is available to middleware.
- Your middleware logic is otherwise correct in checking the session and redirecting if not authenticated, but the timing of when the cookie is available is the problem Protect App Routes. What you can do: - After a successful login, instead of using Nuxt's
navigateTo, use a full page reload:
This will ensure the browser sends the new cookie to the server, and your middleware will see the authenticated session.
- Alternatively, you can skip the server-side middleware check for the first navigation after login (as you are already attempting with your import.meta.server && from.path.startsWith("/auth") check), but this is less robust than a full reload.
Summary:Your middleware is running before the session cookie is available to the server. To fix this, trigger a full page reload after login so the cookie is sent to the server and the session is recognized by your middleware. This is a standard approach for cookie-based authentication in Nuxt and is supported by the official documentation and community discussions Protect App Routes. If you need more advanced handling (such as SPA-only navigation), you would need to ensure the session is available on the client and possibly skip server-side checks for the first navigation after login, but this is not covered in the official Nuxt documentation. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
<@448498136198021134> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
This is still unsolved, as the useSession(useFetch) method seems to return null
@JJ There is a regression right now with better-auth, 1.3.9 is the last version working
Track the issue here
https://github.com/better-auth/better-auth/issues/4722
GitHub
Nuxt SSR: useFetch integration causes session to return undefined a...
Is this suited for github? Yes, this is suited for github To Reproduce 1、Use Nuxt SSR with better-auth 2、Use const { data: session } = await authClient.useSession(useFetch) 3、Login with GitHub OAut...
Thank you so much for referring this to me @Mateleo
I ended up building a nuxt composable that can fetch and store session data and I call it through a nuxt plugin and also inside my middleware which protects certain routes. Took some inspiration from this repo https://github.com/atinux/nuxthub-better-auth/blob/main/app/composables/auth.ts
But it uses
getSession() instead of useSession()GitHub
nuxthub-better-auth/app/composables/auth.ts at main · atinux/nuxth...
A demo of using Better Auth with Nuxt & NuxtHub (Cloudflare D1 & KV). - atinux/nuxthub-better-auth