#Session Security

7 min read

#Overview

When you sign in to the AiDial portal, Zitadel authenticates you through OIDC and the portal resolves your role, tenant, and project scope from aidial_api. The portal stores that context in a next-auth JWT session cookie. The browser-facing session only exposes the fields needed by the user interface; the access token is not returned through useSession() or browser JavaScript.

Browser code must not send X-API-Key. API keys are for trusted server-side integrations, not portal sessions. Browser requests go to portal pages or app/api/ route handlers, and the portal server forwards bearer tokens to aidial_api through the shared lib/aidial-api/ transport.

Page access and data access are checked server-side. Middleware covers non-API portal routes, while every app/api/** route handler must enforce its own auth, RBAC, CSRF, and tenant/project scope checks. Out-of-scope access resolves to non-enumerating denied states such as 404, /not-found, or /access-denied. Navigation visibility is only a convenience and is not a security boundary.

#Session Expiry

The portal registers sessions with aidial_api during sign-in, polls session state after hydration, and touches the session on user activity. The effective lifecycle policy comes from the backend session endpoints and includes idle timeout, absolute timeout, and the concurrent-session limit.

Your session can expire or be invalidated under these conditions:

  • Inactivity timeout — If you have not interacted with the portal for the effective idle period, your session can expire and you will be prompted to sign in again.
  • Absolute timeout — Regardless of activity, your session can expire after the effective maximum duration.
  • Concurrent-session eviction — If an older session is revoked because of the active-session limit, that browser is redirected to the access-denied state.
  • Manual revocation — If you or an authorised administrator revoke a session, that session is treated as no longer valid.
  • IP allowlist restriction — If your tenant restricts portal access by IP address and your current address is no longer allowed, the portal signs that browser out and sends you to the access-restricted state.

SessionMonitor calls GET /api/auth/session-state and redirects the browser when the backend reports a terminal lifecycle state. Most terminal states land on /access-denied with the reason; an IP allowlist restriction is routed through /api/auth/force-signout to /access-restricted. When one tab observes a terminal state, it broadcasts that to the other portal tabs in the same browser so they transition as well. It also posts POST /api/auth/session-touch with the portal CSRF token on activity, using the backend debounce window to avoid excessive requests. If session validation is temporarily unavailable, the portal stays authenticated and shows a non-blocking degraded-state warning instead of forcing an immediate sign-out.

#Signing Out

All portal users can sign out at any time using the sign-out option in the portal.

The sign-out button posts to POST /api/auth/signout with the portal CSRF token. The route clears the current browser's session cookie, any observed chunked session-cookie names, and the CSRF cookie. It records a sign-out lifecycle audit event when the session context is available and returns Zitadel's OIDC end-session URL when an ID token is present. The client then redirects to that URL. If the identity-provider logout URL is unavailable, the current browser is still signed out locally.

Recovery links from session-ended states use GET /api/auth/force-signout to clear local session and CSRF cookies before returning to a safe sign-in path. When requested and an ID token is available, that recovery route can also hand off to Zitadel's OIDC end-session URL.

Signing out affects the current browser session. To end sessions on other devices, use the session revocation controls described below.

#Managing Your Active Sessions

Customer roles (client_admin, client_manager, and client_staff) can review and revoke their own portal sessions under Account → Security at /account?section=security:

  • client_admin — Account is the canonical destination; the compatibility deep link /settings?section=active-sessions also remains available.
  • client_manager and client_staff — the /settings?section=active-sessions deep link returns a not-found state, so use Account → Security.

From the panel you can:

  • View active sessions — See a list of your currently active sessions, including a customer-safe device label, the IP address each session connected from, a device class, when it was created, and when it was last active.
  • Revoke individual sessions — Review a customer-safe device summary, then confirm before ending a specific non-current session (for example, a session left open on another device).
  • Sign out other devices — Revoke all sessions except your current one.

The panel reads your signed-in portal session and forwards no API key. The BFF retains the OIDC ID token server-side; aidial_api verifies its signature, issuer, audience, expiry, and at_hash binding to the bearer access token, then derives the current session from its signed sid. Browser input cannot select which session is current. Revocation requests are CSRF-protected and may be rate-limited.

These features help you maintain control over your account security, especially if you suspect unauthorised access.

The current session is labelled and is not revocable from this panel; use the normal sign-out flow for the current browser.

#Session Revocation by Administrators

Customer roles do not have a team-based session or role-management surface. /team and any path beneath it return a not-found state for every role, and the /api/team/** team-management route handlers are deny-all for every role, so client_admin cannot inspect another user, change that user's role, or revoke that user's sessions. Contact an authorised AiDial administrator when another user's access must be changed.

Internal other-user session truth is part of the canonical admin user detail at /users/{portalUserId}. The route uses the numeric portal_users.id; the returned identity includes the distinct Zitadel subject used by session rows. aidial_operator can read the complete cross-tenant session projection but receives no mutation controls. aidial_admin can read it and revoke one session or all sessions. Customer and partner roles receive a non-enumerating not-found response from the corresponding admin APIs.

Admin revocation is CSRF-protected, rate-limited, and server-scoped. The browser never supplies client_id, data_env, or a Zitadel subject. A tenant-scoped bulk action supplies only a decimal-string numeric assignment ID returned by the same admin detail; the API rejects JSON-number coercion, verifies that assignment belongs to the target portal user, and derives tenant and environment. A single-session action verifies the session belongs to the target user's Zitadel subject and derives tenant and environment from that session. An administrator cannot target their own Zitadel subject through these admin routes.

#Partner Roles

Partner roles (partner_admin and partner_user) can sign out of the portal using the standard sign-out option. Partner roles do not have access to the session-management surface. The session BFF routes (/api/auth/sessions, /api/auth/sessions/[sessionId]/revoke, and /api/auth/sessions/revoke-others) return a not-found state for partner roles, so they cannot view active session lists, revoke individual sessions, or sign out other devices from the portal.

#Required Runtime Configuration

Session security depends on these required runtime environment variables. The portal code treats them as required and does not define fallback defaults:

  • NEXTAUTH_SECRET
  • NEXTAUTH_URL
  • AIDIAL_API_BASE_URL
  • AIDIAL_API_TIMEOUT_MS
  • ZITADEL_ISSUER
  • ZITADEL_CLIENT_ID
  • ZITADEL_CLIENT_SECRET

#Session Security Best Practices

  • Sign out when finished — Always sign out when you are done using the portal, especially on shared or public computers.
  • Review active sessions regularly — If you have session management access, periodically review your active sessions and revoke any you do not recognise.
  • Report suspicious activity — If you notice unfamiliar sessions or suspect unauthorised access, revoke them immediately and contact your administrator.
  • Enable MFA — Multi-factor authentication adds an extra layer of protection. Even if your password is compromised, MFA helps prevent unauthorised sign-in. See Multi-Factor Authentication.

#Next Steps