Custom Authentication and Authorization Framework With Kong
Degui Xu
Manager Solutions Engineer, Kong
Authorization Framework Problem
Kong Enterprise provides many out-of-the-box plugins to support various access control solutions like basic authentication, key authentication, JWT, LDAP, OAuth 2.0, OpenID Connect, among others. Most of the time, you should be able to find a plugin to suit your needs to protect your private or public APIs using Kong Enterprise without the need of writing your own plugins. However, there could be situations where you have non-standard or custom security requirements to your environment and business.
Let's assume a customer has built an in-house authentication and authorization service which has been used extensively by other applications. It's able to issue and validate a JWT token, perform fine-grained access control based on user rights and determine if the authenticated user has proper permissions to access API and data. The service has exposed APIs for integration purposes. Rather than build custom code in each microservice to integrate with the custom security service, let's leverage Kong to centralize the integration and allow each microservice to focus on the business logic.
Use Case: Integrate with Custom Authentication and Authorization Framework
To integrate Kong with the custom identity provider to secure and govern API access, we can develop a custom Kong plugin. This is a sound approach, which will not only simplify your microservices but also help to transition to an OpenID-compliant provider down the line by abstracting the application clients from the security service using Kong.
Solution Overview
The diagram below shows a high-level overview of the solution. The custom authentication service exposes API endpoints to validate the JWT token, check user permissions, etc. The Kong custom plugin will first invoke the authentication service API to validate the JWT token from the request header. If the token is valid, the plugin will do a second check to see if the authenticated user has necessary permissions to access the upstream API and related data.
In this example, the custom authentication service has exposed the following API endpoints for integration:
Introspect token: https://<server address>/auth/validate/token Check if the token (passed in Authorization header as Bearer token) is valid.
Check permission: http://<server address>/auth/validate/customer check if the authenticated user has permission to access the customer details based on "custId" in the request JSON body
5 Essential API Gateway Vendor Questions: Make the Right Investment Decision
One of Kong's biggest benefits is the ability to extend the platform. Any custom logic can be added during the lifecycle of a request or response as it is proxied through Kong. For this scenario, let's implement a custom plugin named "custom-auth." If you're new to Kong custom plugins, they are fairly straightforward to implement. A plugin requires minimally two files: schema.lua and handler.lua. You may optionally implement business logic in other Lua files, which can be loaded by handler.lua to make your code more modular and manageable. For the "custom-auth" plugin, let's create the following structure.
schema.lua: Your plugin probably has to retain some configuration entered by the user. This module holds the schema of that configuration and defines rules on it so that the user can only enter valid configuration values.
handler.lua: This is the core of your plugin. It is an interface to implement, in which each function will be run at the desired moment in the lifecycle of a request/connection.
Below are further code details and explanations for each.
Schema.lua:
In this case, we have defined three parameters to configure, including token introspection endpoint, permission checking endpoint and header name from where to get the JWT token. All three parameters are mandatory in this case (required = true). We have also added the logic to validate if the endpoints are entered in proper URL format.
handler.lua: This file contains the actual logic to perform token introspection and permission check by interacting with the custom authentication service. The main function that will be executed first is access(conf). It will check if there is an Authorization token in the HTTP request header. If not, it will return an error; otherwise, it will continue to invoke the next function, introspect_access_token(conf, access_token, customer_id), where the authentication and authorization endpoints of the custom auth service will be executed in sequence to determine if the user has valid access token and correct access permission to view the customer's details.
local http = require "resty.http"local utils = require "kong.tools.utils"local TokenHandler = { VERSION = "1.0", PRIORITY = 1000,}local function introspect_access_token(conf, access_token, customer_id)
local httpc = http:new()
-- step 1: validate the token
local res, err = httpc:request_uri(conf.introspection_endpoint,{ method = "POST", ssl_verify = false, headers = {["Content-Type"] = "application/x-www-form-urlencoded",["Authorization"] = "Bearer " .. access_token }})
if not res then
kong.log.err("failed to call introspection endpoint: ",err)
return kong.response.exit(500)
end
if res.status ~= 200 then
kong.log.err("introspection endpoint responded with status: ",res.status)
return kong.response.exit(500)
end
-- step 2: validate the customer access rights
local res, _ = httpc:request_uri(conf.authorization_endpoint,{ method = "POST", ssl_verify = false, body = '{"custId":"' .. customer_id .. '"}', headers = {["Content-Type"] = "application/json",["Authorization"] = "Bearer " .. access_token }})
if not res then
kong.log.err("failed to call authorization endpoint: ",err)
return kong.response.exit(500)
end
if res.status ~= 200 then
kong.log.err("authorization endpoint responded with status: ",res.status)
return kong.response.exit(500)
end
return true -- all is well
end
function TokenHandler:access(conf)
local access_token = kong.request.get_headers()[conf.token_header] if not access_token then
kong.response.exit(401) --unauthorized
end
-- replace Bearer prefix
access_token = access_token:sub(8,-1) -- drop "Bearer " local request_path = kong.request.get_path()
local values = utils.split(request_path,"")
local customer_id = values[3] introspect_access_token(conf, access_token, customer_id)
kong.service.clear_header(conf.token_header)
end
return TokenHandler
Configuration and Testing
Let's now try to deploy the custom plugin to Kong Enterprise and test it. First, we will create a folder named "custom-auth" under the directory /usr/local/share/lua/5.1/kong/plugins. You can find other out-of-the-box plugins here, which serve as good reference implementations. Sometimes you may find it convenient to replicate one of the plugins and modify its behavior when necessary. The directory structure looks like the following:
Next, we will configure Kong Enterprise to load this plugin by setting the following property in /etc/kong/kong.conf file and then restart the Kong instance.
plugins=custom-auth,bundled
If you are running Kong Enterprise in a container environment, you can package the plugin and rebuild the docker image, and then configure the plugins setting via KONG_PLUGINS environment variable.
Now, you should be able to find the custom plugin at the bottom of the plugins page. You can enable this plugin on the service or route that you are trying to protect from unauthorized access.
Below are sample test results to verify this plugin is working properly.
Query returns 200 status code if a valid token is provided in the header and the user access.
$ http --verify no https://192.168.99.102:8443/customer/xudegui/getOverview 'Authorization:Bear XXXXX'HTTP/1.1200 OK
Connection: keep-alive
Content-Length:73Content-Type: application/json
Date: Sun,03 May 202007:45:06 GMT
Via: kong/1.3-enterprise-edition
X-Kong-Proxy-Latency:1707X-Kong-Upstream-Latency:962X-Vcap-Request-Id: d2dac25f-07bb-4071-7612-b054fb1d27bb
{"custId":"xudegui","customerCountry":"Singapore","customerName":"Degui"}
2. Query returns 401 unauthorized error if the token is not valid, which means the authentication check failed.
$ http --verify no https://192.168.99.102:8443/customer/xudegui/getOverview 'Authorization:Bear YYYY'HTTP/1.1401 Unauthorized
Connection: keep-alive
Content-Type: application/json
Date: Sun,03 May 202007:45:13 GMT
Server: kong/1.3-enterprise-edition
Transfer-Encoding: chunked
{"data":[],"error":{"code":401,"message":"The resource owner or authorization server denied the request."}}
3. The query returns 401 unauthorized error if the user doesn't have access.
$ http --verify no https://192.168.99.102:8443/customer/smith/getOverview 'Authorization:Bear XXXXX'HTTP/1.1401 Unauthorized
Connection: keep-alive
Content-Type: application/json
Date: Sun,03 May 202007:45:26 GMT
Server: kong/1.3-enterprise-edition
Transfer-Encoding: chunked
{"data":[],"error":{"code":401,"message":"The resource owner or authorization server denied the request."}}
Conclusion
Kong's platform can be easily extended and integrated with custom, external systems by implementing custom plugins. This allows Kong to easily integrate with any existing systems to address current requirements as well as address future custom requirements that may arise. This benefit is one of the main reasons customers choose Kong. In this write up, we covered how Kong Enterprise can be integrated with a third-party access control system, but it's quite straightforward to integrate with any external system or have Kong perform any logic as part of the request/response lifecycle. I hope you have enjoyed reading this blog post. If you have any interesting ideas and use cases, we welcome your feedback.
Ensuring secure access to applications and APIs is critical. As organizations increasingly adopt microservices architectures and cloud native solutions, the need for robust, fine-grained access control mechanisms becomes paramount. This is where the
Raja Ravi Varman
Adopt a Zero Trust Approach with OAuth 2.0 Mutual TLS Client Authentication
In the modern IT stack, API gateways act as the first line of defense against attacks on backend services by enforcing authentication/authorization policies and validating and transforming requests. When backend services are protected with a token-b
Samuele Illuminati
Understanding Microsegmentation in Zero Trust Security
With digital transformation shifting networks into the cloud — from remote workforces to online banking — cyberattacks are growing more prevalent and sophisticated. Legacy security models like VPNs and perimeter-based firewalls are proving inadequat
Kong
Top GraphQL Security Vulnerabilities: Lessons Learned Analyzing 1,500+ Endpoints
With its flexible querying capabilities, GraphQL makes it easy to combine data from multiple sources into a single endpoint. GraphQL and API management go hand in hand to build next-generation API platforms. However, GraphQL's features can als
Kong
Tightening Bearer Token Authentication with Proof-of-Possession Tokens
Access tokens In token-based architecture, tokens represent the client’s entitlement to access protected resources. Access tokens (or bearer tokens as they're commonly known) are issued by authorization servers after successful user authentication.
Veena Rajarathna
OpenID vs OAuth: Understanding API Security Protocols
When it comes to digital identity, OpenID and OAuth are two peas in a pod, but they have their differences. OpenID connects you to relying parties using a single sign-on, while OAuth grants access tokens so you can give apps limited access. They bo
Axandria Shepard
Understand the Differences: API Authentication vs API Authorization
If you landed on this blog post, chances are that you care about keeping your API secure. It's an important topic to discuss: API exploits are on the rise, and you don't want unauthorized users accessing your data. A big part of that security is imp
Kong
Ready to see Kong in action?
Get a personalized walkthrough of Kong's platform tailored to your architecture, use cases, and scale requirements.