Skip to main content

authz-keycloak

The authz-keycloak plugin integrates with Keycloak to authenticate and authorize users. See Keycloak's Authorization Services Guide for more information about the configuration options available in this plugin.

While the plugin was developed for Keycloak, it could theoretically be used with other OAuth/OIDC and UMA-compliant identity providers.

Examples

The examples below demonstrate how you can configure authz-keycloak for different scenarios.

To follow along, complete the preliminary setups for Keycloak.

Set Up Keycloak

Start Keycloak

Start a Keycloak instance named apisix-quickstart-keycloak with the administrator name quickstart-admin and password quickstart-admin-pass in development mode:

docker run -d --name "apisix-quickstart-keycloak" \
-e 'KEYCLOAK_ADMIN=quickstart-admin' \
-e 'KEYCLOAK_ADMIN_PASSWORD=quickstart-admin-pass' \
-p 8080:8080 \
quay.io/keycloak/keycloak:18.0.2 start-dev

Save Keycloak URL

Save the Keycloak URL to an environment variable to be referenced in future configuration:

KEYCLOAK_URL=http://192.168.42.145:8080    # replace with your Keycloak URL

Create a Realm, Client, and Authorization Objects

Navigate to http://localhost:8080 and click Administration Console:

Keycloak welcome page with the Administration Console tile highlighted

Sign in with the administrator username quickstart-admin and password quickstart-admin-pass:

Keycloak admin sign-in form

Create a realm named quickstart-realm:

Keycloak Add realm form with the realm name set to quickstart-realm and the Create button highlighted

Create a client named apisix-quickstart-client:

Keycloak Add client form

On the client settings page, select confidential as the access type:

Keycloak client settings with access type set to confidential

Enable authorization for the client and save the configuration. This should also enable the client service account and assign the uma_protection role automatically:

Keycloak client Settings tab with Service Accounts Enabled and Authorization Enabled toggles set to ON

Create a client scope named httpbin-access:

Saving a new Keycloak client scope

In the client's Authorization section, create the authorization scope access:

Keycloak client Authorization > Authorization Scopes tab with the Create button highlighted

Create the resource httpbin-anything with URI /anything and scope access:

Keycloak client Authorization > Resources tab listing the Default Resource, with the Create button highlighted

Create the client scope policy access-client-scope-policy that requires httpbin-access:

Keycloak client Authorization > Policies tab listing the Default Policy, with the Create Policy dropdown highlighted

Create the scope-based permission access-scope-perm that uses the access scope and access-client-scope-policy:

Adding a scope-based permission in Keycloak

Add httpbin-access to the default client scopes of apisix-quickstart-client:

Attaching a client scope to the Keycloak client

Create a user named quickstart-user:

Saving a new Keycloak user

Set the password to quickstart-user-pass and turn off Temporary:

Setting the password for the Keycloak user

Save the client secret from Clients > apisix-quickstart-client > Credentials:

Keycloak client credentials tab showing the generated client secret

Save the OIDC client ID and secret to environment variables:

OIDC_CLIENT_ID=apisix-quickstart-client
OIDC_CLIENT_SECRET=bSaIN3MV1YynmtXvU8lKkfeY0iwpr9cH # replace with your value
tip

If APISIX runs in Kubernetes, use the same Keycloak hostname consistently in both the plugin configuration and the token request. Otherwise, Keycloak may reject the bearer token because the token issuer does not match the configured authorization endpoints.

Request Access Token

Request an access token from Keycloak and save it to ACCESS_TOKEN:

ACCESS_TOKEN=$(curl -sS "$KEYCLOAK_URL/realms/quickstart-realm/protocol/openid-connect/token" \
-d 'grant_type=client_credentials' \
-d 'client_id='$OIDC_CLIENT_ID'' \
-d 'client_secret='$OIDC_CLIENT_SECRET'' | jq -r '.access_token')

Use Lazy Load Path and Resource Registration Endpoint

The examples below demonstrate how you can configure authz-keycloak to dynamically resolve the request URI to one or more resources using the resource registration endpoint instead of static permissions.

Create a route with authz-keycloak-route as follows:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "authz-keycloak-route",
"uri": "/anything",
"plugins": {
"authz-keycloak": {
"lazy_load_paths": true,
"resource_registration_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/authz/protection/resource_set",
"discovery": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/.well-known/uma2-configuration",
"client_id": "'"$OIDC_CLIENT_ID"'",
"client_secret": "'"$OIDC_CLIENT_SECRET"'"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

❶ Set lazy_load_paths to true.

❷ Set resource_registration_endpoint to Keycloak's UMA-compliant resource registration endpoint. Required when lazy_load_paths is true.

❸ Set discovery to the discovery document endpoint of Keycloak authorization services.

❹ Set client_id to the client ID created previously.

❺ Set client_secret to the client secret created previously. Required when lazy_load_paths is true.

Send a request to the route:

curl "http://127.0.0.1:9080/anything" -H "Authorization: Bearer $ACCESS_TOKEN"

You should see an HTTP/1.1 200 OK response similar to the following:

{
"args": {},
"data": "",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Authorization": "Bearer eyJhbGciOiJSU..."
},
"json": null,
"method": "GET",
"url": "http://127.0.0.1/anything"
}

Use Static Permissions

The examples below demonstrate how you can configure authz-keycloak to use the static permission httpbin-anything#access.

Create a route with authz-keycloak-route as follows:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "authz-keycloak-route",
"uri": "/anything",
"plugins": {
"authz-keycloak": {
"lazy_load_paths": false,
"discovery": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/.well-known/uma2-configuration",
"permissions": ["httpbin-anything#access"],
"client_id": "'"$OIDC_CLIENT_ID"'"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

❶ Set lazy_load_paths to false.

❷ Set discovery to the discovery document endpoint of Keycloak authorization services.

❸ Set permissions to resource httpbin-anything and scope access.

Send a request to the route:

curl "http://127.0.0.1:9080/anything" -H "Authorization: Bearer $ACCESS_TOKEN"

You should see an HTTP/1.1 200 OK response.

If you remove the client scope httpbin-access from apisix-quickstart-client, you should receive a 401 Unauthorized response when requesting the resource.

Generate Token with Password Grant at Custom Token Endpoint

The examples below demonstrate how you can configure authz-keycloak to request a token with the password grant at a custom endpoint.

Create a route with authz-keycloak-route as follows:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "authz-keycloak-route",
"uri": "/api/*",
"plugins": {
"authz-keycloak": {
"lazy_load_paths": true,
"resource_registration_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/authz/protection/resource_set",
"client_id": "'"$OIDC_CLIENT_ID"'",
"client_secret": "'"$OIDC_CLIENT_SECRET"'",
"token_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/protocol/openid-connect/token",
"password_grant_token_generation_incoming_uri": "/api/token"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

❶ Set token_endpoint to the Keycloak token endpoint. Required when the discovery document is not provided.

❷ Set password_grant_token_generation_incoming_uri to a custom URI path where users can obtain tokens.

Send a request to the configured token endpoint. The request should use the POST method and application/x-www-form-urlencoded as the Content-Type:

OIDC_USER=quickstart-user
OIDC_PASSWORD=quickstart-user-pass

curl "http://127.0.0.1:9080/api/token" -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Accept: application/json" \
-d 'username='$OIDC_USER'' \
-d 'password='$OIDC_PASSWORD''

You should see a JSON response with an access token similar to the following:

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIi...",
"expires_in": 300,
"refresh_expires_in": 1800,
"token_type": "Bearer",
"scope": "profile email httpbin-access"
}
API7.ai Logo

The digital world is connected by APIs,
API7.ai exists to make APIs more efficient, reliable, and secure.

Sign up for API7 newsletter

Product

API7 Gateway

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN PTE. LTD 2019 – 2026. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the Apache Software Foundation