Configure OpenID Connect with cert-bound access tokens
Certificate-bound access tokens allow binding tokens to clients. This guarantees the authenticity of the token by verifying whether the sender is authorized to use the token for accessing protected resources.
You can configure certificate-bound access token authentication with OpenID Connect by mounting your certificates into an IdP, like Keycloak, and configuring the IdP with a client and mTLS authentication. Then, configure the TLS Handshake Modifier plugin with config.tls_client_certificate
set to REQUEST
and the OIDC plugin with your IdP issuer, config.proof_of_possession_mtls
set to strict
, and enable config.proof_of_possession_auth_methods_validation
. Generate an access token and pass it in a request.
Prerequisites
Kong Konnect
This is a Konnect tutorial and requires a Konnect personal access token.
-
Create a new personal access token by opening the Konnect PAT page and selecting Generate Token.
-
Export your token to an environment variable:
export KONNECT_TOKEN='YOUR_KONNECT_PAT'
-
Run the quickstart script to automatically provision a Control Plane and Data Plane, and configure your environment:
curl -Ls https://get.konghq.com/quickstart | bash -s -- -k $KONNECT_TOKEN --deck-output
This sets up a Konnect Control Plane named
quickstart
, provisions a local Data Plane, and prints out the following environment variable exports:export DECK_KONNECT_TOKEN=$KONNECT_TOKEN export DECK_KONNECT_CONTROL_PLANE_NAME=quickstart export KONNECT_CONTROL_PLANE_URL=https://us.api.konghq.com export KONNECT_PROXY_URL='http://localhost:8000'
Copy and paste these into your terminal to configure your session.
Kong Gateway running
This tutorial requires Kong Gateway Enterprise. If you don’t have Kong Gateway set up yet, you can use the quickstart script with an enterprise license to get an instance of Kong Gateway running almost instantly.
-
Export your license to an environment variable:
export KONG_LICENSE_DATA='LICENSE-CONTENTS-GO-HERE'
-
Run the quickstart script:
curl -Ls https://get.konghq.com/quickstart | bash -s -- -e KONG_LICENSE_DATA
Once Kong Gateway is ready, you will see the following message:
Kong Gateway Ready
decK v1.43+
decK is a CLI tool for managing Kong Gateway declaratively with state files. To complete this tutorial, install decK version 1.43 or later.
This guide uses deck gateway apply
, which directly applies entity configuration to your Gateway instance.
We recommend upgrading your decK installation to take advantage of this tool.
You can check your current decK version with deck version
.
Required entities
For this tutorial, you’ll need Kong Gateway entities, like Gateway Services and Routes, pre-configured. These entities are essential for Kong Gateway to function but installing them isn’t the focus of this guide. Follow these steps to pre-configure them:
-
Run the following command:
echo ' _format_version: "3.0" services: - name: example-service url: http://httpbin.konghq.com/anything routes: - name: example-route paths: - "/anything" service: name: example-service ' | deck gateway apply -
To learn more about entities, you can read our entities documentation.
DNS hostname
In this tutorial, you’ll need a DNS hostname that you can use for your Keycloak server. You’ll need to replace the hostname in any commands in this tutorial with your own hostname.
Java
To complete this tutorial, you need Java 11.0.12 or later installed.
Java is required because we’re using keytool to create the CA JKS keystore with your root certificates.
Generate certificates
In this tutorial, you’ll need various certificates such as:
- CA certificate store
- Client certificate
- Server certificate
- Make an
/oidc/certs
directory to store the certificates and run the following steps from that directory:mkdir -p ~/oidc/certs && cd ~/oidc/certs
-
Run the following to help you generate a CA certificate:
openssl genrsa -out rootCA.key 4096 openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 \ -out rootCA.crt \ -subj "/C=US/ST=State/L=City/O=Organization/OU=Department/CN=Root CA" echo "Root CA certificate (rootCA.crt) generated successfully."
- Export the passwords you want to use for your PKCS#12 and keystore. Both must be at least six characters:
export PKCS12_PASSWORD='YOUR-PASSWORD' export KEYSTORE_PASS='YOUR-PASSWORD'
-
Generate the client certificate:
openssl genrsa -out client.key 2048 openssl req -new -key client.key -out client.csr \ -subj "/C=US/ST=State/L=City/O=ClientOrg/OU=Dev/CN=client-app" cat > client.ext <<EOF basicConstraints=CA:FALSE keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = clientAuth EOF openssl x509 -req \ -in client.csr \ -CA rootCA.crt -CAkey rootCA.key -CAcreateserial \ -out client.crt -days 365 -sha256 -extfile client.ext
-
Generate the server certificate:
Important: In this tutorial, use your DNS hostname in place of
your.hostname
.openssl genrsa -out keycloak.key 2048 openssl req -new -key keycloak.key -out keycloak.csr \ -subj "/C=US/ST=State/L=City/O=ClientOrg/OU=Dev/CN=your.hostname" cat > keycloak.ext <<EOF authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = your.hostname EOF openssl x509 -req \ -in keycloak.csr \ -CA rootCA.crt -CAkey rootCA.key -CAcreateserial \ -out keycloak.crt -days 365 -sha256 -extfile keycloak.ext
This is used to authenticate with Keycloak and to consume the API with access token. The generated CN must adhere to the pre-defined pattern for Keycloak validation.
- Build a PKCS#12 keystore file:
openssl pkcs12 -export \ -in keycloak.crt \ -inkey keycloak.key \ -certfile rootCA.crt \ -out keycloak-keystore.p12 \ -name keycloak \ -passout pass:$PKCS12_PASSWORD
-
Import the root certificates to the
.p12
file:keytool -importkeystore \ -deststorepass $KEYSTORE_PASS \ -destkeypass $KEYSTORE_PASS \ -destkeystore keycloak-keystore.jks \ -srckeystore keycloak-keystore.p12 \ -srcstoretype PKCS12 \ -srcstorepass $PKCS12_PASSWORD \ -alias keycloak
-
Configure Keycloak to trust certificates signed by the CA:
keytool -import -alias rootca \ -keystore keycloak-truststore.p12 \ -storetype PKCS12 \ -file rootCA.crt \ -storepass "$PKCS12_PASSWORD" keytool -list -keystore keycloak-truststore.p12 -storepass "$PKCS12_PASSWORD"
Type
y
when prompted to trust the certificate. The Keycloak server presents this certificate to the client.
Configure Keycloak
Important: You must run the following in a new terminal window because Keycloak’s container is started in the foreground.
- In a new terminal window, export your trust store password and hostname:
export PKCS12_PASSWORD='YOUR-PASSWORD' export HOSTNAME='YOUR-KEYCLOAK-HOSTNAME'
-
Then, start Keycloak in Docker:
Important: In this tutorial, use your DNS hostname in place of
your.hostname
.docker run \ -p 9443:9443 \ --network kong-quickstart-net \ -v $(pwd)/oidc/certs:/opt/keycloak/ssl \ -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \ -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \ --name keycloak \ quay.io/keycloak/keycloak \ start \ --https-port=9443 \ --https-certificate-file=/opt/keycloak/ssl/keycloak.crt \ --https-certificate-key-file=/opt/keycloak/ssl/keycloak.key \ --https-trust-store-file=/opt/keycloak/ssl/keycloak-truststore.p12 \ --https-trust-store-password=$PKCS12_PASSWORD \ --https-client-auth=request \ --hostname=your.hostname
- Open the Keycloak admin console.
The default URL of the console is
https://your.hostname:9443/admin/master/console/
. - In the sidebar, open Clients, then click Create client.
-
Configure the client:
Section
Settings
General settings - Client type: OpenID Connect
- Client ID: any unique name, for example
kong
Capability config - Enable Client authentication
- Enable Authorization
- Select Standard flow, Direct access grants, and Service accounts roles
- Click the Credentials tab.
- Select “X509 Certificate” from the Client Authenticator dropdown menu.
- Enter
CN=client-app, OU=Dev, O=ClientOrg, L=City, ST=State, C=US
in the Subject DN field. - Click Save and agree to the change.
- Click the Advanced tab.
- In Advanced settings, enable OAuth 2.0 Mutual TLS Certificate Bound Access Tokens Enabled.
- Click Save at the bottom of the Advanced settings section.
- Export your issuer:
export DECK_ISSUER='https://your.hostname:9443/realms/master'
Important: In this tutorial, use your DNS hostname in place of
your.hostname
.
Enable TLS handshake plugin
Configure the TLS Handshake Modifier plugin to request that the client to send a client certificate:
echo '
_format_version: "3.0"
plugins:
- name: tls-handshake-modifier
route: example-route
config:
tls_client_certificate: REQUEST
' | deck gateway apply -
Alternatively, you can use the Mutual TLS Authentication plugin instead.
Enable the OpenID Connect plugin
Using the Keycloak and Kong Gateway configuration from the prerequisites, set up an instance of the OpenID Connect plugin.
Enable the OpenID Connect plugin on the example-service
Service:
echo '
_format_version: "3.0"
plugins:
- name: openid-connect
route: example-route
config:
issuer: "${{ env "DECK_ISSUER" }}"
auth_methods:
- bearer
proof_of_possession_mtls: strict
proof_of_possession_auth_methods_validation: true
' | deck gateway apply -
In this example:
-
issuer
: Settings that connect the plugin to your IdP (in this case, the sample Keycloak app). -
proof_of_possession_mtls
: By setting this tostrict
, it ensures all tokens are verified. -
proof_of_possession_auth_methods_validation
: Ensures that only theauth_methods
that are compatible with Proof of Possession (PoP) can be configured when PoP is enabled.
Generate the access token
Now, you can generate your access token to authenticate with certificate-bound authentication.
Navigate to the /oidc/certs
you created previously and generate the access token:
curl -s --location --request POST 'https://your.hostname:9443/realms/master/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=kong' \
--data-urlencode 'grant_type=client_credentials' \
--cert client.crt \
--key client.key \
--cacert rootCA.crt | jq -r .access_token
Important: In this tutorial, use your DNS hostname in place of
your.hostname
.
Export the access token:
export ACCESS_TOKEN='YOUR-ACCESS-TOKEN'
The access token, by default, expires in 60 seconds. If you want to extend the expiration, you can configure this in the Keycloak Advanced settings for the client by adjusting the Access Token Lifespan settings.
Validate the OpenID Connect plugin configuration
Request the Service with the Keycloak access token:
curl -isk \
-X GET "https://localhost:8443/anything" \
-H "Authorization:Bearer $ACCESS_TOKEN" \
--cert client.crt \
--key client.key
You should get an HTTP 200
response.
Cleanup
Clean up Konnect environment
If you created a new control plane and want to conserve your free trial credits or avoid unnecessary charges, delete the new control plane used in this tutorial.
Destroy the Kong Gateway container
curl -Ls https://get.konghq.com/quickstart | bash -s -- -d