Cross-Origin Authentication Mismatch

Hello everyone,

I’m setting up a Next.js (client) application served at https://dashboard.local to connect to a Directus API running on https://directus.local. I’m using the @directus/sdk for authentication.

We successfully configured the Directus backend to use HTTPS with secure cookies and set the REFRESH_TOKEN_TTL to 12 hours. However, due to cross-origin restrictions, the authentication flow is splitting the tokens, which is causing instability.

Observed Behavior (The Mismatch)

When the Next.js client calls the /auth/login endpoint, the server responds with a split token delivery:

  1. Access Token: Delivered in the JSON response body ({ data: { access_token: "..." } }).

  2. Refresh Token: Delivered via a HTTP-only cookie (directus_refresh_token).

This mixed delivery shows that the browser is blocking the Access Token cookie due to cross-origin/SameSite=None restrictions, forcing the server to send the Access Token in the response body. Is this correct?

Environment Variable Value

CORS_ORIGIN"https://dashboard.local"

SESSION_COOKIE_SECURE"true"

REFRESH_TOKEN_COOKIE_SECURE"true"

REFRESH_TOKEN_COOKIE_SAME_SITE"None"

SESSION_COOKIE_SAME_SITE"None"

REFRESH_TOKEN_COOKIE_DOMAIN"dashboard.local"

SESSION_COOKIE_DOMAIN"dashboard.local"

Are you using the Directus SDK to call the login function? Are you specifying a 'mode' attribute in your login payload?

export const directusClient = createDirectus(API_URL) .with( authentication("json", { storage: authLocalStorage, autoRefresh: true, credentials: "include", }) ) .with(rest()) .with(realtime({ authMode: "handshake" })); Do i miss something? in the brower we see Payload mode: Cookie

1 Answer

1

If you’re using “json” mode, cookies are not used at all. Perhaps you want to use the ‘session’ mode which returns a single directus_session_token cookie

export const directusClient = createDirectus(“``http://localhost:8055``”) .with(authentication(“session”, { autoRefresh: true, credentials: “include”, })) .with(rest({ credentials: “include” })) .with(realtime({ authMode: “handshake” }));

This then returns a cookie instead of a json response. and subsequent requests to the API will include the cookie.

Thank you for the clarification. We are already using the "session" authentication mode, and the login and basic collection operations (read , create, update, delete) work correctly. However, we’ve noticed an issue with update permissions when we restrict updates to specific fields in the permissions settings, the API still allows updating all fields. Is this the expected behavior, or could there be a configuration issue on our side?