CodamAIDocs
Topicdone

Session in the BFF and cookies

Why the token lives in the frontend's server and not in the browser, what the session cookie looks like, and why every portal has its own cookie prefix.

Variants
Cookie httpOnly, sameSite=laxown prefix per portallifetime 1 h

What this is about

After the login, the BFF has three tokens from Keycloak. The question is: where are they stored? The answer at CodamAI: in an encrypted cookie that only the BFF can open. The BFF makes the calls to CDMS and CIAS, not the browser.

Where each token lives

flowchart LR
    B["Browser<br/>session cookie (encrypted)"] -- "cookie on every request" --> F["BFF<br/>decrypts:<br/>access, refresh, ID token"]
    F -- "Authorization: Bearer <access token>" --> A["CDMS / CIAS"]
    F -- "refresh token, ID token" --> K["Keycloak"]
TokenWhereWho uses it
Access tokenin the session cookie. The page can request it via /api/auth/sessionthe BFF on every API call
Refresh tokenonly in the session cookiethe BFF, to get a new access token
ID tokenonly in the session cookiethe BFF when signing out

Why not simply store it in the browser, for example in localStorage? Because every script on the page can read from there. A single injected script could then steal the refresh token and use it to get new tokens for hours. An httpOnly cookie is invisible to scripts.

PropertyValueMeaning
httpOnlyyesno JavaScript can read the cookie
sameSitelaxthe browser does not send it with forms or script requests from foreign sites
secureyes under httpsonly over encrypted connections. The name then gets the prefix __Secure-
path/applies to the whole application
Contentencrypted (JWE)tokens, expiry time, an error field. The key is the portal’s secret (NUXT_AUTH_SECRET)
Sizesplit when larger than about 4 KBthe parts are named …session-token.0, .1 and so on

In addition, the BFF sets short-lived cookies during the sign-in for state, PKCE and the return target. They are valid for at most 15 minutes.

JWE stands for JSON Web Encryption: the content is not only signed, but encrypted.

Lifetime: one hour, sliding

The session is valid for one hour. The hour is extended as long as the page is open. The user interface requests /api/auth/session every minute and when you return to the tab. Every request pushes the end back. At the same time, the BFF also renews the access token when it expires soon, see Renew the token.

Is the session still valid?
Tab open, page asks regularlylast request older than 1 hrefresh at Keycloak possibleWhat happens
yesnoyesSession continues, tokens are renewed
–yes–Cookie expired, new login on the next page view
yesnonoSession gets an error, the user interface starts a new login

Own prefix per portal

Cookies belong to a host name, not to a port. When several portals run on the same host, for example locally on localhost:3000 and localhost:3001, they see each other’s cookies. If all had the same cookie name, each portal would overwrite the other’s cookie, and each one has a different key:

What happens with the same cookie name
  1. 1
    Browser→Frontend
    Login in the hub sets next-auth.session-token, encrypted with the hub's key
  2. 2
    Browser→Frontend
    Login in the CDMS portal overwrites the same cookie with its own key
  3. 3
    Frontend
    The hub can no longer decrypt the cookie
    Session error, new login, which in turn signs out the other portal

That is why the CIAS portal uses its own prefix cias-auth. Its cookies are named cias-auth.session-token, cias-auth.csrf-token and so on. The hub and the CDMS portal use the default names next-auth.*.

How the BFF calls the API

One click in the user interface
  1. 1
    Browser→BFF
    GET /api/kunden, the session cookie is sent automatically
  2. 2
    BFF
    decrypts the cookie. Is the access token missing, or is there an error in the session?
    then 401 to the browser, the user interface starts a new login
  3. 3
    BFF→CDMS
    POST /api/rest/crm/customer/query with Authorization: Bearer <access token>
  4. 4
    CDMS→BFF
    Response
  5. 5
    BFF→Browser
    passes the data on

The portals do not send the tenant and user headers for a tenant switch or user switch. See Tenant switch by header.

Next

Sources in the code and the knowledge base
  • hub-frontend, CIAS/cias-frontend, CDMS/frontend – server/api/auth/[...].ts (session strategy jwt, maxAge, updateAge, callbacks), nuxt.config.ts (sessionRefresh)
  • CIAS/cias-frontend – server/utils/authCookies.ts, server/middleware/dropForeignAuthCookies.ts
  • hub-frontend – server/utils/backendFetch.ts, ciasFetch.ts, useCmsApi.ts
  • next-auth 4 – jwt/index.js (JWE dir/A256GCM), core/lib/cookie.js (names, flags, splitting)
Search