title: Openshift / Keycloak 4.8.3. Login to Admin Console infinite redirect loop
body: <p>I have been using Keycloak for a while from an RPM installation without any issue so far. Now we are migrating most of our services into an Openshift Cluster (3.9). Before migrate the Keycloak to the latest version in my current server (4.8.3) I am making a clean installation in the Openshift Cluster, and here comes the problem.</p>
  
  <p>I am using the official image <strong>jboss/keycloak:latest</strong> inside my Openshift cluster and the POD is up and running. But every time I try to access to the securtiy-admin-console, no matter what browser I use, it goes into an infinite loop after a successful login.</p>
  
  <p>So far this is what I got:
   - Access to the security-admin-console <a href="https://keycloak.openshift.cluster/auth/admin/master/console/#/" rel="nofollow noreferrer">https://keycloak.openshift.cluster/auth/admin/master/console/#/</a> goes into a redirect loop.</p>
  
  <ul>
  <li><p>Access to the user account <a href="https://keycloak.openshift.cluster/auth/realms/master/account" rel="nofollow noreferrer">https://keycloak.openshift.cluster/auth/realms/master/account</a> works fine. <a href="https://i.stack.imgur.com/oD8ve.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/oD8ve.png" alt="Keycloak Account access working fine"></a></p></li>
  <li><p>In the browser console, there is no errors in the login process, but I got an 400 Bad Request when the application tries to refresh the token. This errors comes once I already have a token and I am logged in and Keycloak tries to refresh the session.
  <a href="https://i.stack.imgur.com/2Ubz0.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/2Ubz0.png" alt="Bad Request Error"></a> <a href="https://i.stack.imgur.com/oLU5v.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/oLU5v.png" alt="Authentication error"></a>. </p></li>
  </ul>
  
  <p>After that I got this error in the logs:</p>
  
  <pre><code>17:20:06,765 DEBUG [org.keycloak.authentication.AuthenticationProcessor] (default task-8) AUTHENTICATE CLIENT
  17:20:06,765 DEBUG [org.keycloak.authentication.ClientAuthenticationFlow] (default task-8) client authenticator: client-secret
  17:20:06,765 DEBUG [org.keycloak.authentication.ClientAuthenticationFlow] (default task-8) client authenticator SUCCESS: client-secret
  17:20:06,765 DEBUG [org.keycloak.authentication.ClientAuthenticationFlow] (default task-8) Client security-admin-console authenticated by client-secret
  17:20:06,765 DEBUG [org.keycloak.jose.jws.DefaultTokenManager] (default task-8) Failed to decode token: org.keycloak.jose.jws.JWSInputException: java.lang.IllegalArgumentException: Parsing error
      at org.keycloak.jose.jws.JWSInput.&lt;init&gt;(JWSInput.java:58)
      at org.keycloak.jose.jws.DefaultTokenManager.decode(DefaultTokenManager.java:63)
      at org.keycloak.protocol.oidc.TokenManager.toRefreshToken(TokenManager.java:370)
      at org.keycloak.protocol.oidc.TokenManager.verifyRefreshToken(TokenManager.java:336)
      at org.keycloak.protocol.oidc.TokenManager.refreshAccessToken(TokenManager.java:254)
      at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.refreshTokenGrant(TokenEndpoint.java:462)
      at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.processGrantRequest(TokenEndpoint.java:185)
      at sun.reflect.GeneratedMethodAccessor499.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:140)
      at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:509)
      at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:399)
      at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:363)
      at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
      at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:365)
      at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:337)
      at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:137)
      at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:106)
      at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:132)
      at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:100)
      at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:443)
      at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:233)
      at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:139)
      at org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
      at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:142)
      at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:219)
      at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:227)
      at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
      at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
      at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
      at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
      at org.keycloak.services.filters.KeycloakSessionServletFilter.doFilter(KeycloakSessionServletFilter.java:90)
      at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
      at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
      at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
      at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
      at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
      at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
      at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
      at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
      at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
      at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
      at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
      at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
      at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
      at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
      at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
      at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
      at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
      at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
      at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
      at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
      at org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
      at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
      at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
      at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
      at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
      at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
      at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
      at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
      at org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
      at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
      at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
      at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
      at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1502)
      at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
      at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
      at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
      at io.undertow.server.Connectors.executeRootHandler(Connectors.java:360)
      at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
      at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
      at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
      at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
      at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)
      at java.lang.Thread.run(Thread.java:748)
  Caused by: java.lang.IllegalArgumentException: Parsing error
      at org.keycloak.jose.jws.JWSInput.&lt;init&gt;(JWSInput.java:45)
      ... 76 more
  
  17:20:06,766 WARN  [org.keycloak.events] (default task-8) type=REFRESH_TOKEN_ERROR, realmId=master, clientId=security-admin-console, userId=null, ipAddress=XXX.XXX.XXX.XXX, error=invalid_token, grant_type=refresh_token, client_auth_method=client-secret
  
  17:20:06,766 DEBUG [org.keycloak.services.resources.Cors] (default task-8) Added CORS headers to response
  17:20:06,766 DEBUG [org.keycloak.services.resources.Cors] (default task-8) Added CORS headers to response
  17:20:06,766 DEBUG [org.keycloak.services.resources.Cors] (default task-8) Added CORS headers to response
  
  </code></pre>
  
  <ul>
  <li><p>I created multiple users and always has the same behavior.</p></li>
  <li><p>From the ADMIN-CLI all works fine, I can login and do any operations that the admin-cli allows.</p></li>
  <li><p>In our network, any traffic without TLS/SSL is blocked by default, so we are using a router configured as edge and redirecting the non secure traffic.</p></li>
  </ul>
  
  <p>Regarding the deployment / POD configuration, following the instructions for a docker container, I am adding the following environment variables to the Keycloak deployment:</p>
  
  <ul>
  <li><strong>PROXY_ADDRESS_FORWARDING=true</strong></li>
  <li><strong>KEYCLOAK_USER=admin</strong></li>
  <li><strong>KEYCLOAK_PASSWORD=******</strong></li>
  <li><strong>DB_ADDR=postgres.openshift.cluster</strong></li>
  <li><strong>DB_PORT=5432</strong></li>
  <li><strong>DB_DATABASE=keycloak</strong></li>
  <li><strong>DB_USER=keycloak</strong></li>
  <li><strong>DB_PASSWORD=******</strong></li>
  <li><strong>KEYCLOAK_HOSTNAME=keycloak-it</strong></li>
  </ul>
  
  <p>I checked, and the Openshift router is adding by default the right headers, which are:</p>
  
  <ul>
  <li><strong>X-Forwarded-Host</strong></li>
  <li><strong>X-Forwarded-Proto</strong></li>
  <li><strong>X-Forwarded-Port</strong></li>
  </ul>
  
  <p>Here is the router configuration for the Keycloak POD:</p>
  
  <pre><code>mode http
    option redispatch
    option forwardfor
    balance leastconn
  
    timeout check 5000ms
    http-request set-header X-Forwarded-Host %[req.hdr(host)]
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request set-header X-Forwarded-Proto http if !{ ssl_fc }
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    http-request set-header Forwarded for=%[src];host=%[req.hdr(host)];proto=%[req.hdr(X-Forwarded-Proto)]
    cookie *************************** insert indirect nocache httponly secure
    server pod:keycloak-50-k75pr:keycloak:XXX.XXX.XXX.XXX:8080 XXX.XXX.XXX.XXX:8080 cookie ***************************** weight 256 check inter 5000ms
  
  </code></pre>
  
  <p>The only modification I am doing is to add the CA certificate of my Openshift cluster to the cacert of the container.</p>
  
  <p>My master realm configuration, is the default one, but here is the content:</p>
  
  <pre><code>  [ {
    "id" : "master",
    "realm" : "master",
    "displayName" : "Keycloak",
    "displayNameHtml" : "&lt;div class=\"kc-logo-text\"&gt;&lt;span&gt;Keycloak&lt;/span&gt;&lt;/div&gt;",
    "notBefore" : 0,
    "revokeRefreshToken" : false,
    "refreshTokenMaxReuse" : 0,
    "accessTokenLifespan" : 60,
    "accessTokenLifespanForImplicitFlow" : 900,
    "ssoSessionIdleTimeout" : 1800,
    "ssoSessionMaxLifespan" : 36000,
    "ssoSessionIdleTimeoutRememberMe" : 0,
    "ssoSessionMaxLifespanRememberMe" : 0,
    "offlineSessionIdleTimeout" : 2592000,
    "offlineSessionMaxLifespanEnabled" : false,
    "offlineSessionMaxLifespan" : 5184000,
    "accessCodeLifespan" : 60,
    "accessCodeLifespanUserAction" : 300,
    "accessCodeLifespanLogin" : 1800,
    "actionTokenGeneratedByAdminLifespan" : 43200,
    "actionTokenGeneratedByUserLifespan" : 300,
    "enabled" : true,
    "sslRequired" : "external",
    "registrationAllowed" : false,
    "registrationEmailAsUsername" : false,
    "rememberMe" : true,
    "verifyEmail" : false,
    "loginWithEmailAllowed" : true,
    "duplicateEmailsAllowed" : false,
    "resetPasswordAllowed" : false,
    "editUsernameAllowed" : false,
    "bruteForceProtected" : false,
    "permanentLockout" : false,
    "maxFailureWaitSeconds" : 900,
    "minimumQuickLoginWaitSeconds" : 60,
    "waitIncrementSeconds" : 60,
    "quickLoginCheckMilliSeconds" : 1000,
    "maxDeltaTimeSeconds" : 43200,
    "failureFactor" : 30,
    "defaultRoles" : [ "uma_authorization", "offline_access" ],
    "requiredCredentials" : [ "password" ],
    "passwordPolicy" : "hashIterations(20000)",
    "otpPolicyType" : "totp",
    "otpPolicyAlgorithm" : "HmacSHA1",
    "otpPolicyInitialCounter" : 0,
    "otpPolicyDigits" : 6,
    "otpPolicyLookAheadWindow" : 1,
    "otpPolicyPeriod" : 30,
    "otpSupportedApplications" : [ "FreeOTP", "Google Authenticator" ],
    "browserSecurityHeaders" : {
      "contentSecurityPolicyReportOnly" : "",
      "xContentTypeOptions" : "nosniff",
      "xRobotsTag" : "none",
      "xFrameOptions" : "SAMEORIGIN",
      "xXSSProtection" : "1; mode=block",
      "contentSecurityPolicy" : "frame-src 'self'",
      "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
    },
    "smtpServer" : { },
    "eventsEnabled" : false,
    "eventsListeners" : [ "jboss-logging" ],
    "enabledEventTypes" : [ ],
    "adminEventsEnabled" : false,
    "adminEventsDetailsEnabled" : false,
    "internationalizationEnabled" : false,
    "supportedLocales" : [ ],
    "browserFlow" : "browser",
    "registrationFlow" : "registration",
    "directGrantFlow" : "direct grant",
    "resetCredentialsFlow" : "reset credentials",
    "clientAuthenticationFlow" : "clients",
    "dockerAuthenticationFlow" : "docker auth",
    "attributes" : {
      "_browser_header.xXSSProtection" : "1; mode=block",
      "_browser_header.xFrameOptions" : "SAMEORIGIN",
      "_browser_header.strictTransportSecurity" : "max-age=31536000; includeSubDomains",
      "permanentLockout" : "false",
      "quickLoginCheckMilliSeconds" : "1000",
      "displayName" : "Keycloak",
      "_browser_header.xRobotsTag" : "none",
      "maxFailureWaitSeconds" : "900",
      "minimumQuickLoginWaitSeconds" : "60",
      "displayNameHtml" : "&lt;div class=\"kc-logo-text\"&gt;&lt;span&gt;Keycloak&lt;/span&gt;&lt;/div&gt;",
      "failureFactor" : "30",
      "actionTokenGeneratedByUserLifespan" : "300",
      "maxDeltaTimeSeconds" : "43200",
      "_browser_header.xContentTypeOptions" : "nosniff",
      "offlineSessionMaxLifespan" : "5184000",
      "actionTokenGeneratedByAdminLifespan" : "43200",
      "_browser_header.contentSecurityPolicyReportOnly" : "",
      "bruteForceProtected" : "false",
      "_browser_header.contentSecurityPolicy" : "frame-src 'self'",
      "waitIncrementSeconds" : "60",
      "offlineSessionMaxLifespanEnabled" : "false"
    },
    "userManagedAccessAllowed" : false
  } ]
  </code></pre>
  
  <p>I tried to reinstall many times always from a clean environment and the result is always the same, a loop to access to the main console. Even running the POD / container in privileged mode has the same result.</p>
  
  <p>Could someone help me to check what I am doing wrong? </p>
  
  <p>Thanks a lot in advance.</p>