Single sign-on like the big guys

Authenticate Anything

Configuration and User Creation

Now you'll need configurations for:

  • A test authentication realm
  • A client for the native application
  • A client for the application authenticated through a proxy
  • A user that will log in against both clients

It might sound counterintuitive, but in Keycloak-speak a client is an application that authenticates against Keycloak, so always remember that when a client is mentioned, it can refer also to a service or server and not just to front-end web apps.

Once you are logged in, mouse over the Master section in the upper left corner and click Add realm ; enter testrealm as a name and submit.

Next, go to the Clients section and click Add Client , set the Client ID to native , and set the Root URL to http://localhost:5000 before clicking Save . Once the settings are saved, switch the Access Type to confidential and save again.

Now repeat the last (add client) procedure, but this time set the Client ID to proxy and the Root URL to http://localhost:4180 . Additionally, click on the Mappers tab and create a mapper called audience , of Audience type, and select proxy as the included target audience.

Finally, go to the Users section, click Add User , and fill in the form with anything you like (Figure 1). Set both Enabled and Email Verified to ON , then click Save . Before leaving this section, click on the Credentials tab and set a password for your newly created user.

Figure 1: User details on the Keycloak admin user interface.

A Native Authentication App

Keycloak used to provide libraries for several languages called Adapters . Since February 2022 they have been discontinued because a robust availability of independent OAuth2 and OIDC libraries has been reached.

As an example, I'll set up a Python app that uses Flask and the Flask-OIDC module. You'll need Python 3.8 or later, PIP, and Python-venv. On Ubuntu or Arch Linux type,

apt install python3 python3-venv python3-pip
pacman -S python python-pip

respectively. Now create a file named with the content of Listing 2 and another called oidc-config.json with the content of Listing 3.

Listing 3


01 {
02    "web": {
03      "client_id": "native",
04      "client_secret": "hu5t82LXfYKtr3XFcPeAYaCBWFK8DcI1",
05      "auth_uri": "http://localhost:8080/realms/testrealm/protocol/openid-connect/auth",
06      "token_uri": "http://localhost:8080/realms/testrealm/protocol/openid-connect/token",
07      "issuer": "http://localhost:8080/realms/testrealm",
08      "userinfo_uri": "http://localhost:8080/realms/testrealm/protocol/openid-connect/userinfo",
09      "redirect_uris": [
10        "http://localhost:5000/oidc/callback"
11      ]
12    }
13  }

Listing 2 (Native)

01 # Import dependencies
02 from flask import Flask, g
03 from flask_oidc import OpenIDConnect
05 # Create a Flask app and set the OpenID connect config params
06 app = Flask(__name__)
07 app.secret_key = 'hu5t82LXfYKtr3XFcPeAYaCBWFK8DcI1'
08 app.config['OIDC_CLIENT_SECRETS'] = 'oidc-config.json'
09 app.config['OIDC_COOKIE_SECURE'] = False
11 # Instantiate a flask_oidc object that will be used to handle the authentication flow
12 oidc = OpenIDConnect(app)
14 # Function decorators to set the app route and the required login
15 @app.route('/')
16 @oidc.require_login
17 def index():
18    # Check if user is authenticated
19    if oidc.user_loggedin:
20        # If user is authenticated, run this code
21        return 'Welcome %s' % oidc.user_getfield('preferred_username')
22    else:
23        # If he's not, run this code
24        return 'Not logged in'

Note that for the authentication flow to work, you must replace line 7 of Listing 2 and line 4 of Listing 3 with the client key found in the Credentials tab of the Keycloak native client created for this example.

To create the environment to run the application, enter

python -m venv .venv && source .venv/bin/activate
pip install flask flask-oidc itsdangerous==2.0.1

and run the application with the flask run command before heading to http://localhost:5000 .

If everything was done correctly, you should be redirected automatically to the Keycloak instance, where you are asked to authenticate. If the authentication is successful, you will be brought back to the sample application, where the username is printed (Figure 2).

Figure 2: After authentication, the app returns your username.

As you may have guessed, the application will have access to a wide range of information on the authenticated user. Such information can be used to template your app or apply further conditions according to the user roles (authorization).

Authentication by Proxy

Sometimes you cannot customize the application for the described mechanism to be implemented, as could certainly be the case for proprietary applications or scenarios where messing with the code is simply not possible. In this case, you can use a reverse proxy that performs the authentication flow on behalf of the application it's serving, forwarding only requests from logged-in users (Figure 3).

Figure 3: The authentication flow.

One example is OAuth2 Proxy [3], a mature project that aims to provide a layer of authentication in front of an existing application. It doesn't necessarily features all the bells and whistles of more renowned solutions such as Nginx, but it can be used in conjunction with it and is natively cloud friendly, providing Docker images and Kubernetes operators.

To test OAuth2 Proxy, I'll first write a trivial web app (Listing 4) and, as before, run it with

flask run -p 9190

Listing 4 (Proxied)

01 from flask import Flask, g
02 app = Flask(__name__)
03 @app.route('/')
04 def hello():
05    return("Hello world")

The app is now freely accessible at http://localhost:9190 .

To add the authentication layer, you will need to create an OAuth2 Proxy config file (Listing 5) modifying the client_id and client_secret with the information from the Keycloak proxy client created earlier. The reason for setting the audience mapper is that OAuth2 Proxy expects said OIDC field valued with the same name of the configured client_id.

Listing 5


# Ports to listen to
http_address = ":4180"
redirect_url = "http://localhost:4180/oauth2/callback"
# The http url(s) of the upstream endpoint.
upstreams = [
# Accept requests from all user email domains
email_domains = "*"
# Keycloak configuration
oidc_issuer_url = "http://localhost:8080/realms/testrealm"
provider = "keycloak-oidc"
client_id = "proxy"
client_secret = "t1BmFL4HHk7xC6nPYJEMfiprMfw1QK7b"
# Cookie settings
cookie_name = "_oauth2_proxy"
cookie_secret = "4235342623623623"

Now spin up an instance of the service through a convenient Docker container:

docker run --network host -v $(pwd)/oauth2proxy.conf:/etc/oauth2-proxy.cfg bitnami/oauth2-proxy:7.2.1 --config=/etc/oauth2-proxy.cfg

Point your browser at http://localhost:4180 . If everything went according to the plan, you should be asked by OAuth2 Proxy to authenticate (Figure 4). After a successful procedure, you should be brought back to the trivial "Hello World" app.

Figure 4: OAuth2 Proxy starting the authentication flow.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Single sign-on with Keycloak
    Google and Facebook are two of the biggest providers for single sign-on on the web, with OAuth2 and OpenID, but if you don't want to put your customers' or employees' data in their hands, Red Hat's Keycloak software lets you run your own operations with the option of integrating existing Kerberos or LDAP accounts.
  • Registry for Docker images
    Running your own registry for Docker images is not difficult. We'll show you how to get started using the free docker_auth software.
  • Azure AD with Conditional Access
    Trust is good, but controls are better. As more flexible working models become widespread, the boundaries of the classic perimeter are blurring and softening existing models of trust for adopting cloud software and data storage or running domain controllers or core applications in the cloud.
comments powered by Disqus
Subscribe to our ADMIN Newsletters
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs

Support Our Work

ADMIN content is made possible with support from readers like you. Please consider contributing when you've found an article to be beneficial.