Skip to main content

Protect APIs on KrakenD with ThunderID

This guide explains how to secure your APIs at the KrakenD gateway layer using tokens issued by ThunderID. By retrieving public signing keys from the ThunderID JWKS endpoint, KrakenD cryptographically verifies every incoming token at the edge before forwarding authorized requests to your backend services.

ApplicationThunderIDBackend API Request Access token Issue Access token API request+ Bearer token Call JWKS endpoint to validate token signature Forward request

The guide covers two core integration approaches available in KrakenD:

Prerequisites

Before you begin, ensure you have the following:

  • A running ThunderID installation. Follow Get ThunderID for download, setup, and start commands.
  • KrakenD installed.
  • A backend REST API service running and accessible (for example, http://localhost:8081).
  • curl available in your terminal.

Configure JWT Token Validation in KrakenD

JWT Token Validation is the foundation of API security with KrakenD and ThunderID. In this section, you register an application in ThunderID to obtain credentials, configure KrakenD to validate tokens using the ThunderID JWKS endpoint, and verify that unauthenticated requests are rejected.

Configure ThunderID

Create an Application

  1. Sign in to the ThunderID Console at https://<THUNDERID_HOST>:<THUNDERID_PORT>/console.
  2. Navigate to ApplicationsNew Application.
  3. Enter an Application Name.
  4. Select Backend Service as the application type.
  5. Click Create Application.
  6. Note the Client ID and Client Secret from the application details page.

Obtain an Access Token

Use the client credentials grant to request an access token:

curl --location 'https://<THUNDERID_HOST>:8090/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=<CLIENT_ID>' \
--data-urlencode 'client_secret=<CLIENT_SECRET>'

Save the returned access_token. You will use it in the Try It Out section.

Configure KrakenD

Create an API

Create a krakend.json configuration file. See the KrakenD configuration structure for a full reference.

The endpoint object defines the routes KrakenD exposes. The backend object defines the upstream services each endpoint connects to.

{
"$schema": "https://www.krakend.io/schema/v2.7/krakend.json",
"version": 3,
"name": "KrakenD API Gateway",
"port": 8082,
"cache_ttl": "3600s",
"timeout": "3000ms",
"endpoints": [
{
"endpoint": "/api/items",
"method": "POST",
"output_encoding": "json",
"backend": [
{
"url_pattern": "/api/items",
"encoding": "json",
"method": "POST",
"host": [
"http://localhost:8081"
]
}
]
}
]
}

Start KrakenD to verify the API is reachable before adding authentication:

krakend run -c krakend.json

KrakenD starts on port 8082. Verify the endpoint responds:

curl --location 'http://localhost:8082/api/items' \
--header 'Content-Type: application/json' \
--data '{"name":"Widget","description":"A test item"}'

Add JWT Validation

KrakenD validates JWTs using the auth/validator component. KrakenD fetches public keys from the ThunderID JWKS endpoint and uses the keys to verify the signature on incoming tokens.

Add the auth/validator block inside the endpoint:

{
"$schema": "https://www.krakend.io/schema/v2.7/krakend.json",
"version": 3,
"name": "KrakenD API Gateway",
"port": 8082,
"cache_ttl": "3600s",
"timeout": "3000ms",
"endpoints": [
{
"endpoint": "/api/items",
"method": "POST",
"output_encoding": "json",
"extra_config": {
"auth/validator": {
"alg": "RS256",
"jwk_url": "https://<THUNDERID_HOST>:8090/oauth2/jwks",
"disable_jwk_security": true,
"cache": true
}
},
"backend": [
{
"url_pattern": "/api/items",
"encoding": "json",
"method": "POST",
"host": [
"http://localhost:8081"
]
}
]
}
]
}

Configuration reference: See the full list of options in the JWT validation docs:

FieldValueDescription
algRS256Signing algorithm used by ThunderID
jwk_urlhttps://<THUNDERID_HOST>:<THUNDERID_PORT>/oauth2/jwksThunderID JWKS endpoint for fetching public keys
disable_jwk_securitytrueSkips TLS certificate verification. Use only in local development. Remove in production.
cachetrueCaches JWKS keys to avoid fetching them on every request

Restart KrakenD to apply the changes:

pkill -f "krakend run"
krakend run -c krakend.json

The log output confirms authentication is active:

KRAKEND INFO: Starting KrakenD v2.13.7
KRAKEND INFO: [SERVICE: Gin] Listening on port: 8082
KRAKEND DEBUG: [ENDPOINT: /api/items][JWTValidator] Validator enabled for this endpoint

Try It Out

Request without a token, expect 401 Unauthorized:

curl --location 'http://localhost:8082/api/items' \
--header 'Content-Type: application/json'

Request with a valid ThunderID token, expect 200 OK:

curl --location 'http://localhost:8082/api/items' \
--header 'Authorization: Bearer <ACCESS_TOKEN>' \
--header 'Content-Type: application/json'

Configure Scope-Based Authorization in KrakenD

JWT token validation confirms that a token is valid and was issued by ThunderID. It does not control what the token holder is allowed to do. With the configuration from the previous section, KrakenD accepts any valid ThunderID token regardless of the application or its assigned permissions.

Scope-based authorization adds a second layer of control. ThunderID embeds scopes in tokens based on the roles assigned to an application. KrakenD then checks those scopes on every request and rejects tokens that do not carry the required permissions. This lets you enforce scope-based access control, for example, restricting a read endpoint to tokens with item:read and a write endpoint to tokens with item:write, without changing the upstream service.

The steps below build on the JWT Token Validation from the previous section. You will define a Resource Server, a Resource, and actions in ThunderID to model your API permissions. Then bundle them into a role, assign the role to your application, and update the KrakenD configuration to enforce scope validation.

Configure ThunderID

Create a Resource Server

A Resource Server represents your API in ThunderID. The Resource Server groups all resources and actions under a single identifier and acts as the audience for tokens issued to clients of that API. For a full reference, see Resource Servers.

Using the Console:

  1. Sign in to the ThunderID Console at https://<THUNDER_PUBLIC_URL>/console.
  2. Navigate to Resource ServersNew Resource Server.
  3. Fill in the following fields:
    • Name: Booking API
    • Identifier: https://api.example.com/bookings
    • Description: Handles item operations
    • Delimiter: : (colon)
  4. Click Create.
  5. Note the Resource Server ID from the details page.

Create a Resource

A Resource represents a specific entity within the API, such as /api/items. Resources let you model your API surface so that permissions can be granted at a granular level.

Using the Console:

  1. Open the Booking API Resource Server.
  2. Go to the Resources tab and click New Resource.
  3. Fill in the following fields:
    • Name: Items
    • Handle: item
  4. Click Create.

Create Resource Actions

Actions define the operations allowed on a resource. Each action produces a scope in the format <resource-handle>:<action-handle>. ThunderID includes these scopes in tokens issued to applications that hold the corresponding role.

Using the Console:

  1. Under the Booking API Resource Server, open the Items resource.
  2. Go to the Actions tab and click New Action.
  3. Fill in the following fields:
    • Name: Read Item
    • Handle: read
    • Description: Permission to read an item
  4. Click Create.
  5. Note the generated permission shown in the action details: item:read.

Create a Role and assign permission

Roles bundle one or more permissions together. Assign roles to applications to control which scopes appear in their tokens.

  1. Navigate to RolesNew Role.
  2. Fill in the following fields:
    • Name: Booking Reader
  3. Click Continue.
  4. Under Assign permissions, choose item:read.
  5. Click Continue.

Assign a Role to the Application

Assign the role to the application you created in the previous section. ThunderID includes the role's scopes in every token issued for that application.

Using the Console:

  1. Navigate to Applications and open your Backend Service application.
  2. Go to the Roles tab.
  3. Click Assign Role, select Booking reader from the list, and confirm.

Configure KrakenD

Add scopes, scopes_key, and scopes_matcher to the auth/validator block you configured in the previous section. See the JWT validation docs for the full list of options.

{
"$schema": "https://www.krakend.io/schema/v2.7/krakend.json",
"version": 3,
"name": "KrakenD API Gateway",
"port": 8082,
"cache_ttl": "3600s",
"timeout": "3000ms",
"endpoints": [
{
"endpoint": "/api/items",
"method": "POST",
"output_encoding": "json",
"extra_config": {
"auth/validator": {
"alg": "RS256",
"jwk_url": "https://<THUNDERID_HOST>:<THUNDERID_PORT>/oauth2/jwks",
"disable_jwk_security": true,
"cache": true,
"scopes_key": "scope",
"scopes_matcher": "any",
"scopes": ["item:read"]
}
},
"backend": [
{
"url_pattern": "/api/items",
"encoding": "json",
"method": "POST",
"host": [
"http://localhost:8081"
]
}
]
}
]
}

Scope configuration reference:

FieldValueDescription
scopes_keyscopeJWT claim that stores scopes
scopes_matcheranyany: the token needs at least one matching scope; all: the token must carry every listed scope
scopes["item:read"]Required scopes to access this endpoint

Restart KrakenD to apply:

pkill -f "krakend run"
krakend run -c krakend.json

Try It Out

Obtain an Access Token with the Required Scope

Request a token for the application that has the role assigned:

curl --location 'https://<THUNDERID_HOST>:8090/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'scope=item:read' \
--data-urlencode 'client_id=<CLIENT_ID>' \
--data-urlencode 'client_secret=<CLIENT_SECRET>'

The response confirms the scope is present:

{
"access_token": "<ACCESS_TOKEN>",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "item:read"
}

Call the Protected API

With a token that has the required scope, expect 200 OK:

curl --location 'http://localhost:8082/api/items' \
--header 'Authorization: Bearer <ACCESS_TOKEN>' \
--header 'Content-Type: application/json'

With a token missing the required scope, expect 403 Forbidden:

curl --location 'http://localhost:8082/api/items' \
--header 'Authorization: Bearer <TOKEN_WITHOUT_REQUIRED_SCOPE>' \
--header 'Content-Type: application/json'

Explore with AI

ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© Copyright Linux Foundation Europe.For web site terms of use, trademark policy and other project policies please see https://linuxfoundation.eu/en/policies.