X.509 Authentication with Reverse Proxy


I’m trying to set up the following architecture but I’m struggling:

  • Keycloak container with this image jboss/keycloak:7.0.0
  • Apache with mod_auth_openidc
  • The apache has a protected directory
  • Apache does an SSL client Authent

I want to configure the following scenario:

  • A user visits mywebsite/demo
  • Apache prompt him to authenticate with his certificate
  • Apache forward the info to keycloak
  • Keycloak uses X509/Validate Username to validate the certificate (CN)
  • Return the resource to the user once authenticated

I have the following config for Apache vhost :

Listen 8081 https
<VirtualHost *:8081>

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html/

        SSLEngine on
        SSLCipherSuite HIGH
        SSLProtocol all -SSLv3 -TLSv1.3

        SSLCertificateFile /etc/apache2/ssl/serv.crt
        SSLCertificateKeyFile /etc/apache2/ssl/serv.key
        SSLCACertificateFile /etc/apache2/ssl/ca.crt

        <Location /pdf >
                ProxyPass http://mywebsite:5001/pdf
                ProxyPassReverse http://mywebsite:5001/pdf
        #RequestHeader set CERT_CHAIN ""
        RequestHeader set  SSL_CLIENT_CERT ""

        OIDCCryptoPassphrase passphrase
        OIDCProviderMetadataURL https://mywebsite:9004/auth/realms/demorealm/.well-known/openid-configuration
        OIDCClientID demo2
        OIDCClientSecret e6dc781f-49c0-4cfa-9cde-411f9d8bc2cb
        OIDCSSLValidateServer Off
        OIDCRedirectURI https://mywebsite:9998/demo2/redirect
        OIDCRemoteUserClaim preferred_username
        OIDCInfoHook access_token id_token userinfo session

        <Location /demo2 >

                SSLVerifyClient require
                SSLVerifyDepth 2
                #RequestHeader set SSL_CLIENT_CERT_CHAIN_0 "%{{CERT_CHAIN}}s"
                RequestHeader set SSL_CLIENT_CERT "%{SSL_CLIENT_CERT}s"
				#Require ssl

                AuthType openid-connect
                Require valid-user
                Loglevel debug

For the keycloak container, I’m not sure if the container consider my standalone.xml if I mount it instead of the default so I have executed the following jboss commands:

/subsystem=keycloak-server/spi=x509cert-lookup:write-attribute(name=default-provider, value="apache")

My keycloak is configured as follow :
Client redirections :

And the Authentication flow :

But when I visit the websiteas a user “Team XYZ” with certificate CN “Team XYZ” I get this error :
{"error_description":"X509 client certificate is missing.","error":"invalid_request"}

Keycloak Logs :

21:10:24,178 WARN  [org.keycloak.services.x509.AbstractClientCertificateFromHttpHeadersLookup] (default task-49) HTTP header "SSL_CLIENT_CERT" is empty

20:09:48,062 WARN  [org.keycloak.events] (default task-9) type=LOGIN_ERROR, realmId=5c005f6f-a912-4788-bf53-345551eb0e01, clientId=demo2, userId=null, ipAddress=Dummy, error=user_not_found, auth_method=openid-connect, auth_type=code, response_type=code, redirect_uri=https://mywebsite:9998/demo2/redirect, code_id=d2b3aecf-0a53-4d3a-85fd-3433aee61d61, response_mode=query, authSessionParentId=d2b3aecf-0a53-4d3a-85fd-3433aee61d61, authSessionTabId=FqOsf6BrEBk

Can someone please help me, I’ve been stuck with this for days now.

I’ve solved my issue by putting an RP ahead of keycloak, apparently we can’t modify mod_auth_openidc redirection headers.

@sidxzx, does your keycloak just serve to validate a certificate? Could you configure it to shows up a screen for your user to input his certificate?

I don’t think that you can show up a screen to input a certificate.
If mutual HTTPS is configured and the client certificate is installed in the browser store, the user will be automatically prompted to select it.

1 Like

@sidxzx would you please elaborate on putting an RP ahead of Keycloak. In your post, Apache is already an RP and forward the request to Keycloak. What if you have a web application behind apache? How would you pass the access token to the web app?

In my case, my first hop is HAProxy. Do you know if HAProxy can do something similar?


Yes, I think that it is pretty easy to forward the acces token to your web application using Apache.
And it should be possible to do it with HAProxy too.

You can do something like this (Not that the web app is also hosted on an Apache webserver):


I am stuck in a similar situation. I have standalone keycloak and my web application both running behind IIS ARR reverse proxy with URL rewrite. I am trying to implement x509 client-cert based user authentication and map it to the username, then send this info in SAML response to my application to let the user in. User login (in my app via SAML) works just fine with username and password and I get the user all the into my application without an issue but I am unable to get the user in with x509 Client Cert.

My setup is as following (this is all local for now but will be replicating to Win Server 2019 IIS ARR if this works):

  • Self signed certificate for the domain (i.e. www-sample-com)
  • Added www-sample-com to IIS and routing the traffic to localhost:8080 (this is where my application runs)
  • Enabled SSL and client cert authentication of IIS so when you browse to https://www.sample.com from local machine, it prompts for certificate and after validation routes the traffic to my app
  • Added a virtual directory under https://www.sample.com/idp which then goes to localhost:8180 (this is where Keycloak is running)
  • Added reverse proxy inbound rules for both my app and keycloak so when users go to my app the browser address bar shows www-sample-com when they’re in my app and shows www-sample-com/idp/realms/… when they are routed to keycloak for authentication
  • All of this works seamlessly when users are required to use username and password
  • It doesn’t work when I enable X509/Validate Username or X509/Validate Username Form

I end up with the following errors:

{“error_description”:“X509 client certificate is missing.”,“error”:“invalid_request”}

[org.keycloak.events] (default task-3) type=LOGIN_ERROR, realmId=XXXX, clientId=XXXX, userId=null, ipAddress=, error=user_not_found, auth_method=saml, redirect_uri=https://www.sample.com/SSO/assertion, code_id=d5eb72e2-662c-4696-8a89-a4eca435da98, username=jon.snow, authSessionParentId=d5eb72e2-662c-4696-8a89-a4eca435da98, authSessionTabId=wRbWg19A-ZY

P.S I could only put two links in there for some reason so replaced it with (-)