Cookies in your app

Your app runs on <project>.eurobase.dev, next to every other Eurobase app. Any of those apps can write a cookie in its visitors' browsers that is also sent to your address, and your server can't tell who wrote it. So Eurobase forwards to your server only the cookies it can prove are yours.

What reaches your server

  • Cookies your server set with Set-Cookie, with any path and lifetime and any name except a __Host-js- or reserved one (below), as long as the browser still holds the value your server set.
  • Cookies your browser code writes whose name starts with __Host-js-, in exactly that case. Browsers accept __Host- cookies only with Secure, Path=/ and no Domain, so no other app can write or replace them, and Eurobase drops any your server tries to set under __Host-js-, so they can only come from your browser code.

Not forwarded:

  • Cookies written by browser code with any other name, __Host- ones included.
  • A cookie your server set, once browser code changes it, or once the browser drops Eurobase's proof cookie for it.
  • A cookie your server tries to set or delete with a __Host-js- name, in any letter case: Eurobase drops the Set-Cookie, so only browser code can remove those cookies, sign-out included.
  • Cookies set by other apps on eurobase.dev.
  • Names starting with eurobase, also after __Host- or __Secure-, in any letter case. They are reserved for Eurobase, and your server can't set them either.

Eurobase removes the Domain attribute from cookies your server sets, so they stay on your address, and adds one HttpOnly __Host-eurobase-c. cookie next to each one. That cookie is the proof; your code never sees it. Browsers keep about 180 cookies for all of eurobase.dev, shared with every app a visitor uses.

A cookie that isn't forwarded is still visible to your JavaScript in the browser; only the server doesn't receive it. Eurobase doesn't log cookie names or values.

One writer per cookie

Decide for each cookie whether your server or your browser code writes it. A cookie your server writes keeps the SameSite setting your server gives it, and stops reaching your server if the browser changes it. A cookie your browser code writes needs a __Host-js- name, which your server can't write. Set session cookies and anything else your server trusts from your server.

Keep a cookie written in the browser

Give it a name that starts with __Host-js-, and write and remove it with secure and path=/, without a domain:

document.cookie = '__Host-js-theme=dark; Path=/; Secure; Max-Age=31536000';

Removing it needs the same Path=/; Secure. Safari doesn't store Secure cookies on http://localhost; develop in Chrome or Firefox, or serve your dev server over HTTPS.

Requests from other sites

Browsers treat every .eurobase.dev app as the same site, so Eurobase applies the site rules for them. A cookie your server set arrives according to its SameSite setting: a link from another site, including another .eurobase.dev app, carries Lax, None and unset cookies; any other request from another site carries only None cookies.

Eurobase can't see the SameSite setting of a __Host-js- cookie your browser code wrote, so it treats it as a cookie without one, which browsers handle as SameSite=Lax. Your server receives it on requests from your own pages, when a visitor types your address, and on links from other sites, including search results, sign-in and email-link redirects and other .eurobase.dev apps, and on pages Chrome preloads for such a link. It never arrives on any other request from another site, such as a form post, a fetch, a frame or an image. Writing it with SameSite=Strict doesn't change this; for a Strict cookie, set it from your server.

Libraries that need a change

These write a cookie in the browser that the server reads. The deploy screen warns when your app depends on one marked Deploy warning.

LibraryFixWithout the fix
@supabase/ssrDeploy warningKeep the session in the browser with createClient from @supabase/supabase-js, and send its access token to your server in the Authorization header, which Eurobase forwards unchanged. Your server checks it with supabase.auth.getUser(token) and never refreshes it. Pages then render signed out on the server; load user data in the browser. If your server must read the session from cookies instead, pass cookieOptions: { name: '__Host-js-sb', secure: true } to the browser client and run sign-in, the sign-in callback and sign-out in the browser. Eurobase drops every cookie your server sets or deletes under __Host-js-, so your server may only verify the access token it reads from those cookies, for example with supabase.auth.getClaims(accessToken). Never call getSession, or getUser and getClaims without a token, exchangeCodeForSession, verifyOtp, signIn… or signOut on the server: they refresh or write the session, which Eurobase drops, and a server-side refresh can end the browser's session.The browser client writes the session and PKCE cookies in the browser, so the server sees users as signed out and sign-in callbacks can’t read the verifier. Both clients write the session cookies, so renaming them isn’t enough on its own.
@nuxtjs/supabaseDeploy warningSet supabase: { useSsrCookies: false, redirect: false } in nuxt.config, protect pages in the browser, and check the access token from the Authorization header in your server routes with getUser(token): serverSupabaseUser reads only cookies.As @supabase/ssr.
@nuxtjs/i18nDeploy warningKeep the language in the URL (the default prefix_except_default strategy) and set detectBrowserLanguage: false. With { useCookie: false } instead, / still redirects by browser language.Both the browser and the server write the language cookie, so the server stops receiving it and redirects by browser language.
@sidebase/nuxt-auth (local provider)Deploy warningSet cookieName to a __Host-js- name and secureCookieAttribute: true for the token and the refresh token, and turn refresh off or set disableServerSideAuth: true.The token cookie is written in the browser, so the server sees users as signed out after a reload. With refresh enabled the server writes it too.
Paraglide JS cookie strategyDeploy warningPut 'url' before 'cookie' in strategy, so the server reads the locale from the URL.The locale switcher reloads the page in the base locale. Paraglide writes its cookie without Secure, so it can’t use a __Host-js- name.
js-cookie, universal-cookie, react-cookie, cookies-nextDeploy warningGive the cookies your server reads a __Host-js- name, and write and remove them with { secure: true, path: '/' }. universal-cookie and react-cookie have no default path.The server never sees cookies written in the browser.
Nuxt useCookieUse useCookie('__Host-js-theme', { secure: true }). Eurobase drops the default your server would write back, so the browser's value is kept.A value changed in the browser is lost: the server doesn’t receive it, renders the default and writes the default back.
next-intlKeep the default localePrefix: 'always', so the locale is in the URL.With localePrefix as-needed or never, a language switch is lost on the next full load. The middleware and the browser both write the locale cookie.
i18next-browser-languagedetector with the cookie cacheSet lookupCookie: '__Host-js-i18next' and cookieOptions: { path: '/', sameSite: 'strict', secure: true }.The server doesn’t see the detected language.
@nuxtjs/color-mode with storage: cookieSet storageKey: '__Host-js-color-mode' and cookieAttrs: { path: '/', secure: true, 'max-age': '31536000' }.The server renders the default theme, then the page switches.
ClerkDeploy warningNo fix on a .eurobase.dev address: the name can't be changed, and Clerk production instances need a domain you own. Use another auth library.Clerk writes its session cookie in the browser under a fixed name, so the server sees every visitor as signed out.

Works without changes

  • Cookies your server sets and reads: SvelteKit cookies, Next.js cookies(), Astro cookies, Express, Rails, Django and Laravel sessions, Auth.js.
  • CSRF tokens your server sets and the browser only reads: Laravel XSRF-TOKEN with axios, Django csrftoken, Angular HttpClient.
  • next-themes, i18next-browser-languagedetector and @nuxtjs/color-mode with their default localStorage.

When your server doesn't receive a cookie

  • Browser code wrote it and its name doesn't start with __Host-js-, or browser code changed a cookie your server set.
  • The request came from another site and wasn't a link, or the cookie is SameSite=Strict (see above).
  • Your server set it before Eurobase started forwarding cookies. Set it again from your server.
  • The browser evicted it or its __Host-eurobase-c. proof to stay within its cookie limit, which another app can also cause by writing many cookies. Your app sees a new visitor.

Reused addresses

When a project is deleted, another project can take its address at once. Cookies your server set are bound to your project and never reach the next owner of the address. Cookies named __Host-js-, which only browser code writes, are bound only to the address: values a previous owner's app wrote, or ones planted by whoever held the address before you, can still be in visitors' browsers and reach your server under the same name until they expire. Set session cookies and anything else your server trusts from your server.

Supported browsers

These protections hold in Chrome 104.0.5112.101, Edge 106, Opera 92, Samsung Internet 20, Firefox 105 (ESR 102.3) and Safari 16.4, or later versions of each, including every browser on iOS and iPadOS 16.4 or later. In older browsers another app can forge cookies or send requests that carry them.