Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

accessing useCookie on server immediately after setting it doesn't return cookie #22631

Open
sync42johnny opened this issue Aug 14, 2023 · 8 comments · May be fixed by #21940
Open

accessing useCookie on server immediately after setting it doesn't return cookie #22631

sync42johnny opened this issue Aug 14, 2023 · 8 comments · May be fixed by #21940

Comments

@sync42johnny
Copy link

sync42johnny commented Aug 14, 2023

Environment

Nuxi 3.6.5


  • Operating System: Darwin
  • Node Version: v16.15.1
  • Nuxt Version: 3.6.5
  • Nitro Version: 2.5.2
  • Package Manager: [email protected]
  • Builder: vite
  • User Config: devtools
  • Runtime Modules: -
  • Build Modules: -

Reproduction

https://github.com/sync42johnny/nuxt-app

Describe the bug

Description:

An issue has been identified with the authentication logic in the middleware of a Nuxt application. The application attempts to authenticate a user by checking for an authToken cookie. However, due to the authToken cookie not being set on the server-side before navigateTo, the middleware encounters an infinite redirection loop.

Details:

Affected Files:

  • index.vue
  • main.vue
  • app.global.ts
  • auth.ts
  • confirm.ts

Workflow:

  1. On accessing the index page (index.vue), the confirm middleware is invoked. This middleware tries to set the authToken cookie on the server-side.
  2. The middleware then redirects to /main.
  3. The /main page is protected by the auth middleware, which checks for the presence of the authToken cookie.
  4. Due to the cookie not being recognized (or initialized correctly on the server), the auth middleware redirects the user back to /, leading to a continuous loop of redirections.

Additional context

The issue might be related to the incorrect functioning of the useCookie function when used within middleware before navigateTo.

Logs

authToken.value in app.global undefined                                                                                                       2:10:58 PM
in confirm                                                                                                                                    2:10:58 PM
authToken.value in app.global undefined                                                                                                       2:10:58 PM
authToken in auth undefined
@sync42johnny sync42johnny changed the title Infinite Redirection Loop in Nuxt Authentication Middleware The incorrect functioning of the useCookie function when used within middleware Aug 14, 2023
@sync42johnny sync42johnny changed the title The incorrect functioning of the useCookie function when used within middleware the useCookie is not set in route middleware Aug 14, 2023
@sync42johnny sync42johnny changed the title the useCookie is not set in route middleware useCookie is not set in route middleware before navigateTo Aug 14, 2023
@danielroe
Copy link
Member

The issue here is that when setting a cookie it is set in the response headers. But when reading a cookie it is looked for in the request headers.

When you redirect to /main, the middleware for main is immediately called and the cookie hasn't yet been set, because it's still in the outgoing response, not the incoming.

If your intent is to check for the cookie immediately after it is initially set (that is, in the same request) then you probably also need to set it in the event.context, for example:

if (process.server) {
  // you can access arbitrary values on the event, like this
  useRequestEvent().context.token
}

There is a PR to do this automatically: #21940.

@danielroe danielroe linked a pull request Aug 14, 2023 that will close this issue
8 tasks
@danielroe danielroe changed the title useCookie is not set in route middleware before navigateTo accessing useCookie on server immediately after setting it doesn't return cookie Aug 14, 2023
@saifobeidat
Copy link

did you find a workaround? im having a similar issue where changing useCookie value is not possible on server (inside a plugin)

@saifobeidat
Copy link

here is my case and how i fixed it..

i have 2 plugins:

The first plugin: startup.ts
it reads if the url has a token in the url, if yes, it sets it in a cookie and immediately calls an api (fetch user info) -- this is on server

something like this:

// startup.ts
  if (route.query.access_token) {
   useCookie<any>("access-token").value="the token"
  }
  
if( useCookie<any>("access-token").value) {
 await fetchUser(); // this gets executed (which means the token is stored correctly in the cookie)
}

the second plugin: api.ts
has some stuff for managing api calls like the above, and interceptors, and getting headers as well..

something like this:

// api.ts
  const getHeaders = function (sendToken: boolean, extraHeaders = {}) {
    let headers: Headers = {
      "Access-Control-Allow-Origin": "*",
      "Content-Type": "application/json",
      platform: "web",
      "x-trace-id": userAnalyticsID.value.toString(),
      ...extraHeaders
    };


  if (sendToken && useCookie<any>("access-token").value )) {
      headers["x-access-token"] = accessTokenCookie.value;
    }
}

the getHeaders was called by the fetchUser() to get the headers dynamically, the main issue here... the useCookie<any>("access-token").value ) has no value, which means the headers won't contain the access-token so it will fail..

the weirdest thing, is the `fetchUser() is wrapped with if statement to check if we have a token cookie, that's why it got called, but why that cookie was not there in the second plugin?

My fix, I followed @danielroe method above, by saving the token in event.context in the first plugin

if(process.server)
{
  const event = useRequestEvent();
  event.context["token"] = route.query.access_token
}

and then read it as well in the second plugin

const event = useRequestEvent();
let tkn = event.context.token

it works, but im not really confident, and hopefully the root cause gets fixed

@vhovorun
Copy link

@danielroe Hey, sorry for pinging you but any chances that this issue will be resolved soon? Seems like a critical one

@RomanSkrypnik
Copy link

Probably it's a little bit late but here is workaround:

import type { CookieOptions } from 'nuxt/dist/app/composables';

export default defineNuxtPlugin(() => {

  const setMyCookie = (key: string, val = '', options: CookieOptions = {}) => {
    useCookie(key, options).value = val;

    if (process.server) {
      const exp = options.expires;

      if (exp && exp.toUTCString) {
        options.expires = exp.toUTCString();
      }

      val = encodeURIComponent(val);

      let updatedCookie = key + '=' + val;

      for (const key in options) {
        updatedCookie += '; ' + key;
        const propValue = options[key];

        if (propValue !== true) {
          updatedCookie += '=' + propValue ;
        }
      }

      const event = useRequestEvent();

      event.node.req.headers.cookie = event.node.req.headers.cookie
        ? `${updatedCookie}; ${event.node.req.headers.cookie}`
        : updatedCookie;
    }
  };

  return {
    provide: {
      setMyCookie,
    }
  };
});

@mlbonniec
Copy link

Hi, is there any news on this issue ?

It seems that some methods has been implemented on h3 unjs/h3#509

@BobbieGoede
Copy link
Member

@danielroe does this mean we want useCookie to read and write to both Cookie (req) and Set-Cookie (res) headers server-side? I could implement this in the i18n module for nuxt-modules/i18n#2975 or see if I can revive/update #21940 to have it work from Nuxt's side.

@danielroe
Copy link
Member

Yes, it would be good to do that within Nuxt.

We would need to have the initial value of useCookie coming from the request headers, then (once set) future calls would access this value/update the value in the response headers.

One tricky thing is that this very much depends on cookie options - these effectively mean we can have different cookies which need to be tracked separately but have the same 'name'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants