DEV Community

Cover image for 🔁 Fixing Keycloak Auto-Redirect on Refresh: Persist Authentication in SPAs
Raj Aryan
Raj Aryan

Posted on

🔁 Fixing Keycloak Auto-Redirect on Refresh: Persist Authentication in SPAs

If you're using Keycloak in a React, Vue, or vanilla JS app and your users are being forced to log in again after every page refresh, you're not alone.

This post explains why it happens, and shows you how to persist authentication with clear examples and best practices.


🔍 The Problem

By default, keycloak-js stores your tokens (accessToken, refreshToken, idToken) in memory only.

So when your Single Page App (SPA) reloads:

  • The tokens are gone
  • The user appears logged out
  • Keycloak redirects to login again

✅ Solution 1: Store Tokens in Local/Session Storage

Step 1: Save Tokens After Login

keycloak.init({ onLoad: 'login-required' }).then((authenticated) => {
  if (authenticated) {
    localStorage.setItem('kc_token', keycloak.token);
    localStorage.setItem('kc_refreshToken', keycloak.refreshToken);
    localStorage.setItem('kc_idToken', keycloak.idToken);
  }
});
Enter fullscreen mode Exit fullscreen mode

Step 2: Restore Tokens on Page Load

const keycloak = new Keycloak({
  url: 'https://your-keycloak-domain/auth',
  realm: 'your-realm',
  clientId: 'your-client-id',
});

const token = localStorage.getItem('kc_token');
const refreshToken = localStorage.getItem('kc_refreshToken');

keycloak.init({
  onLoad: 'login-required',
  token,
  refreshToken,
}).then((authenticated) => {
  if (!authenticated) keycloak.login();
});
Enter fullscreen mode Exit fullscreen mode

Step 3: Auto-Refresh the Token

setInterval(() => {
  keycloak.updateToken(70).then((refreshed) => {
    if (refreshed) {
      localStorage.setItem('kc_token', keycloak.token);
      localStorage.setItem('kc_refreshToken', keycloak.refreshToken);
    }
  }).catch(() => {
    console.error('Token refresh failed');
    keycloak.logout();
  });
}, 60000);
Enter fullscreen mode Exit fullscreen mode

⚠️ Security Considerations

Storage Pros Cons Security Level
localStorage Easy to use, persists reloads XSS vulnerable 🔓 Low-Medium
sessionStorage Safer (cleared on tab close) Less persistent 🔒 Medium
HttpOnly Cookies Most secure, no JS access Requires backend setup 🔐 High

✅ Best Practices

  • Use CSP headers
  • Sanitize all inputs
  • Avoid innerHTML
  • Prefer sessionStorage unless persistence is a must

🛠 Solution 2: Use Silent SSO (check-sso)

If you don’t want to manually store tokens, use silent SSO.

Create silent-check-sso.html

<!DOCTYPE html>
<html>
  <body>
    <script>
      parent.postMessage(location.href, location.origin);
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Update Your Init

keycloak.init({
  onLoad: 'check-sso',
  silentCheckSsoRedirectUri: window.location.origin + '/silent-check-sso.html',
}).then((authenticated) => {
  if (!authenticated) keycloak.login();
});
Enter fullscreen mode Exit fullscreen mode

Heads up: Some browsers block third-party cookies, which can break Silent SSO in cross-domain setups.


🔐 Solution 3: Use HttpOnly Cookies (Backend Required)

For production-level security, handle tokens server-side with HttpOnly cookies.

Why?

  • Tokens can’t be accessed via JS (safe from XSS)
  • Automatically attached to requests
  • Requires your backend (Node, Django, etc.) to manage tokens

This is ideal for highly secure applications or enterprise needs.


✅ Summary

Method Use when...
localStorage Simplicity is more important than security
sessionStorage You want better security, no persistence
Silent SSO You prefer not storing tokens at all
HttpOnly Cookies You’re building a secure, production-grade app

🔗 Resources


Top comments (2)

Collapse
 
scandinave profile image
Romain LE BARO • Edited

This is completly wrong and dangerous. Never store token in local, session or cookie. it is not secure. Keycloak-js don't do it for a good reason. If the user refresh the page, the token is lost, that is true. But this is not a problem as soon as your application redirect the user to keycloak. Keycloak will then read its own cookie, emit a new token and redirect back the user to the application almost instantly.

Solution 3, just break the entire openid connect thing by forcing the user to send its credential to the bakend and losing sso feature.

So if you have the problem describe in this article, just make your application do the redirect.

Collapse
 
er-raj-aryan profile image
Raj Aryan

Thank you for your comment — you’ve raised valid concerns about token security, and we completely agree that blindly storing tokens in localStorage or sessionStorage without proper safeguards can be dangerous. That’s exactly why Keycloak-js avoids doing so by default.

However, in complex SPA environments — particularly where routing and seamless user experience are critical — relying solely on Keycloak’s default redirect-based login flow may not always be practical. Controlled token persistence, if implemented correctly, can prevent unnecessary logins on refresh without breaking the OpenID Connect flow.

It’s also important to consider that many modern browsers are now blocking Keycloak’s silent refresh mechanism (via hidden iframes), especially when Keycloak is hosted on a different domain — a common setup in microservice architectures. In such setups, iframe-based token renewal fails due to third-party cookie restrictions, leaving users stuck or logged out.

To address this, we use a strongly encrypted storage approach that ensures tokens are not stored as plain text and are inaccessible to unauthorized scripts — mitigating the risk of token theft via XSS. Combined with strict CSP headers and robust input sanitization, this approach balances usability with security.

That said, we fully support redirect-based login as the most secure out-of-the-box option. Our solution is an alternative for edge cases — meant for experienced teams who understand the trade-offs and implement rigorous security practices.

Appreciate your input — it’s a vital part of evolving secure SPA authentication strategies!