Third-Party Cookies, FedCM, and What Breaks in Keycloak.js

Guilliano Molaire Guilliano Molaire 13 min read

Last updated: October 2026

Browsers phasing out third-party cookies breaks the patterns keycloak.js has historically used for silent single sign-on and session monitoring. The hidden-iframe “silent check-sso” flow and the OIDC Session Management check-session iframe both depend on the Keycloak session cookie being readable inside a cross-site iframe — which third-party cookie blocking prevents. The practical fixes are: disable the check-session iframe, stop relying on silentCheckSsoRedirectUri in browsers that block cross-site cookies, and fall back to access/refresh token expiry or redirect-based login flows. FedCM (the browser Federated Credential Management API) is the longer-term browser-native replacement for cookie-based federated login, and Keycloak support for it is actively evolving.

How keycloak.js Historically Used Third-Party Cookies

keycloak.js is the official JavaScript adapter for Keycloak. It lets a browser-side application initialize a Keycloak session, check whether the user is already authenticated, and redirect to login when they are not — all without a page reload in the happy path. To pull this off in a purely client-side way, it relied on two browser mechanisms that both depend on third-party cookies.

Silent Check-SSO via Hidden Iframe

When you initialize the adapter with onLoad: 'check-sso' and provide a silentCheckSsoRedirectUri, keycloak.js creates a hidden <iframe> that navigates to the Keycloak server’s /realms/{realm}/protocol/openid-connect/auth endpoint with a special prompt=none parameter. The idea is simple: if the browser already has a valid Keycloak session cookie, the authorization server can silently issue a new token and post it back to the parent frame via postMessage. If there is no session, it posts back a short error and the adapter treats the user as unauthenticated.

The critical dependency: for the iframe to receive that session cookie, the browser must send it as a third-party cookie — the iframe’s origin is the Keycloak server, embedded inside your application’s origin. In browsers that block cross-site cookies by default (Safari has done this since ITP launched in 2017; Firefox via ETP; Chrome began field trials in 2024 and is progressively rolling out deprecation), the session cookie is silently dropped. The Keycloak server sees an unauthenticated request and posts back an error, so the adapter concludes the user is logged out — even when they have an active session on the same Keycloak realm.

OIDC Session Management and the Check-Session Iframe

The second mechanism is the OIDC Session Management spec. After a successful login, keycloak.js can open a second hidden iframe pointing at the Keycloak check_session_iframe endpoint. Your application periodically sends a postMessage with the session state string into that iframe, and the iframe responds whether the session is still active. If the session ends (logout elsewhere, session timeout on the server), the adapter detects the change and can react — for example by silently re-authenticating or forcing a redirect.

This mechanism similarly relies on the iframe having access to the Keycloak session cookie. In a cross-site context, third-party cookie blocking cuts the iframe off from that cookie, so the check-session endpoint cannot evaluate the current session state. The response will be ambiguous or consistently report the session as changed, causing spurious logouts or console errors in your application.

The checkLoginIframe option in keycloak.js (which defaults to true in older versions) controls this behavior.

What Actually Breaks: Symptoms You Will See

When third-party cookie blocking is in effect, the breakage is not always dramatic. It tends to manifest as subtle, hard-to-reproduce issues that vary by browser and user settings.

Silent SSO fails on page load. Applications that call keycloak.init({ onLoad: 'check-sso', silentCheckSsoRedirectUri: '...' }) will find that keycloak.authenticated is false for users who are genuinely logged in. The user then sees the application’s “unauthenticated” state and has to click a login button — even though they have an active Keycloak session.

Spurious logouts mid-session. With checkLoginIframe: true, the adapter polls the check-session iframe. If that iframe cannot read the cookie, it may repeatedly report that the session state has changed. Depending on your onAuthRefreshError handler, this can trigger automatic logouts for active users.

Console errors referencing iframes. You may see errors like "Unhandled Promises", failed postMessage deliveries, or CSP violations if your Content-Security-Policy does not include the Keycloak server in frame-src. These are symptoms, not causes.

Inconsistent behavior across browsers. Safari users see this in every affected session because ITP is always active. Chrome users started seeing it as the deprecation rollout progressed. Firefox users with Enhanced Tracking Protection set to “Strict” see it too. This inconsistency makes the problem especially hard to reproduce in development environments where cookies are same-site.

It is worth noting what does not break: if the user actively logs in via a redirect (login-required or explicit keycloak.login() call), the server issues tokens and the access/refresh token flow works fine. Tokens are stored in memory or sessionStorage on the application’s own origin — not dependent on cross-site cookies. The breakage is specific to the passive, cookie-dependent session probing that the two iframe mechanisms perform.

Practical Mitigations Available Today

These are the established, production-safe approaches for Keycloak 26.x applications dealing with cross-site cookie restrictions.

1. Disable the Check-Session Iframe

Set checkLoginIframe: false in your keycloak.init() call:

const keycloak = new Keycloak({
  url: 'https://auth.example.com',
  realm: 'myrealm',
  clientId: 'my-app',
});

await keycloak.init({
  onLoad: 'check-sso',
  checkLoginIframe: false,
  silentCheckSsoRedirectUri: `${window.location.origin}/silent-check-sso.html`,
});

This stops the adapter from creating the check-session iframe entirely. You lose the ability to detect server-side session termination passively, but you eliminate the main source of spurious logouts and console errors. For most applications this is the right starting point.

2. Use Token Expiry Instead of the Session Iframe for Session State

If you disable the check-session iframe, you still need a way to know when the user’s session ends. The answer is to manage this through the token lifecycle rather than through cookie probing.

The access token has a configurable accessTokenLifespan (default: 5 minutes in Keycloak). The refresh token has a longer ssoSessionIdleTimeout and ssoSessionMaxLifespan. When the access token expires, the adapter calls keycloak.updateToken(minValidity). If the refresh token is also expired or the server-side session has ended, this call fails — and your onAuthRefreshError handler fires. That is the right place to redirect the user back to the login page.

// Proactively refresh the access token before it expires
setInterval(async () => {
  try {
    const refreshed = await keycloak.updateToken(60); // refresh if < 60 sec remaining
    if (refreshed) {
      console.log('Token refreshed');
    }
  } catch {
    // Refresh failed — session is gone; redirect to login
    keycloak.login();
  }
}, 30_000);

This approach is resilient to third-party cookie blocking because the token refresh uses a direct CORS request to the token endpoint, not a cookie-bearing iframe. See our guide on building secure React applications with Keycloak OIDC and PKCE for a complete implementation example.

3. Switch to login-required for Applications That Cannot Tolerate Silent Failure

If your application always requires authentication, switch from check-sso to login-required:

await keycloak.init({
  onLoad: 'login-required',
  checkLoginIframe: false,
});

With login-required, the adapter redirects to the Keycloak login page if the user is not authenticated. There is no silent iframe probe — the redirect is explicit, the session cookie is set in a same-site first-party context on return, and tokens are exchanged directly. This eliminates the silent-SSO problem entirely, at the cost of requiring a redirect on first load for unauthenticated users.

For public-facing applications where unauthenticated browsing is meaningful (landing pages, marketing sites), login-required is too aggressive. For internal tools or SaaS dashboards where every user must be logged in, it is the correct default.

4. Move Session Management to the Backend with a BFF

The most architecturally sound solution for applications that need seamless SSO across a complex deployment is to move session management server-side using the Backend for Frontend (BFF) pattern.

In a BFF architecture, the browser-side application does not handle tokens at all. A thin server layer (Node.js, Next.js middleware, Go service) handles the OIDC redirect flow, stores tokens server-side, and issues its own first-party session cookie to the browser. Because that cookie is set by your own domain, it is a same-site first-party cookie — completely immune to third-party cookie restrictions.

Browser ──── first-party session cookie ────► BFF (your-app.example.com)
BFF    ──── access token (server-to-server) ──► Keycloak / Resource APIs

The browser never touches Keycloak directly, so there are no cross-site cookie dependencies. We cover this architecture in detail in the Keycloak Backend for Frontend (BFF) pattern guide.

For Next.js specifically, the App Router makes this straightforward with Route Handlers. See our Keycloak Next.js App Router authentication guide for implementation steps.

5. Adjust the SameSite and Cookie Configuration on the Keycloak Side

If your Keycloak server and your application share a top-level domain (for example, auth.example.com and app.example.com), you can configure cookies with SameSite=None; Secure to explicitly permit cross-site sending. However, this is exactly the behavior browsers are moving to block, and it requires the user’s browser to accept third-party cookies — which is what you cannot assume. Do not rely on this as a primary mitigation; treat it as a temporary compatibility shim for browsers that still allow third-party cookies, while you implement the token-based or BFF approach above.

The Bigger Picture: What Third-Party Cookie Deprecation Is

For context: browsers introduced third-party cookie restrictions to combat cross-site tracking. Advertising networks and data brokers used third-party cookies to build profiles of users across unrelated websites. The privacy harm was real.

The problem is that third-party cookies were also used for entirely legitimate purposes — including federated identity. The silent check-sso pattern is not tracking: it is checking whether the same user who logged in at auth.company.com has an active session, so they do not have to log in again at app.company.com. But from the browser’s perspective, a cookie being read by an iframe at a different origin is structurally the same pattern — the browser cannot distinguish intent.

Third-party cookie blocking is a blunt instrument that solves the tracking problem but breaks federated login as a side effect. This is precisely the gap that FedCM is designed to fill.

What Is FedCM?

FedCM (Federated Credential Management) is a browser API — currently a W3C draft specification — that gives identity providers a way to participate in federated login flows without relying on third-party cookies or cross-site redirects that expose user behavior to the identity provider.

The core idea is that the browser acts as a privacy-aware intermediary. When a user wants to log in to a relying party using an identity provider:

  1. The relying party calls navigator.credentials.get({ identity: { providers: [...] } }).
  2. The browser — not the page — contacts the identity provider’s FedCM endpoints.
  3. The browser shows its own native account picker UI (not a redirect, not a popup).
  4. If the user consents, the browser mediates the token exchange and returns a credential to the relying party.

Because the browser mediates the flow, the identity provider cannot track which sites the user visits — the browser fetches the IdP manifest and account list itself, without exposing the relying party’s origin to the IdP. From the user’s perspective, login is faster and more privacy-preserving. From the developer’s perspective, the flow does not depend on third-party cookies.

FedCM is already shipped in Chrome and available behind a flag in other browsers. Google Sign-In has migrated to FedCM, which is why you may have noticed the Google account picker appearing as a native browser dialog rather than a popup.

FedCM and Keycloak: Current Status

This is where accuracy matters. As of Keycloak 26.x, native FedCM support in Keycloak is emerging and actively tracked, but not a fully supported, production-ready feature. The Keycloak community has discussed FedCM integration in upstream issues and mailing lists, and there is ongoing work to understand how Keycloak’s provider endpoints would need to change to expose the FedCM-required manifest and account endpoints.

What this means in practice:

  • You cannot currently configure Keycloak as a FedCM identity provider out of the box and expect a production-grade integration.
  • You can experiment with FedCM in Chrome using Keycloak as the IdP by manually implementing the required endpoint contract, but this is not officially supported.
  • The keycloak.js adapter does not yet call navigator.credentials.get with an identity provider — it still uses the redirect/iframe model.

The right thing to do today is check the Keycloak release notes and the upstream GitHub issues for the current FedCM implementation status. This is a fast-moving area and the status will change as browser support and the W3C spec mature.

What is safe to say: FedCM is the direction browsers and major identity providers are moving, and when Keycloak formalizes support, it will provide a path to seamless SSO that does not rely on third-party cookies at all.

Keycloak Configuration Reference for Keycloak 26.x

For readers on Keycloak 26.x who want to audit their current configuration:

// Recommended safe initialization for third-party-cookie-restricted environments
const keycloak = new Keycloak('/keycloak.json');

await keycloak.init({
  onLoad: 'check-sso',           // or 'login-required' if auth is always required
  checkLoginIframe: false,        // disables the check-session iframe entirely
  pkceMethod: 'S256',            // use PKCE — good practice regardless
  // Do NOT set silentCheckSsoRedirectUri if cross-site cookies are blocked in your users' browsers
  // If you still want to attempt silent SSO in browsers that allow it, keep the redirect URI
  // and accept that it will fail silently in Safari/Firefox strict mode
});

In the Keycloak admin console, under your realm’s Tokens tab, review:

  • SSO Session Idle: how long an idle session lives server-side (default: 30 minutes)
  • SSO Session Max: the absolute session ceiling (default: 10 hours)
  • Access Token Lifespan: keep this short (5 minutes) if you are relying on refresh-token-based session detection

Shorter access token lifespans mean the adapter calls updateToken more frequently, which gives you faster detection of server-side session expiry without relying on cookie-dependent iframes. The tradeoff is more token refresh requests to the server.

For a deeper look at how cookies and tokens compare as session state carriers across distributed services, see our post on session management in distributed systems, and for a full SSO implementation walkthrough see the SSO implementation guide for developers.

What to Do Today: Checklist

Use this to audit your Keycloak.js integration now, before third-party cookie deprecation affects more of your users:

  • Audit your keycloak.init() calls. If any of them set checkLoginIframe: true (or rely on the default), change to checkLoginIframe: false.
  • Remove or replace silentCheckSsoRedirectUri. Silent SSO via hidden iframe should not be your primary session-check strategy. Replace it with token-expiry-based session detection.
  • Add an onAuthRefreshError handler. This is the correct signal that the server-side session has ended. Redirect to keycloak.login() from inside it.
  • Test in Safari and Firefox with strict tracking protection. These browsers have blocked third-party cookies for years. If your app works correctly in them today, you are already in good shape for Chrome’s deprecation rollout.
  • Consider the BFF pattern for new applications. If you are building a new SPA or migrating to a framework like Next.js, architect session management in the server layer from the start. It is more secure and avoids the entire class of cross-site cookie problems.
  • Monitor Keycloak release notes for FedCM progress. When Keycloak ships FedCM support, it will be the cleanest long-term path to browser-native federated SSO without cookie workarounds.
  • Update your CSP frame-src directive. If you have disabled iframe-based flows, you may no longer need frame-src entries for your Keycloak server. Removing unnecessary frame permissions reduces your attack surface.

Frequently Asked Questions

Does third-party cookie removal break Keycloak?

Third-party cookie removal does not break Keycloak itself or its token endpoints — it breaks the iframe-based session probing mechanisms in keycloak.js. Specifically, the hidden-iframe silent check-sso flow and the OIDC Session Management check-session iframe both rely on the Keycloak session cookie being sent in a cross-site context. When browsers block that, those flows fail silently. The fix is to disable these mechanisms and rely on token-based session management instead.

What is checkLoginIframe in keycloak.js?

checkLoginIframe is a keycloak.js initialization option (default true in older adapter versions) that controls whether the adapter creates a hidden iframe pointing at Keycloak’s check_session_iframe endpoint. The iframe polls for session state changes — useful for detecting logouts initiated elsewhere. In browsers that block third-party cookies, this iframe cannot read the Keycloak session cookie and will report false session-state changes, causing spurious logouts. Setting checkLoginIframe: false disables the iframe. Session expiry should then be detected via updateToken failure and the onAuthRefreshError callback.

What is silentCheckSsoRedirectUri and should I still use it?

silentCheckSsoRedirectUri is a path on your application (typically /silent-check-sso.html) that keycloak.js loads inside a hidden iframe when onLoad: 'check-sso' is set. The iframe navigates to Keycloak with prompt=none; if a session exists, Keycloak posts a token back. This mechanism depends on the browser sending the Keycloak session cookie from within the cross-site iframe. In browsers with third-party cookie blocking, the cookie is not sent and the check always returns unauthenticated. You can continue providing the redirect URI as a graceful fallback for browsers that still permit third-party cookies, but it should not be your only session-check strategy. Pair it with checkLoginIframe: false and token-expiry detection.

Does Keycloak support FedCM?

As of Keycloak 26.x, FedCM support is emerging and under active development, but it is not a fully supported production feature. Keycloak does not yet ship built-in FedCM endpoints or keycloak.js FedCM integration out of the box. The upstream community is tracking this, and the status will change as the W3C FedCM specification matures and browser support broadens. Check the current Keycloak release notes and the project’s GitHub for the latest status before planning a FedCM integration.

Is the BFF pattern the right fix for all applications?

The Backend for Frontend pattern is the most robust fix because it moves session management entirely server-side, using first-party cookies that are never affected by cross-site restrictions. However, it adds infrastructure complexity: you need a server layer between the browser and your APIs, and you need to manage token storage and refresh server-side. For simple SPAs or internal tools where you control the browser environment, disabling checkLoginIframe and using token-expiry detection may be sufficient. For customer-facing applications, multi-tenant SaaS products, or applications where seamless SSO across multiple subdomains is a requirement, the BFF pattern is the right architectural investment.

Conclusion

The third-party cookie deprecation wave is not a hypothetical future problem — Safari and Firefox have enforced cookie restrictions for years, and Chrome’s progressive rollout is bringing the same constraints to the majority of browser traffic. If your application relies on keycloak.js with checkLoginIframe: true or a silentCheckSsoRedirectUri-based silent SSO flow, it is already failing for a meaningful portion of your users.

The near-term fixes are well-established: disable checkLoginIframe, rely on updateToken failure for session expiry detection, and redirect users to login explicitly when their session ends. For new applications, design session management server-side from the start. FedCM is the browser ecosystem’s long-term answer to this problem, and when Keycloak formalizes support, it will offer a cleaner path — but that work is still maturing.

Running Keycloak in production while tracking these changes, managing upgrades, and keeping your authentication flows compatible across browsers takes real operational effort. Skycloak’s managed Keycloak platform handles the infrastructure so your team can focus on the application layer.

Guilliano Molaire
Written by Guilliano Molaire Founder

Guilliano is the founder of Skycloak and a cloud infrastructure specialist with deep expertise in product development and scaling SaaS products. He discovered Keycloak while consulting on enterprise IAM and built Skycloak to make managed Keycloak accessible to teams of every size.

Ready to simplify your authentication?

Deploy production-ready Keycloak in minutes. Unlimited users, flat pricing, no SSO tax.

© 2026 Skycloak. All Rights Reserved. Design by Yasser Soliman