Keycloak is installed in the kubernetes cluster as part of QHub and it manages all users and groups, plus OAuth2 authentication for other QHub components such as JupyterHub and Conda Store.
Sometimes you want a simple way to isolate and play around with Keycloak separately from QHub as a whole, but also want it to be configured in a similar way to Keycloak when part of QHub.
Run Keycloak in Docker#
The Docker image is an easy way to get a standalone local Keycloak instance.
docker run -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin \ --name keycloak --rm -v keycloakdata:/opt/jboss/keycloak/standalone/data \ quay.io/keycloak/keycloak:15.0.2
Note: the volume mount (-v flag) should allow data to persist when you stop and start the container.
You can now visit the Keycloak admin panel at http://localhost:8080/auth/ and login with username and password both as
When deployed within QHub, Terraform code will configure Keycloak in a certain way. Here we attempt to perform similar configuration, but of course check the code for the latest config.
Create QHub Realm#
Once you’ve signed in, create a new realm. In the upper left portion of the admin console, you should see
which is the default realm. Hover over
Master and a dropdown should appear with a button labeled
Add realm. Click
that button. You should be taken to a form to create a new realm. Name the realm
qhub (case sensitive) and click the
Create button. The admin console should now be in the qhub realm, as reflected in the upper left of the UI.
Add groups and rules#
All QHub deployments will have
admin groups. For development, you need to add them manually. Click
Groups on the side nav, and
New - enter the name
users in lower case. Then do the same for
users group also needs to be configured so that it is a default group assigned to any new users. To do this, click
Default Groups tab within the
Groups page. Click
users in the list of Available Groups, then
Add to move it
to the list of Default Groups on the left.
Create an OAuth 2 client#
Within the qhub realm, you will create a new client. Within QHub, a separate client exists for each of jupyterhub,
conda-store, dask etc. In the side nav, click
Clients, then click the
Create button. Fill out the form as show
Save, you will be taken to the client settings form. Make sure the form fields are filled in as
Valid Redirect URIs
The redirect URI you use here will depend on how you want to test OAuth2 login flows. The example above would make sense if you are running your OAuth2 client (e.g. JupyterHub or Conda Store) at port 7010 locally, and it happens to have its callback URL at the path
If you plan to test using Postman (see below) the callback will be
You will next create a new mapper for the
myclient client. Go to the
Mapper tab and click the
Create button. Make
sure the form is filled out as shown below and then click the
Token Claim Name
Full group path
Add to ID token
Add to access token
Add to userinfo
Update: You may also want to set mappers for roles, which are now used for conda-store and dask.
Create Qhub login#
You will now create a new user. This will be the user that you use to sign in to the Qhub control panel (which is separate from the Keycloak admin sign in).
In Keycloak, go to
Users in the side nav and click
Add user. Give the user any username that you want (for these
instructions, we will assume
quser) and click
Save. Go to the
Credentials tab, toggle off the
and set a password for your user (we will assume
quser for the password).
In order for your new user to access the Qhub control panel, they must belong to the admin group. Go to
Users in the
side nav, click
View all users, find your user, then click
Edit under the
Actions column. Go to the
Available Groups, you should see
admin. Click on
admin then click
Join. You should see the
Group Membership box update with
Understanding JupyterHub OAuth2#
For example, for login to JupyterHub in QHub, the OAuth2 flow works as follows:
JupyterHub redirects to Keycloak at this URL:
https://myqhub.net/auth/realms/qhub/protocol/openid-connect/authwith some extra parameters including the client ID of jupyterhub to say which client should be authenticated.
Keycloak redirects to the callback
https://myqhub.net/hub/oauth_callbackplus a short auth code.
JupyterHub makes a server-to-server call to
http://localhost:8080/auth/realms/qhub/protocol/openid-connect/tokenin order to exchange that code for a more permanent access token.
JupyterHub then also makes a server-to-server call to
http://localhost:8080/auth/realms/qhub/protocol/openid-connect/userinfo(passing the access token as authentication) in order to obtain extra information about the user. This step is generally optional in OAuth2.
If you check JupyterHub’s logs you may see the results of the userinfo call - which should contain a list of groups due to the group mapper that was configured earlier. It may also contain email address etc.
A similar flow happens for the other clients too (conda store etc).
Testing OAuth2 using Postman#
Without having to run a service such as JupyterHub to see, for example, that our group mapper is working, it is possible to test the login flow independently. It would be possible using curl, but it takes a lot of effort to fully understand all the parameters needed at each stage.
Postman is an application for experimenting with APIs. It can run in your browser (which works best if you also install the ‘Postman Agent’ to run on your computer), or you can install a native Mac app. See Postman’s website.
You can use Postman to try out the OAuth2 flow of a standalone Keycloak instance (in this example, running using Docker locally, as described above).
Create a client within the qhub realm, as described above (for
myclient). Going forward, let’s assume the client is
postman and you registered it with the callback URL
https://oauth.pstmn.io/v1/browser-callback (which is what
Postman uses for this purpose).
In the Postman app, go into a workspace (My Workspace is the default) and open a new ‘request tab’ in the main working area of the screen.
In the big box at the top, next to GET, enter
In the Authorization tab change ‘Type’ to ‘OAuth 2.0’.
Then ‘Configure New Token’ using the defaults plus the following:
Access Token URL:
postman(or whatever you chose)
Client Secret: This is a guid-like string available from the Credentials tab of your Client in Keycloak
Click the ‘Get New Access Token’ button. You will be prompted to sign into Keycloak (use the user you created in ‘Create QHub login’ above, not the admin user).
This should result in an access token being displayed. Click the ‘Use Token’ button.
Now your authentication is ready and you can use it to call the userinfo API.
Click the blue ‘Send’ button towards the top of the window, next to the main userinfo URL.
The JSON results should be visible at the bottom of the window. If the group mapping was configured successfully, this
should include a
groups field listing any groups the user has joined.