Qontak | Platform | Centralize SSO Token — Centralized Web Session Integration
Product Requirements Document · NEW PRD v1.0
Superseded by centralized-sso-token.md — this early draft (Hub-Chat + Launchpad scope only) was superseded by the broader 4-product PRD, which carries the assigned Epic
BIF-7802. Kept for historical reference only.
HEADER BLOCK
| Field | Value |
|---|---|
| PM | Qontak PM Group |
| PRD Version | 1.0 |
| Status | DEPRECATED |
| PRD Type | NEW |
| Epic | TBD — add once Epic is created |
| Squad | Bifrost |
| RFC Link | RFC: Centralized Web Session Between Product and SSO |
| Figma Master | N/A — no UI changes required |
| Anchor | No — standalone, single-squad |
| Labels | epic:qontak-platform | module:sso | feature:centralized-session |
| Last Updated | 2026-06-30 |
Table of Contents
- HEADER BLOCK
- 1. One-liner + Problem
- 2. Target Users + Persona Context
- 3. Non-Goals
- Scope Changes
- 4. Constraints
- 5. Background & Current State
- 6. New Features
- 7. System Flow + User Stories + ACs
- 8. Rollout
- 9. Observability
- 10. Success Metrics
- 11. Dependencies
- 12. Key Decisions + Alternatives Rejected
- 13. Open Questions
- PRD CHANGELOG
1. One-liner + Problem
One-liner: Integrate the Mekari Session SDK into Qontak products so that user sessions are synchronized with SSO — logging out or switching accounts on any Mekari product is immediately reflected in Qontak without stale session state.
Problem:
Qontak's products (hub-chat and qontak-launchpad) each manage sessions independently. When a user logs out from SSO (account.mekari.com) or switches to a different Mekari account, Qontak products have no mechanism to detect this. As a result:
- A user who logs out of SSO remains fully logged in to Qontak — their session persists until it naturally expires, potentially exposing another user's company data.
- A user who switches SSO accounts (e.g. from Company A to Company B) can land back on a Qontak page still showing Company A's data, because the product session was never invalidated.
- Hub-chat currently maintains three parallel token chains (
chat_sso_token,crm_sso_token,global_sso_token) with no centralized validation — token drift leads to inconsistent auth state. - Qontak Launchpad uses
LAUNCHPAD_SSO_IDcookies andglobal_sso_tokenfor session tracking, but has no event-driven mechanism to react to SSO-side session changes.
The Platform team (Account & Launchpad) is building a centralized solution: a mekari-session JS SDK and a Session Manager service (RFC: Centralized Web Session Between Product and SSO). Qontak's responsibility is to integrate this SDK into its frontend products and update its logout flows to propagate session termination through SSO.
2. Target Users + Persona Context
| Persona | Role | Goal | Pain | Workaround |
|---|---|---|---|---|
| Primary — Qontak End User | Agent or Admin using hub-chat or Qontak Launchpad | Log out from one Mekari product and have all products reflect that immediately | After logging out from SSO or another Mekari product, still has full access to Qontak — session is not revoked | None — unaware the session is stale until a colleague tries to access the same browser |
| Primary — Multi-account User | User who manages multiple Mekari company accounts | Switch companies on SSO and immediately work in the correct company context in Qontak | Switches SSO account to Company B but Qontak still shows Company A's data — must manually sign out and back in | Manually sign out from Qontak, then re-sign in after SSO switch |
| Secondary — Qontak Frontend Engineer | Dev maintaining hub-chat or qontak-launchpad-fe | Single, reliable source of truth for session validity | Manages three parallel token chains with no cross-product validation; token drift is hard to debug | Periodic token sync via syncSsoCookie() — fires regardless of actual SSO session state |
3. Non-Goals
- This does not replace Qontak's existing OAuth2/Doorkeeper token management in hub-service — the SDK validates session state; the existing token system continues to handle API authorization.
- This does not auto-revoke access & refresh tokens when the user is idle for 2 hours (out of scope per RFC).
- This does not cover mobile apps — web only.
- This does not implement the Session Manager service or the SDK itself — that is owned by the Account & Launchpad Platform team.
- This does not modify Qontak's existing Redis or session storage — Qontak does not write to the centralized SSO Redis.
- This does not build a new logout UI — the existing logout screens are preserved; only the destination of the logout redirect changes.
- This does not gate access to SSO login/callback flows — the existing OAuth2 authorization code flow is unchanged.
- This does not apply to non-Qontak One clients (
unified_app = false) — the SDK is only initialized for accounts on the unified platform.
Scope Changes
- Frontend (hub-chat) — Install
@mekari/sdk; initializeSessionwithuser_sso_idon every page via global middleware; handlelogged_in,logged_out,switch_user,server_downevents; gate full behavior behindcentralized_sessionfeature toggle. - Frontend (qontak-launchpad-fe) — Same SDK integration as hub-chat; update unified logout to call SSO sign-out endpoint.
- Backend (hub-service) — Update product logout flow to redirect to
account.mekari.com/sign_outafter destroying the local session; sync current company from SSO after session creation. - Backend (qontak-launchpad) — Update logout routing to propagate to SSO sign-out endpoint; align
update_last_sessionwebhook with Session Manager's session tracking.
4. Constraints
- Platform dependency gate: This PRD cannot be released until the Platform/Account & Launchpad team delivers: (a) Session Manager service at
account.mekari.com/sm/*, (b)@mekari/sdkpublished and stable, (c) Qontak domains added to the SDK CSP frame-ancestors or referrer whitelist. - Feature toggle required: All behavioral changes must be gated behind a
centralized_sessionfeature flag to allow safe rollback if Session Manager is degraded. - SDK SLA dependency: Hub-chat pages are high-traffic (up to 2.9k RPS at clock-in/out). Session Manager's published SLA is 50ms p95 at 6k RPS. Qontak FE must implement the
server_downfallback correctly to avoid user disruption if that SLA is breached. - No domain-crossing: Session validation relies on the
_mekari_accountcookie. Qontak's domains (qontak.com,qontak.net) must be declared as allowed origins in the SDK CSP policy before integration goes live. - Backward compatibility: When
centralized_sessiontoggle is OFF, existing auth behavior (current cookie/localStorage token chains) must continue working without any regression. - Qontak One only: The SDK must only be initialized for accounts where
unified_app = true. Non-unified accounts (unified_app = false) must continue using the existing auth flow with no changes.
5. Background & Current State
Current Session Architecture Per Product
| Product | Session Storage | Token Keys | Logout Flow |
|---|---|---|---|
| hub-chat (FE) | Cookies + localStorage | qontak._token.hub, qontak._refresh_token.hub, chat_sso_token, crm_sso_token, global_sso_token | Clears cookies + localStorage; does NOT call SSO sign-out |
| hub-service (BE) | Doorkeeper OAuth2 + cookies | chat_sso_token, chat_sso_refresh_token, crm_sso_token, global_sso_token | Revokes OAuth2 tokens; does NOT call SSO sign-out |
| qontak-launchpad-fe (FE) | Cookies | global_sso_token, global_sso_refresh_token, global_sso_valid_until, LAUNCHPAD_SSO_ID | Calls ChatPanel /logout with is_unified_logout=true; does NOT call SSO sign-out directly |
| qontak-launchpad (BE) | Header-based (X-Authenticated-Userid + Bearer) + Redis cache (24h TTL) | N/A (stateless) | No dedicated logout endpoint — token invalidation delegated upstream |
Key Gap: None of the four products currently validate session state against SSO at page load or on an interval. They rely entirely on their own token TTL and refresh logic, which operates independently of the SSO session's actual state.
What the Platform Team Delivers (from RFC)
| Component | Description |
|---|---|
| Session Manager Service | Go service hosted at account.mekari.com/sm/* via Kong/MAG. Maintains session state in a dedicated Redis. Validates _mekari_account cookie and returns user_sso_id |
@mekari/sdk | JS SDK (CJS + ESM). Injects an invisible iframe pointing to account.mekari.com/sm/current. Emits events: logged_in, logged_out, switch_user, server_down. Uses postMessage to return session state to the parent page |
| Centralized Redis | Separate from SSO's existing Redis. Stores msi:session:{sessionID} (1 day TTL) and msi:sessionmapping:{user_sso_id}. Accessible only by SSO and Session Manager |
| Session Events | logged_in — session valid, user_sso_id matches; logged_out — session gone (idle 2h or explicit logout); switch_user — session exists but different user_sso_id; server_down — Session Manager unreachable |
| Fallback mechanism | SDK reads msli (Mekari Session Logged In) localStorage key + _mekari_account cookie as fallback when Session Manager is down |
6. New Features
F1: Mekari Session SDK Integration (hub-chat)
Initialize @mekari/sdk on every page of hub-chat, passing the current user's user_sso_id. React to session events to enforce session state consistency:
logged_in→ continue normally; updatemslitimestamplogged_out→ trigger sign-out flow (clear tokens, redirect to SSO sign-in)switch_user→ destroy local session, redirect to SSO autologin, rebuild session for the new accountserver_down→ usemsli+_mekari_accountcookie as fallback; sign out if fallback also fails
F2: Mekari Session SDK Integration (qontak-launchpad-fe)
Same as F1 but implemented in qontak-launchpad-fe (Nuxt), leveraging the existing authenticated.global.ts middleware hook for SDK initialization.
F3: Centralized Logout Flow — Hub-Service
After destroying the local Qontak session, redirect the user to account.mekari.com/sign_out instead of terminating the flow at the product. This ensures the SSO session is also terminated, which in turn causes Session Manager to invalidate all product sessions for that user.
F4: Centralized Logout Flow — Qontak Launchpad
Update Qontak Launchpad to route logout through account.mekari.com/sign_out to propagate session termination to SSO. Align update_last_session webhook behavior with Session Manager's last_request_at TTL logic.
F5: Current Company Sync After Session Event
After logged_in or switch_user results in a new session being created in Qontak, call https://api.mekari.com/v1.1/users/{user_sso_id}/current_company via Qontak BE (using client_credentials) to ensure the correct company context is set. This guards against the multi-account scenario where session switches leave stale company data.
7. System Flow + User Stories + ACs
7.1 System Flow
F1/F2: SDK Event Flow (FE)
User accesses Qontak page
→ Middleware loads SDK: new Session({ current_user: user_sso_id })
→ SDK injects hidden iframe → account.mekari.com/sm/current (sends _mekari_account cookie)
→ Session Manager validates session in Redis
→ If session exists: update last_request_at, return user_sso_id via postMessage
→ If session absent: return null
→ SDK compares user_sso_id
→ Match → emit logged_in → update msli timestamp
→ Mismatch → emit switch_user → destroy session, redirect to SSO autologin
→ Null (no session) → emit logged_out → sign-out flow
→ Timeout/unreachable→ emit server_down → fallback: check msli + _mekari_account cookie
F3/F4: Centralized Logout Flow (BE)
User clicks logout on Qontak
→ Qontak FE calls Qontak BE logout endpoint
→ Qontak BE: destroy local session + revoke OAuth tokens
→ Qontak BE / FE: redirect user to account.mekari.com/sign_out
→ SSO: destroy _mekari_account session in Redis Session
→ SSO: clear session mapping (msi:sessionmapping:<user_sso_id>)
→ SSO: redirect user to account.mekari.com/users/sign_in
F5: Current Company Sync
SDK emits logged_in or switch_user
→ Qontak FE → Qontak BE: GET /current_company
→ Qontak BE → SSO: GET /v1.1/users/{user_sso_id}/current_company (client_credentials)
→ Qontak BE: set company context
→ Qontak FE: render correct company data
7.2 User Stories
| User Story | Importance | Technical Notes | Acceptance Criteria |
|---|---|---|---|
| [SSO-S01] — Hub-Chat SDK Integration As a hub-chat user, I want my Qontak session to automatically expire when I log out of SSO or any Mekari product, so that my company data cannot be accessed by another person using the same browser. | Must Have | Install @mekari/sdk. Initialize Session in authenticated.global.ts middleware after user is loaded. Gate entire SDK behavior behind centralized_session feature toggle. Store SDK instance in AuthStore or a dedicated composable. | — Happy Path — • AC-1: Given centralized_session toggle is ON, when a hub-chat page loads and the user is authenticated, then the SDK is initialized with the correct user_sso_id before the user can interact with the page.• AC-2: Given the SDK emits logged_in, then msli localStorage key is updated with the current timestamp and the user sees the page normally.• AC-3: Given the SDK emits logged_out (SSO session ended), then all local tokens and cookies are cleared and the user is redirected to the Qontak sign-in page.• AC-4: Given the SDK emits switch_user (user switched SSO account), then the Qontak FE destroys the local session, redirects to SSO /auth for autologin, and after redirect back, creates a new Qontak session for the new account with correct company data.— Error / Unhappy Path — • ERR-1: Given the SDK emits server_down, when msli exists and the diff with current time is < 2 hours AND _mekari_account cookie is valid, then the SDK returns logged_in as a fallback and normal page access continues.• ERR-2: Given the SDK emits server_down, when msli is absent OR diff > 2 hours OR _mekari_account cookie is invalid, then the user is signed out.• NEG-1: Given centralized_session toggle is OFF, then SDK is not loaded and existing hub-chat token flow behaves exactly as before.• NEG-2: Given the authenticated user's account has unified_app = false, then the SDK is not initialized and the existing hub-chat auth flow is used unchanged. |
| [SSO-S02] — Qontak Launchpad FE SDK Integration As a Qontak Launchpad user, I want my Launchpad session to automatically expire when I log out of SSO or any Mekari product, so that stale sessions from a previous company setup flow cannot persist. | Must Have | Same SDK integration pattern as SSO-S01. Launchpad's authenticated.global.ts is the integration point. Replace current LAUNCHPAD_SSO_ID cookie check with SDK event. Remove or retain LAUNCHPAD_SSO_ID as secondary fallback during migration. | — Happy Path — • AC-1: Given centralized_session toggle is ON and a Launchpad page loads, then SDK is initialized with the user's user_sso_id.• AC-2: Given SDK emits logged_out, then the Launchpad session is destroyed and user is redirected to sign-in.• AC-3: Given SDK emits switch_user, then Launchpad destroys session, redirects to SSO for autologin, and rebuilds session with the new account's company context.— Error / Unhappy Path — • ERR-1: Given SDK emits server_down, then fallback behavior (msli + cookie check) applies identically to SSO-S01.• NEG-1: Given centralized_session toggle is OFF, then existing Launchpad session flow (LAUNCHPAD_SSO_ID + global_sso_token) is unchanged.• NEG-2: Given the authenticated user's account has unified_app = false, then the SDK is not initialized and existing Launchpad auth flow is used unchanged. |
| [SSO-S03] — Hub-Service Centralized Logout As a Qontak system, when a user logs out from Qontak, I want the SSO session to also be terminated so all other Mekari products detect the logout via the SDK. | Must Have | Modify the logout endpoint in hub-service to redirect to account.mekari.com/sign_out after local session destruction and OAuth token revocation. This propagates the logout through SSO Redis, which invalidates the _mekari_account session. | — Happy Path — • AC-1: Given a user clicks logout on hub-chat, then hub-service destroys the local Qontak session and revokes OAuth tokens, then redirects the user to account.mekari.com/sign_out.• AC-2: Given the user is redirected to SSO sign-out, then the _mekari_account session is destroyed in SSO Redis and the user lands on account.mekari.com/users/sign_in.• AC-3: Given another browser tab has hub-chat open after the logout, when the SDK polling interval fires, then the SDK emits logged_out and that tab is also signed out.— Error / Unhappy Path — • ERR-1: Given the redirect to account.mekari.com/sign_out fails (SSO unreachable), then the user is still signed out of Qontak locally and shown the Qontak sign-in page.• NEG-1: Given centralized_session toggle is OFF, then the existing logout behavior (no SSO redirect) is preserved. |
| [SSO-S04] — Qontak Launchpad BE Centralized Logout As a Qontak system, when a user logs out from Qontak Launchpad, I want the SSO session to also be terminated so all products detect the logout. | Must Have | Currently, qontak-launchpad has no dedicated logout endpoint — termination is delegated upstream to hub-service via unified logout. Confirm that the unified logout path already propagates to SSO sign-out after SSO-S03 is done, OR add an explicit SSO sign-out redirect in qontak-launchpad's logout handler if one exists. | — Happy Path — • AC-1: Given a user initiates logout from Qontak Launchpad FE, when the unified logout chain completes (ChatPanel /logout → hub-service → SSO sign-out), then the _mekari_account session is destroyed.• AC-2: Given SSO-S03 is implemented, then the existing unified logout chain in qontak-launchpad-fe already achieves SSO sign-out without additional changes to qontak-launchpad BE. (If not, a direct SSO redirect must be added.) — Error / Unhappy Path — • ERR-1: Given hub-service (ChatPanel) is unreachable during logout, then qontak-launchpad destroys local cache (Redis user/company lookup) and redirects user to SSO sign-out directly as fallback. |
| [SSO-S05] — Current Company Sync After Session Event As a Qontak user who switches SSO accounts, I want the correct company to be displayed immediately after switching, so I don't see data from my previous company. | Must Have | After logged_in or a successful switch_user → autologin cycle, Qontak FE calls Qontak BE to fetch current company from SSO API (GET /v1.1/users/{user_sso_id}/current_company via client_credentials). This is per RFC recommendation. | — Happy Path — • AC-1: Given SDK emits logged_in and Qontak BE creates a session, then Qontak BE calls SSO GET /v1.1/users/{user_sso_id}/current_company (client_credentials) and stores the result as the user's active company context.• AC-2: Given SDK emits switch_user and the autologin cycle completes with a new Qontak session, then the new company context from SSO is fetched and rendered before the user interacts with any company-specific data.— Error / Unhappy Path — • ERR-1: Given the SSO /current_company call fails, then the user is shown an error state and prompted to refresh; Qontak does not silently use the previous company context. |
8. Rollout
This PRD is a SUPPORT initiative from Qontak's perspective — Qontak integrates what the Platform team builds, following the rollout sequence defined in the RFC.
| Phase | Description | Owner | Dependency |
|---|---|---|---|
| Phase 0 — Prerequisite | Confirm Platform team has deployed Session Manager, published @mekari/sdk, and whitelisted Qontak domains (qontak.com, qontak.net) in SDK CSP | Platform / Account & Launchpad | Session Manager deployed at account.mekari.com/sm/* |
| Phase 1 — SDK Spike | Install @mekari/sdk in hub-chat and qontak-launchpad-fe on staging; validate iframe + postMessage flow against Session Manager; confirm all four events fire correctly | Bifrost FE | Phase 0 complete |
| Phase 2 — BE Logout Update | Update hub-service logout to redirect to SSO sign-out; validate qontak-launchpad unified logout chain propagates to SSO correctly | Bifrost BE | Phase 0 complete |
| Phase 3 — Internal Rollout | Enable centralized_session flag for internal Mekari company CIDs only; monitor SDK event rates and server_down frequency; validate company sync accuracy | Bifrost | Phase 1 + 2 complete |
| Phase 4 — Gradual GA | Enable centralized_session flag progressively by user percentage (10% → 50% → 100%); monitor p95 SDK latency and server_down event rate; back off if anomalies detected | Bifrost | Phase 3 stable for 1 week |
Rollback: Disable centralized_session feature flag → reverts to pre-integration token behavior with no code changes required.
9. Observability
| Signal | Tool | Alert Threshold |
|---|---|---|
server_down event rate from SDK | Datadog / custom metric | > 1% of SDK initializations in 5-minute window |
| SDK initialization failure (sdk.js load error) | Sentry / browser error tracking | Any error on sdk.js load |
| Hub-service logout redirect failure rate | Datadog | > 0.1% of logout requests fail to reach SSO sign-out |
/current_company call failure rate after session event | Datadog | > 1% failure rate |
switch_user event rate (anomaly detection) | Datadog | Spike > 5× baseline in 5-minute window |
10. Success Metrics
⭐ Primary KPI: % of Qontak sessions that are correctly terminated within 30 seconds of SSO sign-out
- Baseline: 0% (no detection today)
- Target: ≥ 95% within 30 seconds post-GA
Session Consistency:
switch_userevents resulting in correct company context after autologin: ≥ 99%
Stability:
server_downevent rate: < 0.5% of SDK initializations- Zero regression in existing auth flows when
centralized_sessiontoggle is OFF
11. Dependencies
| Dependency | Owner | Blocker? | Notes |
|---|---|---|---|
Session Manager service deployed at account.mekari.com/sm/* | Account & Launchpad Platform | Yes | SDK will not function without this |
@mekari/sdk package published to npm/internal registry | Account & Launchpad Platform | Yes | FE integration blocked until SDK is stable |
Qontak domains added to SDK's CSP frame-ancestors whitelist | Account & Launchpad Platform | Yes | Iframe security policy blocks cross-origin postMessage without this |
centralized_session feature flag created in LaunchDarkly | Bifrost | Yes | All behavior is gated; must exist before any code ships |
SSO GET /v1.1/users/{user_sso_id}/current_company endpoint available (client_credentials) | Account & Launchpad / SSO | Yes | Required for company sync (SSO-S05) |
| Confirmation of unified logout chain (qontak-launchpad → hub-service → SSO) | Bifrost BE | No — investigation item | Determines whether SSO-S04 needs additional BE work |
12. Key Decisions + Alternatives Rejected
| Decision | Rationale |
|---|---|
| Integrate Platform SDK rather than build custom session validation | The RFC's Session Manager service + SDK provides a shared, scalable solution. Building per-product custom validation would require each product to individually hit SSO Redis, defeating centralization. |
Gate all changes behind centralized_session feature toggle | Session management is critical path. Any regression could lock out users. A toggle allows instant rollback without a code deploy. |
Route logout through account.mekari.com/sign_out (BE-initiated redirect) | SSO sign-out is the authoritative termination point. Qontak-only logout leaves the _mekari_account cookie alive, meaning other products (and the SDK) see the user as still logged in. |
| Keep existing OAuth2/Doorkeeper token system unchanged | The SDK handles session validation; OAuth2 handles API authorization. These are complementary, not competing, concerns. Replacing the token system is out of scope. |
Use switch_user → autologin flow rather than silent session swap | RFC design: product cannot silently assume the new user's identity. A fresh OAuth2 authorization code flow via SSO ensures the new account's tokens are properly issued. |
13. Open Questions
| # | Question | Owner | Status |
|---|---|---|---|
| 1 | What is the concrete timeline for Platform team to deliver @mekari/sdk and Session Manager to staging? Bifrost cannot start Phase 1 without it. | Account & Launchpad PM | Open |
| 2 | Which SDK security model will Platform use: CSP frame-ancestors whitelist OR referrer/origin validation? This determines how Qontak domains are registered and whether a deploy is needed each time a new subdomain is added. | Platform / Infosec | Open |
| 3 | Does the existing unified logout chain (qontak-launchpad-fe → ChatPanel /logout → hub-service) already propagate to account.mekari.com/sign_out after SSO-S03 is implemented, or does qontak-launchpad BE need its own redirect? | Bifrost BE | Open — investigation needed |
| 4 | Should hub-chat's syncSsoCookie() and is_sync_auth seamless auth pattern be deprecated once centralized_session is at 100%? Or are they serving a different purpose (token propagation between hub-chat and CRM)? | Bifrost FE | Open |
| 5 | What is the session.refresh() call throttle interval (TBD in RFC)? Hub-chat makes high-frequency user interactions — this interval affects how often last_request_at is extended in Session Manager Redis. | Platform | Open |
| 6 | Does the centralized_session toggle live in LaunchDarkly, in hub-service's feature flag system, or somewhere else? Who controls it? | Bifrost / Platform | Open |
PRD CHANGELOG
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2026-06-30 | Qontak PM Group | Initial draft based on RFC: Centralized Web Session Between Product and SSO |