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

SSR not passing cookies #186

Closed
MrTeapot opened this issue Sep 11, 2022 · 14 comments
Closed

SSR not passing cookies #186

MrTeapot opened this issue Sep 11, 2022 · 14 comments
Assignees
Labels
bug Something isn't working

Comments

@MrTeapot
Copy link

Hey!

This is probably an issue based on my lack of knowledge about Nuxt. But I can't find a way to solve it.

I have a Nuxt middleware that makes sure that a user is authenticated before allowing them to navigate to certain pages. The authentication is based on sessions, and a cookie needs to be sent with every request to my graphql api.

This works great in SPA mode: the cookie is passed directly from the browser to the API. However, on initial page load, when the app runs in SSR mode, the cookie is not passed along to the API. This means that if a user logs in and navigates to a restricted page, then refreshes the window, they are redirected to the login screen even though they have a session.

How can I make sure that the SSR code passes along the cookie?

Here is the code for the middleware:

export default defineNuxtRouteMiddleware(async (to, from) => {
  const user = useState("user");
  if (!user.value) {
    try {
      const { data } = await useAsyncGql("userinfo");
      if (data.value.user) {
        user.value = data.value.user;
      } else {
        return navigateTo({
          path: "/login",
          query: {
            reason: "No user info",
          },
        });
      }
    } catch (err) {
      return navigateTo({
        path: "/login",
        query: {
          reason: 'request error',
        },
      });
    }
  }
});

Thanks in advance.

@Diizzayy Diizzayy self-assigned this Sep 12, 2022
@Diizzayy
Copy link
Owner

@MrTeapot Thank you for raising this issue, This module is supposed to proxy cookies in SSR by default but, it seems there might be a bug in it's current implementation that foregoes this expected behavior when your client isn't declared in the clients object ( ie: declared via GQL_HOST ).

@Diizzayy Diizzayy added the bug Something isn't working label Sep 12, 2022
@Diizzayy
Copy link
Owner

@MrTeapot Update nuxt-graphql-client to version 0.1.17 then give it a try again

@MrTeapot
Copy link
Author

Thanks for getting back to me!

I upgraded but I still have issues.
I get this error in the console now, I don't think I got it before (I also upgraded Nuxt to rc9):
[Vue warn]: onServerPrefetch is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement.

@MrTeapot
Copy link
Author

MrTeapot commented Sep 12, 2022

I changed my middleware to this, now I don't get the warning I just mentioned. But still, the request in unauthorized:

export default defineNuxtRouteMiddleware(async (to, from) => {
  const user = useState("user");
  if (!user.value) {
    try {
      const response = await GqlUserinfo();
      if (response.user) {
        user.value = response.user;
      } else {
        return navigateTo({
          path: "/login",
          query: {
            reason: "No user info",
          },
        });
      }
    } catch (err) {
      return navigateTo({
        path: "/login",
        query: {
          reason: JSON.stringify(err),
        },
      });
    }
  }
});

This is from the nuxt config:

  runtimeConfig: {
    public: {
      GQL_HOST: "http://nginx/api/graphql",
    },
  },

The Nuxt app is reached through http://nginx/ so they are on the same domain.

@Diizzayy
Copy link
Owner

Diizzayy commented Sep 12, 2022

I changed my middleware to this, now I don't get the warning I just mentioned. But still, the request in unauthorized:

@MrTeapot The onServerPrefetch warning that you previously encountered, was in fact due to using useAsyncGql, perhaps the docs are a bit unclear about it's intended use but, It's only meant to be used to initially request data that is required to render a page. Outside of that case, you should simply be using the pertinent GqlFunction for your query.

As for the authorization issue here, I can confirm that the implementation does in fact work as it's expected to, so there must be something else at play here causing your auth issue, Might I ask what GraphQL API you're working with?

@MrTeapot
Copy link
Author

I can see that the cookie is passed along now! So your library is doing what is expected :)

The graphql api is built with Nestjs, and uses the express-session npm package for session management.

  app.use(
    session({
      secret: 'my-secret',
      resave: false,
      saveUninitialized: false,
      cookie: {
        sameSite: true,
        secure: false,
      },
    }),
  );

For some reason it's not picking up the session, even though the correct cookie is passed!

@MrTeapot
Copy link
Author

From what I can see it looks like the nuxt ssr mode gets it's own session id and cookie. When the graphql queries run in SPA mode, it's the cookie id and session associated with the user. But when it runs in SSR mode, it's a different cookie and session id that is not associated with a user.

@sweetroll
Copy link

@MrTeapot I am finding the same thing. Console logging out the gqlState in my server middleware shows the correct headers but my GraphQL API receives another. Although it seems like they are old tokens which suggest some persistence bug in the gqlState?

@MrTeapot
Copy link
Author

MrTeapot commented Sep 13, 2022

@MrTeapot I am finding the same thing. Console logging out the gqlState in my server middleware shows the correct headers but my GraphQL API receives another. Although it seems like they are old tokens which suggest some persistence bug in the gqlState?

Yup it looks like old cookies are showing up sometimes!

I'm even getting new session id's assigned to old cookies in my graphql api.. I'm super confused right now :)

There could also be some issues when logging out, I'm destroying the session and clearing the cookie but it's could still be stored in Nuxt. SSR appears to be using the old one, for the session that has been destroyed.

@sweetroll
Copy link

@Diizzayy is it possible to override headers per request rather than relying on gqlState, similar to $fetch?

@Diizzayy
Copy link
Owner

@sweetroll headers can be overridden on a per request basis as seen here

const variables = {}
const headers = { 'X-Custom-Header': 'ABC' }
const data = await GqlExample(variables, headers)

@sweetroll
Copy link

@Diizzayy appreciate your quick reply. That definitely seems to be working better however I'm seeing an issue when trying to unset the Authorization header. When I pass {} in as the headers it seems to be using the previously set token. Thanks

@Diizzayy
Copy link
Owner

Diizzayy commented Sep 13, 2022

@sweetroll Passing {} would actually have no effect, The proper way to reset headers should be by passing useGqlHeaders(null) whereas the auth token should be reset via useGqlToken(null). These should be working as expected, if that isn't that case I'll have to investigate to see exactly what's causing this behavior.

@sweetroll Feel free to reach out to me on discord@ Diizzayy#1964 , I may be able to provide more assistance there.

@Diizzayy
Copy link
Owner

Closing for now as the initial issue raised should be fixed in recently released versions ^0.1.28

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants