nuxt-community / auth-module

Zero-boilerplate authentication support for Nuxt 2
https://auth.nuxtjs.org
MIT License
1.93k stars 925 forks source link

SSR: Logged-in user redirected to login page when refreshing secure page #258

Closed mllull closed 2 years ago

mllull commented 6 years ago

Version

v4.5.1

Reproduction link

https://codesandbox.io/s/github/nuxt-community/auth-module/tree/master/

Steps to reproduce

Well, this bug is highly related to this GitHub issue #55 .

I'm simply cloning this whole repo to my computer and run a yarn install and yarn dev into a terminal. Next, I'm going to http://localhost:3000 and all works fine, I can go to the secure page and, as expected, it redirects me to Login page. Next, when I'm logged in, I can access the secure page. Ok, now, if I press the F5 button to reload the page, it throws the bug. I'm redirected to the login page, but at the same time (well, some milliseconds after it) it displays my name at the navbar. Looking in the console there is two vue-warnings:

Captura_2018-10-16_09-08-31.png

But wait, if I run the live example on herokuapp (https://nuxt-auth.herokuapp.com/) it works as expected, if i press F5 it keeps me on secure page and no warnings are displayed.

What is expected ?

When pressing F5 key (to reload the page) on secured page, no redirecting to login page.

What is actually happening?

When pressing F5 key (to reload the page) on secured page, it takes me to login page.

Additional comments?

Software I'm using:

P.S.1: I've cleaned the cache and all aplication data in Chrome, because this bug was firstly discovered in a project that I'm developing. P.S.2: No bug was observed in my home laptop. It's very very strange.

This bug report is available on Nuxt community (#c216)
sfgn commented 6 years ago

I have the same issue when running using SSR, but on SPA it does not happen.

mllull commented 6 years ago

Yes, I forget to say it, I'm in SSR mode too.

demircimurat commented 6 years ago

I have the same issue, with page refresh user comes back even though I'm logged out

drewjbartlett commented 6 years ago

Same issue

cliqer commented 6 years ago

me too, just bumped into this. Do you guys happen to use nuxt-i18n? I have set up i18n as a multidomain (domain.com, eu, fr ...) and the redirection works on all other domains but the main one when refreshing the page. Maybe something is still being cached somewhere in the browser but can't figure out what is happening exactly.

sebas7dk commented 5 years ago

Same issue, but it only happens when I dockerize nuxt, on local it works as expected. Whenever you refresh the page on a authenticated page it will redirect you to the login page. It's very hard to reproduce and only happens when you build nuxt.

I run nuxt in ssr mode and the api is another docker container and the calls are done over https. I also use Cloudflare.

cliqer commented 5 years ago

It seems this error has to do with self-signed certificates. It has been solved in the dev branch: "@nuxtjs/auth": "git://github.com/nuxt-community/auth-module.git#dev"

mllull commented 5 years ago

@gianniskarmas Unfortunately your solution doesen't work for me :pensive:

I have to say that in my project I have "the Nuxt part" and "the Express API part", so it's not the same server where I make the auth.

The issue appears until I click the Clear site data in Chrome Dev tools, even I clean Local storage, Session storage and so on, it throws me the error on console, only when I click the Clear site data it doesn't throws it.

sebas7dk commented 5 years ago

Guys, I figured out what is happening on my part, maybe it can help someone else.

Correct me if I'm wrong, the auth module uses axios to fetch the user once logged in. So if you refresh the page, it will try to fetch the user, if that fails you will be redirected to the login page. What happened in my case is that on server side rendering the axios base url is not defined. Although in my nuxt config it's defined and working as expected. I added the API_URL environment variable and now it registers correctly. So test your api responses and your axios configuration.

Cloudflare was giving me Error 1000: DNS points to prohibited IP error so I disabled the proxy and now it's working as expected.

The main problem is that you will be logged out if the fetch user function fails, but there should be some log message displaying what happened. It's really hard to debug because it can depend on so many factors.

ngcammayo commented 5 years ago

Thanks @gianniskarmas. Resolved when actually generating a valid cert not self-singed.

digitalmagnets commented 5 years ago

I have had this problem too on 4.5.3. I'm not using a self signed cert and I have the axios url defined.

A workaround I have done is:

  1. Turn off all auth redirects
  2. Modify my default layout with a v-if, so if the user is not logged in, they will see a login component.

Then after they login, they will see the page on the URL they tried to access, no redirecting necessary.

I'm relieved to have found this workaround, as I couldn't get anything else to work and it seems simple. Although I am getting the hydration error, which I will have to look into but can live with.

allenhark commented 5 years ago

The problem seems to be with cloudflare generated ssl certificates. I fixed by using letsencrypt.

Sample Code

kiwicopple commented 5 years ago

Thanks @sebas7dk - I had forgotten to set this in one of my server instances. Solved by setting the following 2 environment variables:

API_URL=https://example.com
API_URL_BROWSER=https://example.com
stevepop commented 5 years ago

@sebas7dk @kiwicopple I have a similar setup although in my case, I have a separate container running node-express for my API in my local environment. When I reload my page, I can see that the endpoint is being requested and the user being returned but I don't know why the server keeps redirecting me to login. This works when I switch to spa but this application needs to be SSR. See my page and console when I reload the page after logging in. See screenshot below; ssr_console_error

console_error

I am really open to ideas to help resolve this issue. Thanks!

drewjbartlett commented 5 years ago

If it's useful for anyone, I accidentally had my API_URL set to http://api.foo.com instead of https://api.foo.com. Moving it to https was the fix I needed. Simple oversight!

stevepop commented 5 years ago

@drewjbartlett My case has nothing to do with https though. Can someone actually explain what the problem is here? Why should Nuxt server side not have access to the user even when the API responds with a valid token and user data when the page is reloaded?

hasanmumin commented 5 years ago

I have the same issue on localhost. How can I fix ?

samturrell commented 5 years ago

Issue for me too. isLoggedIn isn't returning true on server side, so getting SSR errors when loading pages when logged in.

Weirdly this only happens when you close the browser down fully and then navigate back to a page with an authenticated state.

Additional reloads or navigations don't suffer from the issue.

MathiasCiarlo commented 5 years ago

I just solved this by removing an x-forwarded-for header that was added to the userinfo request (used in oauth2) by my load balancer/reverse proxy. I was on VPN, and it appeared to make my public IP different than what was shown in the x-forwarded-for header. The calls were then rejected by the auth provider (Keycloak). Try it out with a clean instance of axios, if you suspect header issues. (Replace the axios instance with a fresh one in the fetchUser method defined in schemes/oauth2.js

er1x commented 5 years ago

For me, setting the API_URL fixed it. But keep in mind that API_URL may not be the same in server and client sides.

In my case I noticed that on the first request nuxt was throwing me a 302 to /login page. But, on client side, I could see that user request was sent and user came back correctly.

So I set my public host API_URL for the nuxt build command, and API_URL=http://localhost:XXXX for npm start. Hope this helps.

art0s commented 5 years ago

Same issue. When I start nuxt app with auth module in docker (local strategy) - through "yarn run dev" and "yarn run build && yarn run start". On local it works as expected. auth-module v.4.5.3

MathiasCiarlo commented 5 years ago

@art0s do you get an error? And is your identity provider running on localhost in docker as well? I experienced the same, where the the userinfo calls did not hit the identity provider. The problem for me was that the docker network was set up incorrectly.

art0s commented 5 years ago

do you get an error?

No

And is your identity provider running on localhost in docker as well?

Yes, but I changed hostname in hosts file and in baseURL of axios's option Also, I tried proxy option of axios

I experienced the same, where the the userinfo calls did not hit the identity provider.

When nuxt in the docker "fetchUserOnce" function called on refresh on secure page, but on browser (that is wrong). In local - it called from server and works as expected

The problem for me was that the docker network was set up incorrectly.

May be you're right, but I removed "x-" headers in nginx as you advised - got same problem.

I solved this problem by disabling local strategy in a auth-module, I made this strategy myself.

art0s commented 5 years ago

The problem for me was that the docker network was set up incorrectly.

you was right, resolved problem, issue was in my local DNS server after fixed it - module is working as expected.

now all strategies working fine.

russellsean commented 5 years ago

I'm still being redirected to the login route on page load even though state says I'm logged in.

Here's the kicker: it only happens on https. The first response is a 302 redirect.

tenluap commented 5 years ago

Hi Guy, Here is a solution for this issue.

Goto nuxt.config.js > auth> strategies>local>endpoints

then set the user object to user: { url: '/api/customers/me', method: "GET", propertyName: false } this works on Universal mode.

to handle redirect Goto nuxt.config.js > auth> redirect

then set all the redirects redirect: { login: '/login', logout: '/login', callback: '/login', home: '/home' },

also add this to make authentication work router: { middleware: ['auth'], }

at the end you should have something like this in your nuxt.config.js

export default {
   ....
  auth: {
    redirect: {
      login: '/login',
      logout: '/login',
      callback: '/login',
      home: '/home'
    },
    strategies: {
      local: {
        endpoints: {
          login: { url: '/api/customers/login', method: "POST", propertyName: 'id' },
          logout: { url: '/api/customers/logout', method: "POST" },
          reset: { url: '/api/customers/reset', method: "POST" },
          user: { url: '/api/customers/me', method: "GET", propertyName: false }
        },
        tokenType: false
      }
    },
   ...
  router: {
    middleware: ['auth']
  }
  }
Lucky3337 commented 4 years ago

Hi guys. Have everyone been fixed this issue?

localhost5001 commented 4 years ago

Facing with this issue, it's really hard to understand. Any updates?

sts-ryan-holton commented 4 years ago

Same issue here!

stevenraines commented 4 years ago

I solved this by making sure the BASE_URL is included in the paths to my API endpoints for authentication.

login: { url: ${process.env.BASE_URL}/api/auth/local, method: 'post', propertyName: 'token' }, logout: { url: ${process.env.BASE_URL}/api/auth/logout, method: 'post' }, user: { url: ${process.env.BASE_URL}/api/users/me, method: 'get', propertyName: '' }

Without the base URL in place, the server side can't call the URL. In my case, I set-up a Proxy for /api/ to call to an API_URL set-up for my backend.

hhanh00 commented 4 years ago

In case someone else still has this issue, I spent some time debugging this. Turns out it is a combination of several things. When using SSR, the server receives the request from the browser with the credentials (as cookies I believe) and renders the page. If the page requires authentication, @nuxt/auth will fetch the user and redirect to /login if it authentication fails.

To do this, it uses ctx.$axios which is injected by the axios plugin

The baseURL is set as such:

  const baseURL = process.browser
      ? '<%= options.browserBaseURL || '' %>'
      : (process.env._AXIOS_BASE_URL_ || '<%= options.baseURL || '' %>')

From the browser, you have no issue. But from the server, it will use _AXIOS_BASE_URL_ which is either computed from HOST, PORT (and some variants of them) or set by API_URL. The code is in module.js

By default, this will resolve to http://localhost:3000. So it could work if you are running the server at this endpoint.

In my case, I unfortunately had HOST defined as my external FQDN and the request would fail since port 3000 is not exposed to the internet.

TLDR

OussamaFadlaoui commented 4 years ago

In case someone else still has this issue, I spent some time debugging this. Turns out it is a combination of several things. When using SSR, the server receives the request from the browser with the credentials (as cookies I believe) and renders the page. If the page requires authentication, @nuxt/auth will fetch the user and redirect to /login if it authentication fails.

To do this, it uses ctx.$axios which is injected by the axios plugin

The baseURL is set as such:

  const baseURL = process.browser
      ? '<%= options.browserBaseURL || '' %>'
      : (process.env._AXIOS_BASE_URL_ || '<%= options.baseURL || '' %>')

From the browser, you have no issue. But from the server, it will use _AXIOS_BASE_URL_ which is either computed from HOST, PORT (and some variants of them) or set by API_URL. The code is in module.js

By default, this will resolve to http://localhost:3000. So it could work if you are running the server at this endpoint.

In my case, I unfortunately had HOST defined as my external FQDN and the request would fail since port 3000 is not exposed to the internet.

TLDR

  • Check that you haven't touched HOST, PORT, or added config options to axios that would make the request fail from the server,
  • If everything seems ok, check the debug log baseURL from nuxt:axios

Hi there. I'm facing the same issues and I've been looking around everywhere for this baseURL setting. Aside from my nuxt.config.js file, I can't seem to find this property.

Could you please tell me where you found the setting?

hhanh00 commented 4 years ago

https://axios.nuxtjs.org/options.html#baseurl

localhost5001 commented 4 years ago

The problem could appear if you define API_URL in .env file.

vivekkairi commented 4 years ago

Workaround:

So I had base url set to '/api' and all secured pages were getting redirected through 302.

Changed baseUrl to complete site url with https and it worked. axios: { baseURL: 'https://mdsaban/api' }

debagger commented 4 years ago

Hello! I also ran into a similar issue. I found that if the propertyName property is not specified in the configuration for the "user" endpoint, the library equates it to the propertyName: "user" from the default settings. If server returns user as root object then put any false value to user endpoint propertyName:

          user: {
            url: '/api/users/me',
            method: 'get',
            propertyName: null //IMPORTANT
          }

This fix bug for me.

Here is screenshot from debugging when no any user.propertyName setted:

Аннотация 2020-08-03 134634

honarmandpooria commented 4 years ago

Issue for me too. isLoggedIn isn't returning true on server side, so getting SSR errors when loading pages when logged in.

Weirdly this only happens when you close the browser down fully and then navigate back to a page with an authenticated state.

Additional reloads or navigations don't suffer from the issue.

did you solve it?

oluomotoso commented 4 years ago

If you are using Laravel passport, just add the nuxt dashboard domain accessing the laravel api to your routes/api.php .

I wrote about it here

evd3v commented 3 years ago

Had the same issue, in my case the problem was in the server network settings.

I have the API, URL with domain name https://api.com (for example). But the server was in the same local network, where the nuxt app was. And when I'd tried to make request as curl -X GET https://api.com - it throw me the error curl: (7) Failed to connect to https://api.com : Connection refused, but when I sent the same request from my local machine, or from another server - it was work well. And when requests were sent by SSR, it throw the same error, I think. So, in this moment authentification fails.

After, we fixed the local network settings and all works as expected. May be it helps somebody.

bmulholland commented 3 years ago

Looks like the issue here is that, when using SSR and the fetch user request on page hydration fails for any reason, the user is redirected to login page. Is that correct? Has anyone encountered this issue in other scenarios?

If so, then the root cause is likely some combination of other things, hence the varying solutions posted here to unrelated issues. Obviously server network configuration is out of scope for the auth module 😄 . What we should do, however, is provide some clarity about what the root cause is to help you move on to the real culprit in your debugging.

I don't use SSR myself and am unfamiliar with debugging approaches. What's the standard way of debugging, logging, and/or raising errors during SSR hydration?

kgnfth commented 3 years ago

For me the issue using docker, i had a typo in my env API_URL

silencechow commented 3 years ago

I cloned the middleware auth from runtime.js and used it as a custom-auth middleware. And I got the error Cannot set property 'Access-Control-Allow-Origin' of undefined in SSR mode. Then the application will be redirected to login page.

@nuxt/server: 2.15.1 @nuxtjs/auth-next: 5.0.0-1613647907.37b1156 (Latest Version) @nuxtjs/axios: 5.13.1

kamilcglr commented 3 years ago

Hello I have a similar problem I do not know if it is related.

In development everything works perfectly but on the production server, when I refresh the page while the user is authenticated I have a timeout of 20 seconds before being redirected to /login.

I am in SSR with a nginx reverse proxy. Can this be the cause?

kamilcglr commented 3 years ago

Hello I have a similar problem I do not know if it is related.

In development everything works perfectly but on the production server, when I refresh the page while the user is authenticated I have a timeout of 20 seconds before being redirected to /login.

I am in SSR with a nginx reverse proxy. Can this be the cause?

I finally solved my problem it was related to the proxy.

axios: {
    proxy: true,
    credentials: true,
  },

  proxy: {
    '/api/': 'http://localhost:3000',
  },
ajingopi-bridge commented 3 years ago

There could be many reasons, but for me it's different.

In my nuxt-config.js

ssr: true,
target: 'server',
publicRuntimeConfig: {
    axios: {
      baseURL: process.env.BASE_URL,
    },
}

and I was using below command in production yarn generate && yarn start

I changed it to yarn build && yarn start

Now everything works perfectly. When using yarn generate, it is supposed to use for static rendering only and because of that request & response headers or some nuxt contexts are not available on server side. That is the reson why server is unable to authenticate the user.

bmulholland commented 2 years ago

I've collected the debugging steps into simplified items to check in https://github.com/nuxt-community/auth-module/issues/1197

Please let me know if you discover something else to check so I can add it to that list.

As none of these are bugs with the auth module itself, I will close this issue out.

nomadinteractif commented 2 years ago

I had the redirect to login page after refresh problem after deploying my project to production. In development everything was working fine.

I noticed that serving up the project directly in production through node works fine but as soon as I was relying on Passenger (cPanel) to run the app, the problem occurred. I have changed Passenger in favor of PM2 and the problem stopped.

"@nuxtjs/auth-next": "5.0.0-1643791578.532b3d6",
"@nuxtjs/axios": "5.13.6",
    axios: {
        proxy: true,
        debug: process.env.NODE_ENV && process.env.NODE_ENV === 'development'
    },
    proxy: {
        '/api/': {
            target: 'https://api.mydomain.com/',
            pathRewrite: { '^/api/': '' }
        }
    },
CMehlstaeubler commented 2 years ago

Hi all, just throwing my 2 cents in here, hopefully it helps someone.

I am not actually using nuxt auth, but nonetheless have auth in my App (using Firebase atm.) My problem was that I had a middleware that was acting as a guard for the route, checking if the user was logged in. The key point is that usually middleware is run on the client, except for an initial refresh of the page, where it is also run on the server. From the docs:

In universal mode, middlewares will be called once on server-side (on the first request to the Nuxt app, e.g. when directly accessing the app or refreshing the page) and on the client-side when navigating to further routes. With ssr: false, middlewares will be called on the client-side in both situations.

In my middleware I was checked the state of logged in using the localStorage, which of course isn't filled on the server during initial load, which would then respond with a redirect to the login. Adding the lines

if (!process.client) { return }

solved my problem.

Hopes this helps somebody!

aymericingargiola commented 1 year ago

@CMehlstaeubler Oh my god, thanks a lot, if spended so many hours to find a solution other that ssr: false

For more information, i was not using localStorage but Cookies (JWT Refresh Token httpOnly) and obviously the nuxt server that do the request to my main server has no cookies... so i was always redirected to login page after page refresh on JWT refresh token cookie verification instead of instant login.

This solution is perfect, run only on client side

BenJackGill commented 5 months ago

@CMehlstaeubler @aymericingargiola I am having the same problem right now with Firebase Auth and Nuxt VueFire.

When looking into the Nuxt 3 middleware docs it has some solutions for excluding the middleware on the server.

But none of those work well.

Would love some help if you have any updates for Nuxt 3 :)

/middleware/auth.ts

export default defineNuxtRouteMiddleware(async (to, from) => {
  // skip middleware on server
  // if (import.meta.server) {
  //   return;
  // }

  // skip middleware on initial client load
  // const nuxtApp = useNuxtApp();
  // if (
  //   import.meta.client &&
  //   nuxtApp.isHydrating &&
  //   nuxtApp.payload.serverRendered
  // ) {
  //   return;
  // }

  // Get the current user
  const user = await getCurrentUser();

  // Redirect all logged out users login page
  if (!user) {
    return navigateTo({
      path: "/login",
    });
  }
});