Token transformationv1.0+
Use the OpenID Connect plugin to switch an external token with limited scope for an internal token with necessary scope.
In this example, clients are registered in the same AuthZ server as the one protecting the upstream services. However, clients are restricted and are issued tokens with limited scopes for security reasons. Kong Gateway is a special client that is authorized to request a token (with appropriate scope) to access the upstream services. on behalf of these other clients. Kong exchanges the incoming token for a new token with the right scope to access the upstream services.
Here’s how token exchange works with the OIDC plugin:
sequenceDiagram
participant C as Client
(e.g. mobile app)
participant K as API Gateway
with OIDC plugin
participant A as Authorization server
(e.g. Keycloak)
participant U as Upstream
(backend service,
e.g. httpbin)
C->>K: Request with subject token
activate K
note over K: Validate subject token
(iss, exp, nbf)
K->>A: Token exchange request
activate A
A-->>K: Exchanged access token
deactivate A
K->>K: Validate exchanged token
K->>U: Proxy request with exchanged token
activate U
U-->>K: Response
deactivate U
K-->>C: Response
deactivate K
Prerequisites
- An identity provider (IdPs) that supports token exchange, configured with two clients. Client A is limited in what it can request, while Client 2 is authorized to do token exchange and request specific scopes.
Environment variables
-
ISSUER: The issuer authentication URL for the authorization server that issued the token in the incoming request. For example, if you’re using Keycloak as your IdP, the issuer URL looks like this:http://localhost:8080/realms/example-realm. -
CLIENT_ID: The client ID that the plugin uses when it calls authenticated endpoints of the IdP (in this case, Server A). -
CLIENT_SECRET: The client secret needed to connect to your IdP (in this case, Server A).
Add this section to your kong.yaml configuration file:
_format_version: "3.0"
plugins:
- name: openid-connect
config:
issuer: ${{ env "DECK_ISSUER" }}
client_id:
- ${{ env "DECK_CLIENT_ID" }}
client_secret:
- ${{ env "DECK_CLIENT_SECRET" }}
client_auth:
- client_secret_post
auth_methods:
- bearer
token_exchange:
subject_token_issuers:
- issuer: ${{ env "DECK_ISSUER" }}
conditions:
missing_audience:
has_audience:
missing_scopes:
- profile
has_scopes:
request:
empty_audience: false
scopes:
empty_scopes: false
audience:
Make the following request:
curl -i -X POST http://localhost:8001/plugins/ \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '
{
"name": "openid-connect",
"config": {
"issuer": "'$ISSUER'",
"client_id": [
"'$CLIENT_ID'"
],
"client_secret": [
"'$CLIENT_SECRET'"
],
"client_auth": [
"client_secret_post"
],
"auth_methods": [
"bearer"
],
"token_exchange": {
"subject_token_issuers": [
{
"issuer": "'$ISSUER'",
"conditions": {
"missing_audience": null,
"has_audience": null,
"missing_scopes": [
"profile"
],
"has_scopes": null
}
}
],
"request": {
"empty_audience": false,
"scopes": null,
"empty_scopes": false,
"audience": null
}
}
},
"tags": []
}
'
echo "
apiVersion: configuration.konghq.com/v1
kind: KongClusterPlugin
metadata:
name: openid-connect
namespace: kong
annotations:
kubernetes.io/ingress.class: kong
konghq.com/tags: ''
labels:
global: 'true'
config:
issuer: '$ISSUER'
client_id:
- '$CLIENT_ID'
client_secret:
- '$CLIENT_SECRET'
client_auth:
- client_secret_post
auth_methods:
- bearer
token_exchange:
subject_token_issuers:
- issuer: '$ISSUER'
conditions:
missing_audience:
has_audience:
missing_scopes:
- profile
has_scopes:
request:
empty_audience: false
scopes:
empty_scopes: false
audience:
plugin: openid-connect
" | kubectl apply -f -
Prerequisite: Configure your Personal Access Token
terraform {
required_providers {
konnect = {
source = "kong/konnect"
}
}
}
provider "konnect" {
personal_access_token = "$KONNECT_TOKEN"
server_url = "https://us.api.konghq.com/"
}
Add the following to your Terraform configuration to create a Konnect Gateway Plugin:
resource "konnect_gateway_plugin_openid_connect" "my_openid_connect" {
enabled = true
config = {
issuer = var.issuer
client_id = [var.client_id]
client_secret = [var.client_secret]
client_auth = ["client_secret_post"]
auth_methods = ["bearer"]
token_exchange = {
subject_token_issuers = [
{
issuer = var.issuer
conditions = {
missing_audience =
has_audience =
missing_scopes = ["profile"]
has_scopes =
}
} ]
request = {
empty_audience = false
scopes =
empty_scopes = false
audience =
}
}
}
tags = []
control_plane_id = konnect_gateway_control_plane.my_konnect_cp.id
}
This example requires the following variables to be added to your manifest. You can specify values at runtime by setting TF_VAR_name=value.
variable "client_secret" {
type = string
}
Add this section to your kong.yaml configuration file:
_format_version: "3.0"
plugins:
- name: openid-connect
service: serviceName|Id
config:
issuer: ${{ env "DECK_ISSUER" }}
client_id:
- ${{ env "DECK_CLIENT_ID" }}
client_secret:
- ${{ env "DECK_CLIENT_SECRET" }}
client_auth:
- client_secret_post
auth_methods:
- bearer
token_exchange:
subject_token_issuers:
- issuer: ${{ env "DECK_ISSUER" }}
conditions:
missing_audience:
has_audience:
missing_scopes:
- profile
has_scopes:
request:
empty_audience: false
scopes:
empty_scopes: false
audience:
Make sure to replace the following placeholders with your own values:
-
serviceName|Id: Theidornameof the service the plugin configuration will target.
Make the following request:
curl -i -X POST http://localhost:8001/services/{serviceName|Id}/plugins/ \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '
{
"name": "openid-connect",
"config": {
"issuer": "'$ISSUER'",
"client_id": [
"'$CLIENT_ID'"
],
"client_secret": [
"'$CLIENT_SECRET'"
],
"client_auth": [
"client_secret_post"
],
"auth_methods": [
"bearer"
],
"token_exchange": {
"subject_token_issuers": [
{
"issuer": "'$ISSUER'",
"conditions": {
"missing_audience": null,
"has_audience": null,
"missing_scopes": [
"profile"
],
"has_scopes": null
}
}
],
"request": {
"empty_audience": false,
"scopes": null,
"empty_scopes": false,
"audience": null
}
}
},
"tags": []
}
'
Make sure to replace the following placeholders with your own values:
-
serviceName|Id: Theidornameof the service the plugin configuration will target.
echo "
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: openid-connect
namespace: kong
annotations:
kubernetes.io/ingress.class: kong
konghq.com/tags: ''
config:
issuer: '$ISSUER'
client_id:
- '$CLIENT_ID'
client_secret:
- '$CLIENT_SECRET'
client_auth:
- client_secret_post
auth_methods:
- bearer
token_exchange:
subject_token_issuers:
- issuer: '$ISSUER'
conditions:
missing_audience:
has_audience:
missing_scopes:
- profile
has_scopes:
request:
empty_audience: false
scopes:
empty_scopes: false
audience:
plugin: openid-connect
" | kubectl apply -f -
Next, apply the KongPlugin resource by annotating the service resource:
kubectl annotate -n kong service SERVICE_NAME konghq.com/plugins=openid-connect
Prerequisite: Configure your Personal Access Token
terraform {
required_providers {
konnect = {
source = "kong/konnect"
}
}
}
provider "konnect" {
personal_access_token = "$KONNECT_TOKEN"
server_url = "https://us.api.konghq.com/"
}
Add the following to your Terraform configuration to create a Konnect Gateway Plugin:
resource "konnect_gateway_plugin_openid_connect" "my_openid_connect" {
enabled = true
config = {
issuer = var.issuer
client_id = [var.client_id]
client_secret = [var.client_secret]
client_auth = ["client_secret_post"]
auth_methods = ["bearer"]
token_exchange = {
subject_token_issuers = [
{
issuer = var.issuer
conditions = {
missing_audience =
has_audience =
missing_scopes = ["profile"]
has_scopes =
}
} ]
request = {
empty_audience = false
scopes =
empty_scopes = false
audience =
}
}
}
tags = []
control_plane_id = konnect_gateway_control_plane.my_konnect_cp.id
service = {
id = konnect_gateway_service.my_service.id
}
}
This example requires the following variables to be added to your manifest. You can specify values at runtime by setting TF_VAR_name=value.
variable "client_secret" {
type = string
}
Add this section to your kong.yaml configuration file:
_format_version: "3.0"
plugins:
- name: openid-connect
route: routeName|Id
config:
issuer: ${{ env "DECK_ISSUER" }}
client_id:
- ${{ env "DECK_CLIENT_ID" }}
client_secret:
- ${{ env "DECK_CLIENT_SECRET" }}
client_auth:
- client_secret_post
auth_methods:
- bearer
token_exchange:
subject_token_issuers:
- issuer: ${{ env "DECK_ISSUER" }}
conditions:
missing_audience:
has_audience:
missing_scopes:
- profile
has_scopes:
request:
empty_audience: false
scopes:
empty_scopes: false
audience:
Make sure to replace the following placeholders with your own values:
-
routeName|Id: Theidornameof the route the plugin configuration will target.
Make the following request:
curl -i -X POST http://localhost:8001/routes/{routeName|Id}/plugins/ \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '
{
"name": "openid-connect",
"config": {
"issuer": "'$ISSUER'",
"client_id": [
"'$CLIENT_ID'"
],
"client_secret": [
"'$CLIENT_SECRET'"
],
"client_auth": [
"client_secret_post"
],
"auth_methods": [
"bearer"
],
"token_exchange": {
"subject_token_issuers": [
{
"issuer": "'$ISSUER'",
"conditions": {
"missing_audience": null,
"has_audience": null,
"missing_scopes": [
"profile"
],
"has_scopes": null
}
}
],
"request": {
"empty_audience": false,
"scopes": null,
"empty_scopes": false,
"audience": null
}
}
},
"tags": []
}
'
Make sure to replace the following placeholders with your own values:
-
routeName|Id: Theidornameof the route the plugin configuration will target.
echo "
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: openid-connect
namespace: kong
annotations:
kubernetes.io/ingress.class: kong
konghq.com/tags: ''
config:
issuer: '$ISSUER'
client_id:
- '$CLIENT_ID'
client_secret:
- '$CLIENT_SECRET'
client_auth:
- client_secret_post
auth_methods:
- bearer
token_exchange:
subject_token_issuers:
- issuer: '$ISSUER'
conditions:
missing_audience:
has_audience:
missing_scopes:
- profile
has_scopes:
request:
empty_audience: false
scopes:
empty_scopes: false
audience:
plugin: openid-connect
" | kubectl apply -f -
Next, apply the KongPlugin resource by annotating the httproute or ingress resource:
kubectl annotate -n kong httproute konghq.com/plugins=openid-connect
kubectl annotate -n kong ingress konghq.com/plugins=openid-connect
Prerequisite: Configure your Personal Access Token
terraform {
required_providers {
konnect = {
source = "kong/konnect"
}
}
}
provider "konnect" {
personal_access_token = "$KONNECT_TOKEN"
server_url = "https://us.api.konghq.com/"
}
Add the following to your Terraform configuration to create a Konnect Gateway Plugin:
resource "konnect_gateway_plugin_openid_connect" "my_openid_connect" {
enabled = true
config = {
issuer = var.issuer
client_id = [var.client_id]
client_secret = [var.client_secret]
client_auth = ["client_secret_post"]
auth_methods = ["bearer"]
token_exchange = {
subject_token_issuers = [
{
issuer = var.issuer
conditions = {
missing_audience =
has_audience =
missing_scopes = ["profile"]
has_scopes =
}
} ]
request = {
empty_audience = false
scopes =
empty_scopes = false
audience =
}
}
}
tags = []
control_plane_id = konnect_gateway_control_plane.my_konnect_cp.id
route = {
id = konnect_gateway_route.my_route.id
}
}
This example requires the following variables to be added to your manifest. You can specify values at runtime by setting TF_VAR_name=value.
variable "client_secret" {
type = string
}