HMAC Authentication using Kong API Gateway

Johanes Anggara
6 min readJan 20, 2021

Kong API Gateway is one of the famous open source api gateway. Quoted from its website (https://konghq.com/kong), Kong is a lightweight gateway that is scalable and provides additional functionality via its built-in plugins.

In this post I want to share my experience in using one of Kong’s default plugins, namely HMAC authentication. This plugin serves to validate the integrity of incoming requests. You do this by validating the digital signature sent in the “Proxy-Authorization” or “Authorization” (in this order) field in the request header. In this case, the client encodes the request header and / or body with the hmac algorithm using a mutually agreed secret. When a request is received by / via Kong, kong will also encrypt with the same algorithm and secret, then compare it with the signature sent by the client. If the same, then kong will accept the request sent by the client and forward the request to the back-end service.

First of all, we will use the mockup rest API provided by mockbin.org. Then using the konga UI interface (https://github.com/pantsel/konga), we register mockbin.org into Kong. In Konga, go to the “Services” page then click on “Add New Service” and input the fields as shown below.

Then click “Routes” (under the word: “Service Details”) and click “Add Route” and input data as shown below.

In kong, service is a configuration for registering the intended backend service. In this case we register the api rest with the endpoint: “http://mockbin.org/request". And on the “Route”, we register the path “/ok” on the kong api gateway, so when we send a request to “https://localhost/ok” (if url kong is localhost), the request will be forwarded to the endpoint that we setup previously in the “Service” page (“http://mockbin.org/request"). Now we test the service with curl

Still on the “Route” page, click “Plugins”, then click “Add Plugin” and on the Authentication page select “HMAC Auth” and input data as shown below. In this example we will use the sha256 algorithm by encrypting the x-uuid, x-date fields in the headers, request method, request path and request body.

Now is the time to add a customer in Kong. Go to “Consumer” and click “Create Consumer”, then go to the “Credentials” tab, click HMAC, and click “Create Credentials” as an example we will use “hmac-user” as username and “~,6a=HFaC/P]R5Zp“ as secret, so the display will be as shown below.

Below is an example of an nodejs application to send request with hmac authentication.

And below is the application written in go inspired with medium post by qomarullah.

$ node index.js
variables:
url: localhost
username: hmac-user
secret: ~,6a=HFaC/P]R5Zp
body: {"foo":"bar"}
signingString: x-date: Wed, 20 Jan 2021 11:09:53 GMT
POST /ok HTTP/1.1
x-uuid: 9b83f786-5a70-11eb-ae93-0242ac130002
digest: SHA-256=eji/gfOD9pQzrW6QDTWz4jhVk/dqe3q11DVbi6Qe4ks=
signature: io4Y4JuT3drKGi0ue4yUG0KiI1o8lzRf5QW8I15JczE=
authorization: hmac username="hmac-user", algorithm="hmac-sha256", headers="x-date request-line x-uuid digest", signature="io4Y4JuT3drKGi0ue4yUG0KiI1o8lzRf5QW8I15JczE="
request: POST /ok HTTP/1.1
Digest: SHA-256=eji/gfOD9pQzrW6QDTWz4jhVk/dqe3q11DVbi6Qe4ks=
Authorization: hmac username="hmac-user", algorithm="hmac-sha256", headers="x-date request-line x-uuid digest", signature="io4Y4JuT3drKGi0ue4yUG0KiI1o8lzRf5QW8I15JczE="
X-Date: Wed, 20 Jan 2021 11:09:53 GMT
X-UUID: 9b83f786-5a70-11eb-ae93-0242ac130002
Content-Type: application/json
Content-Length: 13
Host: localhost
Connection: close
response header: {
"server": "openresty/1.15.8.1",
"date": "Wed, 20 Jan 2021 11:08:55 GMT",
"content-type": "application/json; charset=utf-8",
"content-length": "1470",
"connection": "close",
"vary": "Accept-Encoding, X-HTTP-Method-Override, Accept, Accept-Encoding",
"access-control-allow-origin": "*",
"access-control-allow-methods": "POST",
"access-control-allow-headers": "host,connection,x-forwarded-for,x-forwarded-proto,x-forwarded-host,x-forwarded-port,x-real-ip,x-request-id,x-original-uri,x-scheme,digest,authorization,x-date,x-uuid,content-type,x-consumer-id,x-consumer-username,x-credential-username,via,connect-time,x-request-start,total-route-time,content-length",
"access-control-allow-credentials": "true",
"x-powered-by": "mockbin",
"etag": "W/\"5be-5Utnfmb34OzEfiNj9jgNEXjxIZQ\"",
"via": "kong/2.0.3",
"x-kong-upstream-status": "200",
"x-kong-upstream-latency": "589",
"x-kong-proxy-latency": "38",
"kong-cloud-request-id": "18a04589f38b8a1aff6bb26aff6d6575",
"strict-transport-security": "max-age=15724800; includeSubDomains"
}
{
"startedDateTime": "2021-01-20T11:09:53.687Z",
"clientIPAddress": "170.10.21.63",
"method": "POST",
"url": "http://localhost/request",
"httpVersion": "HTTP/1.1",
"cookies": {},
"headers": {
"host": "mockbin.org",
"connection": "close",
"x-forwarded-for": "170.10.21.63, 10.42.7.0, 172.17.0.10, 3.133.183.124",
"x-forwarded-proto": "http",
"x-forwarded-host": "localhost",
"x-forwarded-port": "80",
"x-real-ip": "202.158.23.76",
"x-request-id": "11bf4063dcd516142592016da06222f2",
"x-original-uri": "/ok",
"x-scheme": "https",
"digest": "SHA-256=eji/gfOD9pQzrW6QDTWz4jhVk/dqe3q11DVbi6Qe4ks=",
"authorization": "hmac username=\"hmac-user\", algorithm=\"hmac-sha256\", headers=\"x-date request-line x-uuid digest\", signature=\"io4Y4JuT3drKGi0ue4yUG0KiI1o8lzRf5QW8I15JczE=\"",
"x-date": "Wed, 20 Jan 2021 11:09:53 GMT",
"x-uuid": "9b83f786-5a70-11eb-ae93-0242ac130002",
"content-type": "application/json",
"x-consumer-id": "8e568d5c-5da9-4e9e-8389-46b8e8834400",
"x-consumer-username": "hmac-consumer",
"x-credential-username": "hmac-user",
"via": "1.1 vegur",
"connect-time": "1",
"x-request-start": "1611140993686",
"total-route-time": "0",
"content-length": "13"
},
"queryString": {},
"postData": {
"mimeType": "application/json",
"text": "{\"foo\":\"bar\"}",
"params": []
},
"headersSize": 929,
"bodySize": 13
}
$ go run post.go
2021/01/20 18:14:38 variables:
url: https://localhost/ok
username: hmac-user
secret: ~,6a=HFaC/P]R5Zp
body: {"foo":"bar"}
signingString: x-date: Wed, 20 Jan 2021 11:14:38 GMT
POST /ok HTTP/1.1
x-uuid: 9b83f786-5a70-11eb-ae93-0242ac130002
digest: SHA-256=eji/gfOD9pQzrW6QDTWz4jhVk/dqe3q11DVbi6Qe4ks=
signature: nKOYtaK8mi/OnNyJDbB6jo5vWCeaF7zhYibSoygZxPY=
authorization: hmac username="hmac-user", algorithm="hmac-sha256", headers="x-date request-line x-uuid digest", signature="nKOYtaK8mi/OnNyJDbB6jo5vWCeaF7zhYibSoygZxPY="
2021/01/20 18:14:38 request: POST /ok HTTP/1.1
Host: localhost
Authorization: hmac username="hmac-user", algorithm="hmac-sha256", headers="x-date request-line x-uuid digest", signature="nKOYtaK8mi/OnNyJDbB6jo5vWCeaF7zhYibSoygZxPY="
Content-Type: application/json
Digest: SHA-256=eji/gfOD9pQzrW6QDTWz4jhVk/dqe3q11DVbi6Qe4ks=
X-Date: Wed, 20 Jan 2021 11:14:38 GMT
X-Uuid: 9b83f786-5a70-11eb-ae93-0242ac130002
{"foo":"bar"}
2021/01/20 18:14:42 response header:
Content-Type : [application/json; charset=utf-8]
Etag : [W/"605-+wx7NLxitMmKfIbgtxFO97nQYjw"]
Via : [kong/2.0.3]
X-Kong-Proxy-Latency : [3561]
Strict-Transport-Security : [max-age=15724800; includeSubDomains]
Date : [Wed, 20 Jan 2021 11:13:44 GMT]
Connection : [keep-alive]
Vary : [X-HTTP-Method-Override, Accept, Accept-Encoding]
Access-Control-Allow-Origin : [*]
X-Powered-By : [mockbin]
Kong-Cloud-Request-Id : [0e68c93308522884d89343940561cc53]
Server : [openresty/1.15.8.1]
Access-Control-Allow-Methods : [POST]
Access-Control-Allow-Headers : [host,connection,x-forwarded-for,x-forwarded-proto,x-forwarded-host,x-forwarded-port,x-real-ip,x-request-id,x-original-uri,x-scheme,user-agent,authorization,content-type,digest,x-date,x-uuid,accept-encoding,x-consumer-id,x-consumer-username,x-credential-username,via,connect-time,x-request-start,total-route-time,content-length]
Access-Control-Allow-Credentials : [true]
X-Kong-Upstream-Status : [200]
X-Kong-Upstream-Latency : [586]
2021/01/20 18:14:42 response: {
"startedDateTime": "2021-01-20T11:14:42.547Z",
"clientIPAddress": "170.10.21.63",
"method": "POST",
"url": "http://localhost/request",
"httpVersion": "HTTP/1.1",
"cookies": {},
"headers": {
"host": "mockbin.org",
"connection": "close",
"x-forwarded-for": "170.10.21.63, 10.42.8.0, 172.17.0.10, 3.133.183.124",
"x-forwarded-proto": "http",
"x-forwarded-host": "localhost",
"x-forwarded-port": "80",
"x-real-ip": "202.158.23.76",
"x-request-id": "2fd5381ab7f0b44e3e2882cee1c9fc7f",
"x-original-uri": "/ok",
"x-scheme": "https",
"user-agent": "Go-http-client/1.1",
"authorization": "hmac username=\"hmac-user\", algorithm=\"hmac-sha256\", headers=\"x-date request-line x-uuid digest\", signature=\"nKOYtaK8mi/OnNyJDbB6jo5vWCeaF7zhYibSoygZxPY=\"",
"content-type": "application/json",
"digest": "SHA-256=eji/gfOD9pQzrW6QDTWz4jhVk/dqe3q11DVbi6Qe4ks=",
"x-date": "Wed, 20 Jan 2021 11:14:38 GMT",
"x-uuid": "9b83f786-5a70-11eb-ae93-0242ac130002",
"accept-encoding": "gzip",
"x-consumer-id": "8e568d5c-5da9-4e9e-8389-46b8e8834400",
"x-consumer-username": "hmac-consumer",
"x-credential-username": "hmac-user",
"via": "1.1 vegur",
"connect-time": "1",
"x-request-start": "1611141282544",
"total-route-time": "0",
"content-length": "13"
},
"queryString": {},
"postData": {
"mimeType": "application/json",
"text": "{\"foo\":\"bar\"}",
"params": []
},
"headersSize": 984,
"bodySize": 13
}

--

--