DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Enterprise AI Trend Report: Gain insights on ethical AI, MLOps, generative AI, large language models, and much more.

2024 Cloud survey: Share your insights on microservices, containers, K8s, CI/CD, and DevOps (+ enter a $750 raffle!) for our Trend Reports.

PostgreSQL: Learn about the open-source RDBMS' advanced capabilities, core components, common commands and functions, and general DBA tasks.

AI Automation Essentials. Check out the latest Refcard on all things AI automation, including model training, data security, and more.

Related

  • Securing REST APIs With Nest.js: A Step-by-Step Guide
  • Navigating the API Seas: A Product Manager's Guide to Authentication
  • What D'Hack Is DPoP?
  • Using OKTA as Client Provider in Mulesoft

Trending

  • Telemetry Pipelines Workshop: Introduction To Fluent Bit
  • Generative AI With Spring Boot and Spring AI
  • Role-Based Multi-Factor Authentication
  • Implementing CI/CD Pipelines With Jenkins and Docker
  1. DZone
  2. Software Design and Architecture
  3. Security
  4. Secure Your API With JWT: Kong OpenID Connect

Secure Your API With JWT: Kong OpenID Connect

In this article, walk through the issues of session-based authorization and the benefits of stateless tokens, namely JWT.

By 
Adam Zaręba user avatar
Adam Zaręba
·
Mar. 19, 24 · Tutorial
Like (3)
Save
Tweet
Share
3.2K Views

Join the DZone community and get the full member experience.

Join For Free

Good Old History: Sessions

Back in the old days, we used to secure web applications with sessions. The concept was straightforward: upon user authentication, the application would issue a session identifier, which the user would subsequently present in each subsequent call. On the backend side, the common approach was to have application memory storage to handle user authorization - simple mapping between session ID and user privileges. 

Secure web applications with sessions

Unfortunately, the simple solution had scaling limitations. If we needed to scale an application server, we used to apply session stickiness on the exposed load balancer:

Apply session stickiness on the exposed load balancer

 Or, move session data to shared storage like a database. 

Move session data to shared storage like a database

That caused other challenges to tackle: how to evenly distribute traffic for long living sessions and how to reduce request processing time for communication with shared session storage.

Distributed Nature of Authorization

The stateful nature of sessions becomes even more troublesome when we consider distributed applications. Handling proper session stickiness, and connection draining on a scale like multiple microservices gives no easy manageable solution.

Distributed Nature of Authorization

Stateless Authorization: JWT

Luckily, we can use a stateless solution - JWT - which is based on a compact and self-contained, encoded JSON object acting as a replacement for session ID for client/server communication. The idea is to encode user privileges or roles into a token and sign data with a trusted issuer to prove token integrity. In this scenario, the user, once authenticated, gets an access token in response with all data required for authorization - no more server session storage needed. The server during authorization needs to decode the token and get user privileges from the token itself. 

Stateless Authorization: JWT

Exposing Unprotected API in Kong

To see how things can work, let’s use Kong, acting as an API Gateway for calling upstream service. For this demo, we will use the Kong Enterprise edition together with the OpenID Connect plugin handling JWT validation. But let's first expose some REST resources with Kong. 

To make the demo simple, we can expose a single/mock endpoint in Kong which will proxy requests to the httpbin.org service. Endpoint deployment can be done with a declarative approach: we define the configuration for setting up the Kong service that will call upstream. Then the decK tool will create respective resources in Kong Gateway. The configuration file is as follows: 

YAML
 
_format_version: "3.0"
_transform: true

services:
  - host: httpbin.org
    name: example_service
    routes:
      - name: example_route
        paths:
          - /mock


Once deployed, we can verify endpoint details in Kong Manager UI:

Verify endpoint details in Kong Manager UI

For now, the endpoint is not protected and we can call it without any authorization details. Kong Gateway is exposed on a local machine on port 8000, so we can call it like this:

 
➜  ~ curl http://localhost:8000/mock/anything

{

  "args": {}, 

  "data": "", 

  "files": {}, 

  "form": {}, 

  "headers": {

    "Accept": "*/*", 

    "Host": "httpbin.org", 

    "User-Agent": "curl/8.4.0", 

    "X-Amzn-Trace-Id": "Root=1-65e2f62e-2ea7165246c573e24a3efeaf", 

    "X-Forwarded-Host": "localhost", 

    "X-Forwarded-Path": "/mock/anything", 

    "X-Forwarded-Prefix": "/mock", 

    "X-Kong-Request-Id": "3cef792ded0dfb53575cd866c20aba42"

  }, 

  "json": null, 

  "method": "GET", 

  "url": "http://localhost/anything"

}


Securing API With OpenID Connect Plugin

To secure our API we need two things:

  • IdP server, which will issue JWT tokens
  • Kong endpoint configuration that will validate JWT tokens

Setting up an IdP server is out of scope for this blog post, but for the demo, we can use Keycloak. In my test setup, I created a “test” user which is granted to have a “custom-api-get” scope - we will use this scope name later on for authorization with Kong. To get a JWT token, we need to call the Keycloak token endpoint. It returns an encoded token, which we can decode on the jwt.io website:

An encoded token, decoded on the jwt.io website:

On the Kong side, we will define endpoint authorization with the OpenID Connect plugin. For this, again, we will use the decK tool to update the endpoint definition.

YAML
 
_format_version: "3.0"

_transform: true


services:

  - host: httpbin.org

    name: example_service

    routes:

      - name: example_route

        paths:

          - /mock

        plugins:

          - name: openid-connect

            enabled: true

            config:

              display_errors: true

              scopes_claim:

                - scope

              bearer_token_param_type:

                - header

              issuer: http://keycloak:8080/auth/realms/master/.well-known/openid-configuration

              scopes_required:

                - custom-api-get

              auth_methods:

                - bearer

In the setup above, we stated that the user is allowed to call the endpoint if the JWT token contains the “custom-api-get” scope. We also specified how we want to pass the token (header value). To enable JWT signature verification, we also had to define the issuer. Kong will use this endpoint internally to get a list of public keys that can be used to check token integrity/signature (the content of that response is cached in Kong to avoid future requests). 

With this configuration, calling an endpoint without a token is not allowed. The plugin returns error details as follows:

 
➜  ~ curl http://localhost:8000/mock/anything

{"message":"Unauthorized (no suitable authorization credentials were provided)"}


To make it work, we need to pass a JWT token (for the sake of space, the token value is not presented):

 
➜  ~ curl http://localhost:8000/mock/anything --header "Authorization: Bearer $TOKEN"

{

  "args": {}, 

  "data": "", 

  "files": {}, 

  "form": {}, 

  "headers": {

    "Accept": "*/*", 

    "Authorization": "Bearer $TOKEN", 

    "Host": "httpbin.org", 

    "User-Agent": "curl/8.4.0", 

    "X-Amzn-Trace-Id": "Root=1-65e30053-4f1b17b771c240463a878c41", 

    "X-Forwarded-Host": "localhost", 

    "X-Forwarded-Path": "/mock/anything", 

    "X-Forwarded-Prefix": "/mock", 

    "X-Kong-Request-Id": "c1cf555ab43d951f73f72a30d5546516"

  }, 

  "json": null, 

  "method": "GET", 

  "url": "http://localhost/anything"

}


We should remember that tokens have a limited lifetime (in our demo, it was 1 minute), and the plugin verifies it as well. Calling the endpoint with an expired token returns the error:

 
curl http://localhost:8000/mock/anything --header "Authorization: Bearer $TOKEN"

{"message":"Unauthorized (invalid exp claim (1709375597) was specified for access token)"}


Summary

In this short post, we walked through the issues of session-based authorization and the benefits of stateless tokens, namely JWT. In a microservices solution, we can move authorization from microservice implementation into a centralized layer like Gateway. We just scratched the surface of JWT-based authorization, but we can implement more advanced scenarios by validating additional claims. If you’re interested in JWT details, I recommend you familiarize yourself with the specifications. Practice will make you an expert! 

API OpenID authentication JWT (JSON Web Token) security

Opinions expressed by DZone contributors are their own.

Related

  • Securing REST APIs With Nest.js: A Step-by-Step Guide
  • Navigating the API Seas: A Product Manager's Guide to Authentication
  • What D'Hack Is DPoP?
  • Using OKTA as Client Provider in Mulesoft

Partner Resources


Comments

ABOUT US

  • About DZone
  • Send feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: