Cross Domain Cookie from Localhost returning 401s and 403s

Hi everyone,

There’s an issue that’s kinda driving me crazy and I’ve tried all the combinations of env variables, setups etc.

Setup:

  • Localhost with next.js
  • NextAuth with credentials

I’m developing locally at localhost:3000 and I have my instance of directus at secrey.mydomain.com.

The public API works smoothly but when I log a user in from localhost:3000 and receive an accessToken and/or set the cookie, whenever I make an API request to either /users/me or /items/my-collection from localhost:3000 it won’t include the credentials.

This is my authorize function:

 async authorize(credentials) {
        try {
          const res = await directus.login(credentials?.email as string, credentials?.password as string, {
            mode: 'cookie',
          });

          console.log('*** res ***', res);

          if (res.access_token) {
            (await cookies()).set('directus_session_token', res.access_token, {
              sameSite: 'none',
              path: '/',
              secure: false,
            });
          }

          const user = await directus.request(readMe());

          return {
            id: user.id,
            email: user.email,
            first_name: user.first_name,
            last_name: user.last_name,
            accessToken: res.access_token as string,
          };
        } catch (error) {
          console.error('Auth error:', error);
          throw new Error('Authentication failed');
        }

where directus is the client I import from

import { createDirectus, rest, graphql, authentication } from '@directus/sdk';

const directus = createDirectus(process.env.NEXT_PUBLIC_BASE_URL as string)
  .with(authentication('cookie', { credentials: 'include', autoRefresh: true }))
  .with(rest({ credentials: 'include' }))
  .with(graphql({ credentials: 'include' }));

export default directus;

where NEXT_PUBLIC_BASE_URL is sub.mydomain.com.

I have set on sub.mydomain.com all the combinations of

SESSION_COOKIE_SECURE
SESSION_COOKIE_SAME_SITE
REFRESH_TOKEN_COOKIE_SECURE
REFRESH_TOKEN_COOKIE_SAME_SITE
REFRESH_TOKEN_COOKIE_DOMAIN

but tbf nothing seems to work.

These are the requests I’m trying:

    const promises = [
      axios.patch(
        `${process.env.NEXT_PUBLIC_BASE_URL}/users/me`,
        { first_name: firstName, last_name: lastName },
        { withCredentials: true }
      ),
      directus.request(
        updateItem('user_portfolio', userPortfolio.id, { location, date_of_birth: dateOfBirth, availability })
      ),
    ];

/users/me returns 401 with invalid credentials
/items/user_portfolio returns 403 with forbidden

I’m at loss and not sure where to go next, if not passing the accessToken to the axios requests which I’d rather avoid, because I’d love for the cookie to just work.

Also, the auto-refresh doesn’t seem to work.

Please tell me if there’s anything else you might need from me in terms of info about my setup.

Thanks a lot in advance!

Hey @Stefano_Imparato, perhaps this might help:

cookies().set('directus_session_token', res.access_token, {
  sameSite: 'none',
  path: '/',
  secure: true, // Must be true when sameSite is 'none'
  domain: '.mydomain.com' // Consider setting this to share across subdomains
});

Also make sure that CORS if configured correctly (if you are using that) to allow requests from http://localhost:3000.

This is a good read tbh: Using Authentication in Next Js | Directus Docs

Hi, thanks a lot for your quick reply, what I understand from the document is that I’ll have to use json as a mode to use it client wise, is that correct? Otherwise I feel every request should be server side and that can be a bit tricky.

To be fair, even following by the letter the documentation the authentication is not really working flawlessly.

I’m having issues both with cookie and json mode – especially with the refresh. It won’t work either with autoRefresh: true (cookie) or by calling

const result = await directus.request(refresh('json', refreshToken));

It’s been a little bit frustrating.

I have not used the NextAuth package directly myself, I did make a custom solution with NextJS before using the Directus “session” mode for authentication.

The trick was to get the session token and store it in a cookie on the frontend (the nextjs site). Then, on each request to the backend (client-side OR server-side) I used a custom fetch to send the right cookie along and that worked perfectly fine (the 403 and 401 you mentioned indicate, to me, you are not actually passing the cookie to the Directus backend).

The customFetch also made sure to update the life-time of the cookie (the “refresh”).

As far as I can tell the autoRefresh from the SDK will only work when you use it client side only. Using NextJS that is probably not the best situation because you optimally would want to fetch the data serverside (SSR, SSG, ISR, PPR, whatever you want to use).

I will ditch NextAuth eventually – I have tried with the mode “session” but it’s not setting the cookie automatically at all from localhost. I will try again from scratch, try to understand what I’m doing wrong.

it’s not setting the cookie automatically

That’s correct, you will have to set the cookie yourself :slight_smile:

If you’re working on the server side, you’ll need to implement a custom solution using Redis. Store both the access_token and refresh_token in Redis for each user. On every request, retrieve these tokens from Redis and check if the access_token is expired or about to expire. If it is, use the refresh_token to obtain a new access_token and a new refresh_token, then update both tokens in Redis.