DEV Community

Cover image for Custom Authentication With Kong
Jefferson Xavier
Jefferson Xavier

Posted on • Updated on

Custom Authentication With Kong

The Kong Gateway

The Kong Gateway is an API Gateway to manage, configure and route requests to multiple APIs.

It's used to release a single address to access multiple APIs at the same time.

Objectives

This post presents a step by step to create a plugin with authentication using an external service. This solution is used when exists multiple services managed by Kong that extends the same authorization method.

The Original Problem

OriginalProblem

In our original problem the front-end needs to know how the addresses of all services to execute requests, and both services needs request the external authentication service to validate the authorization token.

Adding Kong

Using Kong

Now, the front-end knows just kong address and kong register all services to release requests. However, all services still require the external authentication service.

The Solution

Our solution, implements a Kong Plugin to validate the authentication in external service and just at success case the request to services is released.

Final Diagram

Plugin Development

It's possible add some logics to execute during the Kong requests lifecycle. To do this, we add plugins with different purposes. In our case, we created a plugin named cutom-auth to request the external auth request and validate the authentication before requesting services.

The plugin structure contains two files developed in lua:

  • schema.lua: This file is used to define the plugin configurations. In our case we defined the external auth request URL and the paths to ignore authentication.
  • handler.lua: The core file to execute the plugin logic. Here is the request to external auth to validate authentication.

Bellow we can see the code of this two files:

schema.lua

local typedefs = require "kong.db.schema.typedefs"

return {
  name = "custom-auth",
  fields = {
    { protocols = typedefs.protocols_http },
    { consumer = typedefs.no_consumer },
    { config = {
      type = "record",
      fields = {
        { url = typedefs.url({ required = true }) },
        {
          public_paths = {
            type = "array",
            default = {},
            required = false,
            elements = { type = "string" },
          }
        },
      },
    }, },
  },
}
Enter fullscreen mode Exit fullscreen mode

handler.lua

local http = require "resty.http"
local ngx = require "ngx"
local cjson = require "cjson"

local ExternalAuthHandler = {
  VERSION = "1.0",
  PRIORITY = 1000,
}

function ExternalAuthHandler:access(conf)
  local path = kong.request.get_path()
  local publicPaths = conf.public_paths;

  for i, pub_path in ipairs(publicPaths) do
    if pub_path == path then
      return
    end
  end

  local client = http.new()

  kong.log("Validating Authentication: ", conf.url)
  local res, err = client:request_uri(conf.url, {
    ssl_verify = false,
    headers = {
      Authorization = kong.request.get_header("Authorization"),
    }
  })

  if not res then
    kong.log.err("Invalid Authentication Response: ", err)
    return kong.response.exit(500)
  end

  if res.status ~= 200 then
    kong.log.err("Invalid Authentication Response Status: ", res.status)
    return kong.response.exit(401)
  end

  local json = cjson.encode(res.body)
  local user_info = cjson.decode(json)
  kong.service.request.set_header("X-UserInfo", ngx.encode_base64(user_info))
end

return ExternalAuthHandler
Enter fullscreen mode Exit fullscreen mode

Explanation

In schema.lua we defined two params:

  • url: Used to set the external auth url to validate authentication. In our case, this request validates the authentication and returns the current user.
  • public_paths: Used to set the service public paths. The paths mapped here will not require authentication validation.

In handler.lua have some steps. The access method is the entry point to Kong execute this plugin in lifecycle.

The first operation is execute a GET in URL defined to validate the authentication. In case the request returns an error or an invalid status the Kong will be exit with status 500 or 401.

In case of success the X-UserInfo header will be added to the request with the current user data mapped in a base64 string. The services can be use this header to validate authorization or get user data if necessary.

Conclusion

With this plugin the Kong can validate authentication before requesting services and the structure of the diagram solution is finished.

We validated the use of this plugin in I9Partner Company using Kong and multiple internal services.

Here is an example of this plugin usage mapped in Konga.

Konga Configuration

You can follow the repository to this project here.

Reference

Authors

Jefferson Xavier
Thyaki Takuno

A I9Partner initiative.

Top comments (2)

Collapse
 
yauheni profile image
Yauheni

Hi, can you add git repo of this project?

Collapse
 
jeffersonxavier profile image
Jefferson Xavier