How to Secure APIs and Services Using OpenID Connect
A modern API gateway like Kong enables organizations to achieve some use cases much more easily than traditional gateways. The reason is older, traditional gateways try to provide as many features as possible into a heavyweight monolith, while modern solutions use a best-in-breed approach. These traditional solutions not only try to be a gateway, but they also try to be a business intelligence system, a central logging hub, a monitoring tool and so much more. Unfortunately, this leads to a solution that on paper can do many things but not do one thing particularly well.
A more tactical approach is to leverage best-in-breed solutions that integrate well with each other and are simple to use. Kong's platform delivers on this approach and provides a modern gateway that's fast, scalable, easy to use and can easily integrate with other platforms through its pluggable architecture. In this blog post, we will cover how easily Kong integrates with existing identity providers (IdPs) to help secure and govern APIs.
AuthN and AuthZ
The defacto standard for API security today is OpenID Connect with JWT. A few years ago, many gateways heavily relied on being the OAuth/OpenID Connect provider for the whole flow – but today, most IdPs have implemented OpenID Connect, and therefore, customers prefer that the management of keys, tokens and users happen in the IdP versus the gateway to remove the need to manage a separate silo of identity.
Let’s think about a very typical customer scenario we come across: you have a central IdP as the identity manager and central point of truth for authentication as well as groups/permissions of users. A legacy gateway approach would use the IdP for authentication and then in the gateway, you define authorization per endpoint to the groups you want to grant access to the backend services.
This design has two flaws:
To attach the users to groups, they must exist in the gateway so you end up having to manage consumers in the gateway.
Administrators have to maintain group memberships in the Gateway to grant or revoke permissions.
A Better Approach with Kong
With Kong, you can leverage the IdP for both authentication and authorization without having to manage consumers or groups in Kong, giving you the ability to leverage your IdP to drive access without additional operational overhead and risk. To do this, we can configure Kong to use OpenID Connect groups to attach scopes to the users and let Kong provide access based on the scopes in the JWT tokens. This solves both issues at the same time, and the administration of users and their permissions are now located where they should be: in the IdP.
Let's see this in practice:
Note: The following example will use Kong Enterprise installed locally. Kong Enterprise provides access to the OpenID Connect plugin needed for this scenario. For the IdP, we will be using KeyCloak. Kong supports many other IdPs. For a full list, see the OpenID Connect plug-ins page (https://docs.konghq.com/hub/kong-inc/openid-connect/).
In order to achieve this, we are going to walk through an example of how to secure APIs and services using OpenID Connect with KeyCloak as an example. Within KeyCloak, the first thing is creating a new scope, attaching it to a group and then attaching this group to a user:
Keycloak scope creation
Keycloak scope and role mapping
Role to group mapping
User to group mapping
Kong Enterprise settings
Note: I am using httpie as my command line tool of choice – feel free to use Studio, Insomnia, curl, etc. instead.
Let's begin by creating a service and route in Kong for validation. Replace localhost with the hostname of your Kong installation.
Service and route
http POST localhost:8001/services name=openidconnect url=http://httpbin.org/anything
http POST localhost:8001/services/openidconnect/routes name=openidconnectRoute paths=/oidc -f
OpenID Connect plugin
OK, now let’s configure the openid-connect plugin to connect to the KeyCloak instance:
Let’s have a look at the parameters.
The config.redirect_uri defines the uri the IDP will redirect the user to after a successful authentication
config.consumer_optional defines whether a Kong consumer should exist to allow access
config.scopes_required defines which scopes are authorized to access. We are defining the JWT returned by KeyCloak must include the scope kong_api_access. Only then Kong will authorize the request and route it to the upstream (backend). The KeyCloak screenshots above show the scope attached to the group of which the user is a member.
Let’s try it
For testing purposes, I have two example users in KeyCloak:
Blog_with_scope / veryComplexPa55word
Blog_without_scope / veryComplexPa55word
Open a new browser window (either in incognito mode or with all caches empty) and navigate to http://localhost:8000/oidc. You will notice that the user Blog_with_scope will get access.
But Blog_without_scope is denied even though he is also a valid user in KeyCloak.
The user without the scope will produce a log entry like required scopes were not found [ openid, profile, email ] in your Kong logs.
Last but not least, let’s have a look at the JWT for Blog_with_scope, which includes the scope:
In this post, we've covered how to secure APIs and services with Kong and an IdP without having to manage local consumers or groups in Kong, allowing the IDd to be the source of truth for identity and entitlements. In a future blog post, we'll cover how to apply policy (i.e., rate limiting and caching) to authenticated consumers.