Keycloak with Go web-services. Why not?
Building web-services in Golang is getting more and more popular, especially for new projects. But sometimes it can be a bit challenging for those who came from another programming world (like me) and might seem not so comfortable in the beginning, mostly due to lack of some libraries, frameworks and tools one get used to.
In my recent micro-service project written in Go we had to implement centralized user management and Single Sign On (SSO). After some analysis of available open-source Identity And User Management systems we came up with Keycloak that seemed to satisfy all our requirements and looked quite mature and stable solution among counterparts. I don’t want to list all its features. There are plenty of good articles and detailed overviews available online, so you can easily get familiar with this product and its wide functionality.
This post is aimed to give you an introduction guide how to start with authentication/authorization of your Go web-service with Keycloak. Hope it will be helpful.
To keep my post as short as possible I intentionally omit most of the details about Keycloak installation on my local environment. There are a detailed guide in the official documentation with thorough descriptions of all installation options.
My choice is getting started with an official docker image which is pretty straightforward. Here is my docker-compose configuration
Note, I specified Keycloak predefined admin credentials as environment variables (please refer to Keycloak docker documentation).
My local Keycloak server is now available on localhost:8086. So, I suppose here you have Keycloak up and running and can access Admin Console.
The target picture we are going to come up in this guide is the following:
So, to authenticate users our web-service exposes /login endpoint which passes user’s credentials, requests authentication in Keycloak and if credentials are valid responses with access and refresh tokens. Another endpoint requires authorization to return some data.
To do that let’s list steps we have to go through:
- We configure our web-service in Keycloak, create a new realm, client and test user, check out Token default configuration. By doing this we inform Keycloak about our application and our users which are supposed to request access
- We build a simple web-service in GO with help of gorilla/mux and a go-client for Keycloak API Nerzal /gocloak. Our web-service is going to have authorized endpoints as well as non-authorized ones. Token verification will be implemented as a simple middleware applied to authorized endpoints only
- Finally, we test our service with Postman to make sure it works properly
Ok, go ahead!!!
Keycloak configuration
- Connect to Keycloak Admin Console (for my configuration it’s http://localhost:8086) and create a new realm. Realm settings page contains the most important security configurations. Just walk through them a bit.
2. You can check and configure tokens’ attributes on the corresponding page. For now it’s OK to leave all of them by default.
3. Then create and configure a new client within the newly created realm. Give it a name and fill all mandatory fields. Make sure it’s in Enabled state.
For our test web-service we need client name and secret. Client secret is generated automatically and can be obtained on Credentials page which is getting available if “Access Type” option on the Settings page set as “confidential”.
3. The next step is creating a test user. Now we are registering it manually, but real life scenarios might be far more complex, e.g. you can allow registration procedure on your website or integrate users from external user-management system through Keycloak API. But keeping it simple we just register a new user and set a password manually
Please, turn off the “User Actions”. Otherwise, Keycloak will request a user to change its password on the first login
So, this is more or less it with Keycloak configuration. It’s time to code a bit. Let’s go!!!
Building a simple web-service in GO
Our web-service is going to have two endpoints:
- /login (POST) — authenticates a registered user. Credentials are passed as a request payload and pair of tokens (access and refresh) is returned in response
- /docs (GET) — retrieves some data if an access is authorized. To authorize a request we have to pass the access token obtained before.
Keycloak provides two basic ways for interaction with third-party software: Java client and REST API. Of course, the second is the only option for us. Fortunately, there is an open source go-client library that simplifies it (https://github.com/Nerzal/gocloak). Thanks to all contributors of this project!!!
We start with a keycloak struct which encapsulates Keycloak API client and realm/client attributes (just take them from Keycloak configuration we made in the previous section)
Then, we are building http server with gorilla/mux. Let’s start from routing
The common way of token verification in HTTP request is applying a middleware that handles all incoming requests before a controller logic. It’s up to a middleware to bypass a request or stop processing by returning the result back to client.
As you remember, we don’t have to apply authorization to all endpoints. To implement this properly we create subroutes from the root route. It will allow us to apply a middleware only to routes which require authorization and leave others unauthorized.
In our case I use MatcherFunc that seemed to be the simplest approach. Maybe there are other options, but this one works perfectly fine.
In the next piece of code we map routes to controller’s methods and apply middleware to the auth routes.
Then, let’s implement login controller method. We decode request and just pass-by our call to Keycloak API. If everything is correct and the user is authenticated we get tokens back from Keycloak and put them in a response.
Ok, so far so good, but what about middleware implementation. Let’s have a look at it…
The idea behind it is quite simple. We just extract a token from HTTP header and if provided ask Keycloak to verify it.
If you want to get more details from the token (e.g. username), you can also call another API method and get JWT struct including roles, claims etc.
Also, additionally check our token is up-to-date
Don’t forget to pass a call further to give other middlewares and a main handler a chance to do their work
And finally start listening on 8081 port
That is it with our service. Let’s test it
Some tests
To start with, we are logging in with the user registered in Keycloak.
As expected, we obtained tokens that are supposed to be used for all subsequent requests
By passing invalid credentials we get an error
Ok, then we call another method that implies authorization
If we try it with no auth in header, we get an authorization error in response. Ok, expected.
But let’s challenge our service a bit more and try it with out-dated token.
And as we pass a valid token, we get expected data in response.
We did it!!!
Conclusion
Of course, this is not an ideal solution. One of the obvious drawbacks is a round-trip to Keycloak server for each incoming request for token verification. There is another approach to decode access tokens locally, but this approach has its own complications and drawbacks (think of the scenario where your token is revoked by admin in Admin console and you aren’t aware of it). This is completely a different story which has its own trade-offs. Just be aware and consider all options for your particular context! Good luck!!
You can find complete source code for this post on github