Custom authorization implementation in Keycloak using Nginx
This topic would be multipurpose. I want to tell you about a powerful web-server, script programming language, and an identity provider. A lot of material already been written about Nginx. Nginx is a lightweight web-server, proxy, reverse-proxy, mail-proxy, gateway, and supports Lua scripts. Lua is a JIT-compiled programming language with light syntax. You can overview these language features at this site. There is an out-of-the-box solution with Nginx and Lua - Openresty. It exists as Win/Mac/Linux builds as well as Docker image. I want to show how you can use Nginx with Lua/Openresty for the simple case below.
The client doesn’t support OAuth authorization and can provide information only as static request headers. We have KeyCloak as the identity provider and have restricted access for k8s/Openshift cluster. We need to intercept client requests, authorize them, add additional information and send it to the necessary endpoint. We’ll use client id and secret for authorization, but you feel free to use Basic authorization type.
Keycloak client creation
First of all, we need to create a realm in KeyCloak. If you need multi-tenancy in your application, you should create separate realms for each tenant. You can also create a realm for utility application in your cluster.
The next step is Client creation. You must set required fields, can grant business roles. Don’t forget to save the client’s secret and id. We’ll use them later.
You can get more information about OIDC Clients in the official documentation chapter 8 Managing Clients.
Nginx preparation
Enable Lua in nginx.conf:
In additional we need two external modules: http, json.
You can keep it locally and copy in the docker container or install it with LuaRocks.
If we are intercept requests and send authorization in KeyCloak, we’ll have token regeneration for each one. It would be ok in some cases, but let’s reduce KeyCloak compute resource usage and create cache storage in our proxy. In the http section of nginx.conf initialize the global variable. This variable will contain key-value pairs. Where key - unique identifier of client and value is current access token.
In server block set reverse-proxy paths and rewriting request by Lua script.
All requests sent on {servername}/in would be processed by a script called with require. If no error happens, it sents to the proxy_pass path.
Lua request processing
We need to create the file with a name that we are defined above. In convertor.lua defines the anonymous function:
After that, get our custom cache and assign to the local variable.
The next step is getting KeyCloak client information from request headers. In this example I’ll use three headers without any encryption. This is not secure rather with https, use Authorization header for the such sensitive information!
Then call KeyCloak REST API via http module:
Try get token from cache and validate it with calling userinfo:
If response have no 200 code, call API for a new token creation:
Then parse response JSON and get the new token.
The last step is setting new token to the cache, set it to the Authorization header, and remove old headers with the sensitive information.
Let’s see how it works. I’ll use docker-compose for running KeyCloak, Openresty, and Spring Boot application as backend. All applications define as services with required settings in docker-compose.yml. All docker images build previously.
The main thing is setting one own network here. You can create a local docker network via
And then, you need to define docker host IP instead of localhost in configurations and applications. In this case, all services with mybridge can have cross-container communication. We can test our proxy. In Postman, set headers (realm, client, secret) and send the request.
All things can be simpler, but you can find your case when you can apply this knowledge.
Source code is available on github.