Keycloak Integration : Part 3: Integration with Python ( Django ) Backend

Logo courtesy http://keycloak.org and http://djangoproject.com.

Keycloak is an Open Source Identity and Access Management For Modern Applications and Services. We will cover the building blocks of integrating keycloak with a python based web application. Taking Django as an example, but most of the concepts and libraries used are python generic.

Previously

Acceptance Criteria

  • REST API(s) exposed by backend need to be protected based on which user can access which endpoint (authorization scope)
  • We are not going to cover controlling login into the web application here. For a full stack Django application (frontend and backend), this library may be useful

Problems with Python integration

  • If we google for python integration with Keycloak, there are so many reference implementations. Keycloak documentation points to a generic OpenId Connect implementation, which is super hard to understand and get it working.
  • The following approach is my pick of libraries to integrate Keycloak with Python. But the core concept remains neutral across libraries.

Pre-requisites (Keycloak side)

Reusing Keycloak client across frontend and backend

One approach to simplify life. It may not be application in all scenarios.

Let’s say, if we have an Angular Frontend and a Django backend application. We could have a single Keycloak client and use the same configurations (Client Id, Client secret). If there is need for redirect to django, Keycloak supports multiple Redirect URL(s).

How this simplifies:

  • The same access token can be used by both Frontend and Backend
  • When frontend passes the token that it has to backend REST API, if they both belong to the same client, unpacking the token is much easier and valid. Else we may face JWT signature issues.

Pre-requisites (python side)

  • Python dependencies
# KeyCloak integration
python-keycloak==0.12.0
python-jose==3.0.0
  • We need a Middleware to handle request, parse the token, take Authorization decisions (whether to allow access or not)
  • Add client id, client secret and other keycloak details to the settings
# Excempt list - URL paths that doesn't need Keycloak Authorization 
KEYCLOAK_BEARER_AUTHENTICATION_EXEMPT_PATHS = [
'admin', 'accounts',
]
CONFIG_DIR = os.path.join(os.path.dirname(__file__),os.pardir)
KEYCLOAK_CLIENT_PUBLIC_KEY = """-----BEGIN PUBLIC KEY-----
...Your public key here...
-----END PUBLIC KEY-----"""
KEYCLOAK_CONFIG = {
'KEYCLOAK_REALM': 'your-realm',
'KEYCLOAK_CLIENT_ID': 'your-client',
'KEYCLOAK_DEFAULT_ACCESS': 'ALLOW', # DENY or ALLOW
'KEYCLOAK_AUTHORIZATION_CONFIG': os.path.join(CONFIG_DIR , 'authorization-config.json'),
'KEYCLOAK_METHOD_VALIDATE_TOKEN': 'DECODE',
'KEYCLOAK_SERVER_URL': 'http://KEYCLOAK_HOST:8088/auth/',
'KEYCLOAK_CLIENT_SECRET_KEY': 'your-secret-key',
'KEYCLOAK_CLIENT_PUBLIC_KEY': KEYCLOAK_CLIENT_PUBLIC_KEY,
}
  • The public key should be exactly in the above format, like beginning with — BEGIN PUBLIC KEY and line breaks. Else python-keycloak library that we use will through error that will have no relationship with the root cause :)
  • In the above settings, we have mentioned `KEYCLOAK_AUTHORIZATION_CONFIG` pointing to a json file. We will discuss about this little later in this article.
  • We could also see a Exempt list of URL paths that doesn’t need Keycloak.

Django Middleware

Though we are mentioning Django, the core concept remains same for any python web framework.

I like django-rest-framework-keycloak repository. But there are few scenarios, that I would like to have in our middleware. Here is a slightly modified version of django-rest-framework-keycloak’s middleware :

  • Add the middleware as a django middleware in settings

Authorization Scopes

For each REST endpoint, we could add finer access control by defining a keycloak scope. Later we will update Keycloak to handle these scopes based on user role.

Pre-requisites for implementing Authorization flow

  • Reading Authorization sevices guide is a must before we dive further. We will see one way of achieving authorization. There are so many other combinations in which we can achieve our goal. To start with, let’s keep it simple and see a simple but concrete way.
  • In keycloak client settings, switch `Authorization Enabled`. Once this is done, a new Authorization tab will appear.

Our simplified authorization flow :

  • Let’s define our Authorization scopes like inventory:view, inventory:add etc.,
  • Let’s define Permissions for the above scopes and attach a role based policy. In other words, based on user role, allow a specific scope (eg: inventory:add)

Let’s Add authorization details for Keycloak

Add different scopes that we like to have
After adding required scopes, our Authorization scopes will look something like this
Let’s create application specific roles inside our client

The above screen shows, roles created inside a client. It could also be roles created under the realm, based on application needs, this will differ.

Add a role based policy

Now Let’s define a Permission which will map a Policy to a Authorization scope

Scope based Permission

There are two types of permissions (Resource and Scope). We are using Scope based permissions for simplicity.

For users with ‘normal user’ role, allow only read only access

Exporting and importing the authorization settings

For python, I couldn’t find a simpler way of fetching these informations from Keycloak matching my needs.

  • For each request, we don’t want to send a request to Keycloak to fetch authorization settings, since they don’t change that much.
  • Fetching programmatically from python, involves exposing keycloak user credentials to python. This doesn’t look right.
  • A simpler approach would be to export the authorization settings as a json and pass it to python-keycloak library during server start
export authorization setings to json

Summary

KeyCloak is a well thought identity management solution. Flexibility that it offers in solving many complex problems in Authentication and Authorization is simply amazing. Will keep you posted on issues that I face using Keycloak. Till then, happy coding.