Kong JWT Authentication
Introduction
JSON Web Tokens (JWT) provide a compact and self-contained way to securely transmit information between parties. When combined with Kong, a popular API Gateway, JWT becomes a powerful authentication mechanism for your APIs. This tutorial will guide you through understanding and implementing JWT authentication with Kong.
What is JWT?
JSON Web Tokens are an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. JWTs can be verified and trusted because they are digitally signed using a secret or a public/private key pair.
A JWT consists of three parts, separated by dots (.
):
- Header: Contains the type of token and the signing algorithm
- Payload: Contains the claims or the data
- Signature: Used to verify that the sender of the JWT is who it says it is
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Kong JWT Plugin
Kong's JWT plugin enables your API Gateway to verify JWT tokens sent by clients. When a client makes a request to your API, Kong verifies the token before forwarding the request to your upstream service.
How Kong JWT Authentication Works
Here's a high-level flow of JWT authentication with Kong:
Setting Up Kong JWT Authentication
Let's walk through setting up JWT authentication in Kong step by step.
Prerequisites
- Kong installed and running
- Basic understanding of Kong services and routes
curl
or another API testing tool
Step 1: Create a Service and Route
First, let's create a service pointing to your backend API:
curl -X POST http://localhost:8001/services \
--data "name=my-api" \
--data "url=http://my-api.com"
Next, create a route for this service:
curl -X POST http://localhost:8001/services/my-api/routes \
--data "paths[]=/api"
Step 2: Enable the JWT Plugin
Now, let's enable the JWT plugin on the service:
curl -X POST http://localhost:8001/services/my-api/plugins \
--data "name=jwt"
Step 3: Create a Consumer
Create a consumer who will access your API:
curl -X POST http://localhost:8001/consumers \
--data "username=john"
Step 4: Create JWT Credentials
Create a JWT credential for this consumer:
curl -X POST http://localhost:8001/consumers/john/jwt \
--data "key=user-issuer" \
--data "secret=secret-key"
The response will include:
{
"consumer": { "id": "7bce93e1-0a90-489c-c887-d385545f8f4b" },
"created_at": 1442426001000,
"id": "bcbfb45d-e391-42bf-c2ed-94e32946753a",
"key": "user-issuer",
"secret": "secret-key"
}
Creating and Using JWT Tokens
Now that we've set up Kong, let's see how to create and use JWT tokens.
Creating a JWT Token
You can create a JWT token using various programming languages. Here's an example using JavaScript with the jsonwebtoken
library:
const jwt = require('jsonwebtoken');
// The payload
const payload = {
sub: "1234567890",
name: "John Doe",
iat: Math.floor(Date.now() / 1000)
};
// Use the secret key from your Kong JWT credential
const secret = 'secret-key';
// The JWT header includes the key (issuer) from your Kong JWT credential
const header = {
typ: "JWT",
alg: "HS256",
kid: "user-issuer"
};
// Create the token
const token = jwt.sign(payload, secret, { header: header });
console.log(token);
Output:
eyJraWQiOiJ1c2VyLWlzc3VlciIsInR5cCI6IkpXVCIsImFsZyI6IkhTMjU2In0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNjQ2NjQ5NjAwfQ.Z4XaMlvZKO2JxT3H5WEj5eN9g-hGvKxTWYx-8c0F2Wo
Using the JWT Token
To make a request to your protected API, include the JWT in the Authorization
header:
curl -X GET http://localhost:8000/api \
-H "Authorization: Bearer eyJraWQiOiJ1c2VyLWlzc3VlciIsInR5cCI6IkpXVCIsImFsZyI6IkhTMjU2In0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNjQ2NjQ5NjAwfQ.Z4XaMlvZKO2JxT3H5WEj5eN9g-hGvKxTWYx-8c0F2Wo"
Alternatively, you can pass it as a query parameter:
curl -X GET "http://localhost:8000/api?jwt=eyJraWQiOiJ1c2VyLWlzc3VlciIsInR5cCI6IkpXVCIsImFsZyI6IkhTMjU2In0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNjQ2NjQ5NjAwfQ.Z4XaMlvZKO2JxT3H5WEj5eN9g-hGvKxTWYx-8c0F2Wo"
Advanced Configuration
Kong's JWT plugin provides several configuration options:
Customizing Token Verification
You can customize how Kong verifies tokens with these parameters:
curl -X POST http://localhost:8001/services/my-api/plugins \
--data "name=jwt" \
--data "config.claims_to_verify=exp" \
--data "config.key_claim_name=kid" \
--data "config.secret_is_base64=false"
JWT Plugin Configuration Options
Parameter | Description | Default |
---|---|---|
config.uri_param_names | Parameters in the URI that contain the token | jwt |
config.cookie_names | Names of cookies that contain the token | none |
config.claims_to_verify | Claims to verify | none |
config.key_claim_name | Claim that contains the key | iss |
config.secret_is_base64 | If true, the secret is base64 encoded | false |
config.run_on_preflight | Run on preflight OPTIONS requests | true |
config.maximum_expiration | Maximum allowed expiration (in seconds) | none |
Real-World Example: Protecting a User API
Let's walk through a real-world example of protecting a user management API with Kong JWT authentication.
Step 1: Set Up the API in Kong
# Create a service
curl -X POST http://localhost:8001/services \
--data "name=user-api" \
--data "url=http://user-service:3000"
# Create routes
curl -X POST http://localhost:8001/services/user-api/routes \
--data "paths[]=/users"
Step 2: Add JWT Authentication
curl -X POST http://localhost:8001/services/user-api/plugins \
--data "name=jwt"
Step 3: Create Admin Consumer and Credentials
# Create admin consumer
curl -X POST http://localhost:8001/consumers \
--data "username=admin"
# Create JWT credential
curl -X POST http://localhost:8001/consumers/admin/jwt \
--data "key=admin-api" \
--data "secret=super-secure-secret"
Step 4: Create a Token for Admin Access
const jwt = require('jsonwebtoken');
const payload = {
sub: "admin",
role: "administrator",
permissions: ["users:read", "users:write"],
exp: Math.floor(Date.now() / 1000) + (60 * 60) // 1 hour
};
const secret = 'super-secure-secret';
const header = {
typ: "JWT",
alg: "HS256",
kid: "admin-api"
};
const token = jwt.sign(payload, secret, { header: header });
console.log(token);
Step 5: Access the Protected API
curl -X GET http://localhost:8000/users \
-H "Authorization: Bearer eyJraWQiOiJhZG1pbi1hcGkiLCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJhZG1pbmlzdHJhdG9yIiwicGVybWlzc2lvbnMiOlsidXNlcnM6cmVhZCIsInVzZXJzOndyaXRlIl0sImV4cCI6MTY0NjY1MzIwMH0.BdCMDhSgFoJ5S9JQrELYgKkP-nHxUdlJVBpgW2UdiNM"
Common Issues and Troubleshooting
1. "No credentials found" error
If you receive a 401 Unauthorized with "No credentials found" message, ensure that:
- You're including the JWT token in the Authorization header as "Bearer [token]"
- The token format is correct
- You're using the correct path that's protected by Kong
2. "Invalid signature" error
This typically means:
- The token was signed with a different secret than what Kong expects
- The token has been tampered with
3. "Token expired" error
Check if:
- The token has an
exp
claim that's in the past - Your system clocks are synchronized
Best Practices for Kong JWT Implementation
- Use HTTPS: Always use HTTPS to prevent token interception
- Short Expiration Times: Set short expiration times for tokens
- Include Only Necessary Claims: Don't include sensitive information in tokens
- Rotate Secrets Regularly: Change your JWT secrets periodically
- Include Rate Limiting: Combine JWT with rate limiting to prevent abuse
- Monitor Token Usage: Log and monitor token usage for suspicious activities
Summary
In this tutorial, we've explored how to implement JWT authentication with Kong API Gateway:
- We learned about JWT structure and how it works with Kong
- We set up Kong with the JWT plugin
- We created consumers and credentials
- We generated and used JWT tokens
- We explored advanced configuration options
- We implemented a real-world example
- We discussed troubleshooting and best practices
JWT combined with Kong provides a robust authentication mechanism for your APIs, ensuring that only authorized clients can access your services while maintaining a stateless, scalable architecture.
Exercise
Try implementing JWT authentication with Kong for your own API:
- Create a simple backend API with a framework of your choice
- Set up Kong to proxy requests to your API
- Enable JWT authentication using the steps outlined in this tutorial
- Create a consumer and credentials
- Generate a token and test your protected API
- Try to access the API without a token and observe the response
- Try to access the API with an expired token
Additional Resources
- Kong JWT Plugin Documentation
- JWT.io - Useful for debugging JWT tokens
- RFC 7519 - The JWT specification
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)