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:

admin-console

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

admin-signin

Create a realm named quickstart-realm:

add-realm

Create a client named apisix-quickstart-client:

add-client

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

client-access-type-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:

enable-authorization

Create a client scope named httpbin-access:

save-client-scope

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

add-scope

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

create-resource

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

create-policy

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

add-scope-permission

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

add-client-scope

Create a user named quickstart-user:

save-user

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

set-password

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

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