This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-jbang-examples.git


The following commit(s) were added to refs/heads/main by this push:
     new 638cae7  Keycloak Token Introspection Support Example (#46)
638cae7 is described below

commit 638cae7409169b57fbeba14a1fd688438a4e3a55
Author: Andrea Cosentino <[email protected]>
AuthorDate: Tue Oct 21 12:12:38 2025 +0200

    Keycloak Token Introspection Support Example (#46)
    
    Signed-off-by: Andrea Cosentino <[email protected]>
---
 keycloak-introspection-rest/README.adoc            | 691 +++++++++++++++++++++
 keycloak-introspection-rest/application.properties |  39 ++
 keycloak-introspection-rest/rest-api.camel.yaml    | 207 ++++++
 3 files changed, 937 insertions(+)

diff --git a/keycloak-introspection-rest/README.adoc 
b/keycloak-introspection-rest/README.adoc
new file mode 100644
index 0000000..c57e47c
--- /dev/null
+++ b/keycloak-introspection-rest/README.adoc
@@ -0,0 +1,691 @@
+= Keycloak Token Introspection REST API
+
+This example demonstrates how to secure REST APIs using Apache Camel with 
Keycloak OAuth 2.0 Token Introspection (RFC 7662).
+It shows the difference between token introspection and standard JWT 
validation, highlighting the benefits of real-time token validation.
+
+== Features
+
+* Public endpoint accessible without authentication
+* Protected endpoints with two validation methods:
+  ** Token Introspection (RFC 7662) - Real-time validation via Keycloak
+  ** Standard JWT validation - Local signature verification
+* Integration with Keycloak using OAuth2/OpenID Connect
+* Real-time token revocation detection
+* Configurable introspection caching
+* Role-based access control (RBAC)
+* Comparison endpoint showing configuration details
+
+== What is Token Introspection?
+
+Token introspection is an OAuth 2.0 endpoint (RFC 7662) that allows you to 
validate tokens in real-time by querying the authorization server (Keycloak).
+
+=== Introspection vs. Local JWT Validation
+
+[cols="1,2,2", options="header"]
+|===
+|Feature
+|Token Introspection
+|Local JWT Validation
+
+|*Validation Speed*
+|Network call required (cached)
+|Very fast (local)
+
+|*Revocation Detection*
+|✅ Real-time detection
+|❌ No detection until expiration
+
+|*Offline Support*
+|❌ Requires Keycloak connectivity
+|✅ Works offline
+
+|*Security*
+|Excellent - always up-to-date
+|Good - trusts JWT signature
+
+|*Best For*
+|Security-critical operations, token revocation scenarios
+|High-throughput, trusted environments
+|===
+
+=== When to Use Introspection
+
+Use token introspection when:
+
+* You need to detect revoked tokens before their expiration
+* Security is critical (e.g., payment processing, admin operations)
+* You want centralized token validation
+* You have compliance requirements for real-time validation
+* You need to immediately invalidate sessions
+
+=== Performance Optimization
+
+This example includes caching to minimize performance impact:
+
+* **Cache Enabled**: Results are cached to reduce API calls
+* **Configurable TTL**: Balance security (lower TTL) and performance (higher 
TTL)
+* **Default TTL**: 120 seconds (2 minutes)
+
+== Prerequisites
+
+* JBang installed (https://www.jbang.dev)
+* Docker installed for running Keycloak
+* Basic understanding of OAuth2/OpenID Connect
+* Understanding of JWT tokens
+
+== Dependencies
+
+This example requires the `camel-keycloak` component.
+
+== Install JBang
+
+First install JBang according to https://www.jbang.dev
+
+When JBang is installed then you should be able to run from a shell:
+
+[source,sh]
+----
+$ jbang --version
+----
+
+This will output the version of JBang.
+
+To run this example you can either install Camel on JBang via:
+
+[source,sh]
+----
+$ jbang app install camel@apache/camel
+----
+
+Which allows to run Camel JBang with `camel` as shown below.
+
+== Running Keycloak
+
+=== Option 1: Using Camel JBang Infra (Recommended)
+
+Starting from Camel JBang 4.16.0-SNAPSHOT, you can easily run Keycloak using 
the built-in infrastructure support:
+
+[source,sh]
+----
+$ jbang -Dcamel.jbang.version=4.16.0-SNAPSHOT camel@apache/camel infra run 
keycloak
+----
+
+This will automatically start Keycloak configured with:
+* Admin username: `admin`
+* Admin password: `admin`
+* Port: `8080`
+
+Wait a few seconds for Keycloak to fully start before proceeding to 
configuration.
+
+To stop Keycloak later:
+
+[source,sh]
+----
+$ jbang -Dcamel.jbang.version=4.16.0-SNAPSHOT camel@apache/camel infra stop 
keycloak
+----
+
+=== Option 2: Using Docker Manually
+
+Alternatively, you can run Keycloak manually with Docker:
+
+[source,sh]
+----
+$ docker run -d \
+  --name keycloak \
+  -p 8180:8080 \
+  -e KEYCLOAK_ADMIN=admin \
+  -e KEYCLOAK_ADMIN_PASSWORD=admin \
+  quay.io/keycloak/keycloak:latest \
+  start-dev
+----
+
+Wait a few seconds for Keycloak to fully start before proceeding to 
configuration.
+
+== Keycloak Configuration
+
+After Keycloak starts, you need to configure it:
+
+=== 1. Access Keycloak Admin Console
+
+Open your browser and navigate to:
+* If using Camel JBang infra: http://localhost:8080
+* If using Docker manually: http://localhost:8180
+
+Login with:
+* Username: `admin`
+* Password: `admin`
+
+=== 2. Create a Realm
+
+1. Click on the dropdown in the top left (says "master")
+2. Click "Create Realm"
+3. Enter realm name: `camel`
+4. Click "Create"
+
+=== 3. Create a Client
+
+Token introspection requires a confidential client with client credentials.
+
+1. In the left menu, click "Clients"
+2. Click "Create client"
+3. Enter Client ID: `camel-client`
+4. Click "Next"
+5. **Enable "Client authentication"** (required for introspection)
+6. Enable "Service accounts roles"
+7. Enable "Direct access grants"
+8. Click "Next"
+9. Add Valid Redirect URIs: `http://localhost:8080/*`
+10. Click "Save"
+11. Go to the "Credentials" tab
+12. Copy the "Client Secret" value
+13. Update the `application.properties` file with this secret:
++
+[source,properties]
+----
+keycloak.client.secret=<your-client-secret>
+----
+
+IMPORTANT: Client authentication must be enabled for token introspection to 
work. This is because the introspection endpoint requires authentication with 
client credentials.
+
+=== 4. Create an Admin Role
+
+1. In the left menu, click "Realm roles"
+2. Click "Create role"
+3. Enter role name: `admin`
+4. Click "Save"
+
+=== 5. Create Users
+
+==== Create Regular User (without admin role)
+
+1. In the left menu, click "Users"
+2. Click "Add user"
+3. Enter username: `testuser`
+4. Enter email: `[email protected]`
+5. Enter first name: `Test`
+6. Enter last name: `User`
+7. Click "Create"
+8. Go to "Credentials" tab
+9. Click "Set password"
+10. Enter password: `password`
+11. Disable "Temporary" toggle
+12. Click "Save"
+
+==== Create Admin User (with admin role)
+
+1. In the left menu, click "Users"
+2. Click "Add user"
+3. Enter username: `admin-user`
+4. Enter email: `[email protected]`
+5. Enter first name: `Admin`
+6. Enter last name: `User`
+7. Click "Create"
+8. Go to "Credentials" tab
+9. Click "Set password"
+10. Enter password: `password`
+11. Disable "Temporary" toggle
+12. Click "Save"
+13. Go to "Role mapping" tab
+14. Click "Assign role"
+15. Select the `admin` role
+16. Click "Assign"
+
+== Running the Example
+
+After Keycloak is configured, start the Camel application:
+
+[source,sh]
+----
+$ jbang -Dcamel.jbang.version=4.16.0-SNAPSHOT camel@apache/camel run *
+----
+
+The application will start on port 8081 with the following endpoints:
+
+* `http://localhost:8081/api/public` - Public endpoint (no auth required)
+* `http://localhost:8081/api/info` - Info endpoint showing configuration
+* `http://localhost:8081/api/protected-introspection` - Protected with token 
introspection
+* `http://localhost:8081/api/protected-standard` - Protected with local JWT 
validation
+
+== Testing the Endpoints
+
+=== Test Info Endpoint
+
+View the configuration and available endpoints:
+
+[source,sh]
+----
+$ curl http://localhost:8081/api/info | jq
+----
+
+Expected response:
+[source,json]
+----
+{
+  "example": "Keycloak Token Introspection REST API",
+  "endpoints": {
+    "public": {
+      "path": "/api/public",
+      "security": "none",
+      "description": "Public endpoint, no authentication required"
+    },
+    "protected_introspection": {
+      "path": "/api/protected-introspection",
+      "security": "token_introspection",
+      "role": "admin",
+      "description": "Real-time token validation via Keycloak introspection 
endpoint (RFC 7662)",
+      "features": [
+        "Detects revoked tokens",
+        "Centralized validation",
+        "Caching enabled"
+      ]
+    },
+    "protected_standard": {
+      "path": "/api/protected-standard",
+      "security": "local_jwt",
+      "role": "admin",
+      "description": "Local JWT signature verification without introspection",
+      "features": [
+        "Fast offline validation",
+        "No network overhead",
+        "Cannot detect token revocation"
+      ]
+    }
+  },
+  "introspection_config": {
+    "enabled": "true",
+    "cache_enabled": "true",
+    "cache_ttl_seconds": "120"
+  }
+}
+----
+
+=== Test Public Endpoint (No Authentication)
+
+[source,sh]
+----
+$ curl http://localhost:8081/api/public | jq
+----
+
+Expected response:
+[source,json]
+----
+{
+  "message": "This is a public endpoint, no authentication required",
+  "timestamp": "2024-10-20T10:30:00",
+  "security": "none"
+}
+----
+
+=== Obtain Access Token
+
+Set the Keycloak port based on your setup:
+
+[source,sh]
+----
+# Use 8080 for camel infra, 8180 for manual Docker
+export KEYCLOAK_PORT=8080
+----
+
+Get an access token for the admin user:
+
+[source,sh]
+----
+export ADMIN_TOKEN=$(curl -X POST 
http://localhost:${KEYCLOAK_PORT}/realms/camel/protocol/openid-connect/token \
+  -H "Content-Type: application/x-www-form-urlencoded" \
+  -d "username=admin-user" \
+  -d "password=password" \
+  -d "grant_type=password" \
+  -d "client_id=camel-client" \
+  -d "client_secret=<your-client-secret>" \
+  | jq -r '.access_token')
+
+echo "Token obtained: ${ADMIN_TOKEN:0:50}..."
+----
+
+=== Test Protected Endpoint with Introspection
+
+[source,sh]
+----
+$ curl -H "Authorization: Bearer $ADMIN_TOKEN" \
+  http://localhost:8081/api/protected-introspection | jq
+----
+
+Expected response:
+[source,json]
+----
+{
+  "message": "This is a protected endpoint using Token Introspection (RFC 
7662)",
+  "timestamp": "2024-10-20T10:30:00",
+  "security": "introspection",
+  "role_required": "admin",
+  "validation": "real-time via Keycloak introspection endpoint",
+  "features": [
+    "Detects revoked tokens before expiration",
+    "Centralized validation",
+    "Caching enabled (TTL: 120s)"
+  ]
+}
+----
+
+=== Test Protected Endpoint with Standard JWT
+
+[source,sh]
+----
+$ curl -H "Authorization: Bearer $ADMIN_TOKEN" \
+  http://localhost:8081/api/protected-standard | jq
+----
+
+Expected response:
+[source,json]
+----
+{
+  "message": "This is a protected endpoint using standard JWT validation",
+  "timestamp": "2024-10-20T10:30:00",
+  "security": "local-jwt",
+  "role_required": "admin",
+  "validation": "local JWT signature verification",
+  "features": [
+    "Fast offline validation",
+    "No network calls to Keycloak",
+    "Cannot detect revoked tokens before expiration"
+  ]
+}
+----
+
+=== Test with Regular User (Should Fail)
+
+Try with a user who doesn't have the admin role:
+
+[source,sh]
+----
+export USER_TOKEN=$(curl -X POST 
http://localhost:${KEYCLOAK_PORT}/realms/camel/protocol/openid-connect/token \
+  -H "Content-Type: application/x-www-form-urlencoded" \
+  -d "username=testuser" \
+  -d "password=password" \
+  -d "grant_type=password" \
+  -d "client_id=camel-client" \
+  -d "client_secret=<your-client-secret>" \
+  | jq -r '.access_token')
+
+# This should fail with 403 Forbidden
+$ curl -i -H "Authorization: Bearer $USER_TOKEN" \
+  http://localhost:8081/api/protected-introspection
+----
+
+This will return a **403 Forbidden** error because `testuser` does not have 
the `admin` role.
+
+Expected error response:
+[source,json]
+----
+{
+  "error": "Forbidden",
+  "message": "Access denied. User does not have required roles: [admin]",
+  "timestamp": "2024-10-20T10:30:00",
+  "status": 403
+}
+----
+
+=== Test with Invalid/Missing Token
+
+[source,sh]
+----
+# Missing token - should return 403
+curl -i http://localhost:8081/api/protected-introspection
+
+# Invalid token - should return 403
+curl -i -H "Authorization: Bearer invalid_token_here" \
+  http://localhost:8081/api/protected-introspection
+----
+
+Both requests will return **403 Forbidden** with an appropriate error message.
+
+== Demonstrating Token Revocation
+
+One of the key benefits of token introspection is the ability to detect 
revoked tokens in real-time.
+
+=== Scenario: Logout a User and Test Token Validity
+
+1. **Get an access token** for admin-user (as shown above)
+
+2. **Verify the token works** with introspection:
++
+[source,sh]
+----
+# This should succeed
+curl -H "Authorization: Bearer $ADMIN_TOKEN" \
+  http://localhost:8081/api/protected-introspection
+----
+
+3. **Logout the user in Keycloak**:
++
+   * Go to Keycloak Admin Console
+   * Navigate to Users → Find "admin-user"
+   * Click on the user
+   * Go to "Sessions" tab
+   * Click "Sign out" to invalidate all sessions
+
+4. **Test with introspection endpoint** (should fail immediately):
++
+[source,sh]
+----
+# This will return 401/403 because the token is no longer active
+curl -i -H "Authorization: Bearer $ADMIN_TOKEN" \
+  http://localhost:8081/api/protected-introspection
+----
++
+The introspection endpoint will detect that the token has been revoked.
+
+5. **Test with standard JWT endpoint** (may still work until expiration):
++
+[source,sh]
+----
+# This might still succeed because local JWT validation
+# doesn't check with Keycloak about revocation
+curl -i -H "Authorization: Bearer $ADMIN_TOKEN" \
+  http://localhost:8081/api/protected-standard
+----
++
+The standard JWT endpoint may still allow access because it only validates the 
JWT signature locally without checking if the session is still active in 
Keycloak.
+
+This demonstrates the key advantage of token introspection: **real-time 
revocation detection**.
+
+== How It Works
+
+=== Security Policies
+
+The example defines two security policies in `rest-api.camel.yaml`:
+
+1. **Introspection Policy** - Uses Keycloak's introspection endpoint:
+
+[source,yaml]
+----
+- name: keycloakIntrospectionPolicy
+  type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
+  properties:
+    serverUrl: "{{keycloak.server.url}}"
+    realm: "{{keycloak.realm}}"
+    clientId: "{{keycloak.client.id}}"
+    clientSecret: "{{keycloak.client.secret}}"
+    requiredRoles: "admin"
+    useTokenIntrospection: true
+    introspectionCacheEnabled: true
+    introspectionCacheTtl: 120
+----
+
+2. **Standard Policy** - Uses local JWT parsing:
+
+[source,yaml]
+----
+- name: keycloakStandardPolicy
+  type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
+  properties:
+    serverUrl: "{{keycloak.server.url}}"
+    realm: "{{keycloak.realm}}"
+    clientId: "{{keycloak.client.id}}"
+    clientSecret: "{{keycloak.client.secret}}"
+    requiredRoles: "admin"
+    # useTokenIntrospection is false by default
+----
+
+=== Route Protection
+
+Routes are protected by referencing the appropriate policy:
+
+[source,yaml]
+----
+- route:
+    id: protected-introspection-api
+    from:
+      uri: "platform-http:/api/protected-introspection"
+      steps:
+        - policy:
+            ref: keycloakIntrospectionPolicy
+        - setBody:
+            simple: |
+              {
+                "message": "Protected with introspection"
+              }
+----
+
+=== Introspection Flow
+
+When a request arrives at the introspection-protected endpoint:
+
+1. **Extract Token**: Policy extracts the Bearer token from Authorization 
header
+2. **Check Cache**: If caching is enabled, check if result is cached
+3. **Call Introspection Endpoint**: If not cached, POST to Keycloak's 
introspection endpoint
+4. **Validate Response**: Check if token is active and has required roles
+5. **Cache Result**: Store result with TTL for subsequent requests
+6. **Allow/Deny**: Proceed with route or return 403 Forbidden
+
+== Monitoring Introspection Calls
+
+To see introspection in action, enable debug logging:
+
+Add to `application.properties`:
+
+[source,properties]
+----
+# Enable debug logging for Keycloak component
+logging.level.org.apache.camel.component.keycloak=DEBUG
+----
+
+You'll see logs like:
+
+[source]
+----
+[INFO] Introspecting token at: 
http://localhost:8080/realms/camel/protocol/openid-connect/token/introspect
+[DEBUG] Returning cached introspection result for token
+[DEBUG] Token is active: true, username: admin-user, scope: email profile
+----
+
+== Stopping
+
+To stop the Camel application, press `Ctrl+C`.
+
+To stop Keycloak:
+
+If you used Camel JBang infra:
+[source,sh]
+----
+$ jbang -Dcamel.jbang.version=4.16.0-SNAPSHOT camel@apache/camel infra stop 
keycloak
+----
+
+If you used Docker manually:
+[source,sh]
+----
+$ docker stop keycloak
+$ docker rm keycloak
+----
+
+== Troubleshooting
+
+=== 401 Unauthorized
+
+* Verify the access token is valid and not expired
+* Check that the Authorization header is properly formatted: `Bearer <token>`
+* Ensure the client secret in `application.properties` matches Keycloak
+* Verify client authentication is enabled in Keycloak (required for 
introspection)
+
+=== 403 Forbidden
+
+* Verify the user has the required role (admin role)
+* Check role assignments in Keycloak Admin Console
+* Ensure the token was obtained with the correct user credentials
+
+=== Connection Refused / Network Errors
+
+* Ensure Keycloak is running on the correct port (8080 for camel infra, 8180 
for Docker)
+* Verify the Keycloak server URL in `application.properties` matches your setup
+* Check network connectivity between Camel app and Keycloak
+
+=== Invalid Client Credentials
+
+* Check that the client ID and secret in `application.properties` match the 
Keycloak client configuration
+* Verify the realm name is correct
+* Ensure "Client authentication" is enabled in the Keycloak client settings
+
+=== Introspection Not Working
+
+* Verify `keycloak.introspection.enabled=true` in application.properties
+* Check that client is configured as confidential (client authentication 
enabled)
+* Ensure client has proper permissions for introspection
+* Review Keycloak logs for errors
+
+=== Slow Performance
+
+* Enable caching: `keycloak.introspection.cache.enabled=true`
+* Increase cache TTL: `keycloak.introspection.cache.ttl=300` (5 minutes)
+* Check network latency to Keycloak
+* Consider using standard JWT for non-critical endpoints
+
+== Architecture
+
+This example demonstrates:
+
+1. **Platform HTTP Component**: Provides HTTP server capabilities
+2. **Keycloak Security Policy**: Validates OAuth2 JWT tokens
+3. **Token Introspection (RFC 7662)**: Real-time token validation
+4. **Introspection Caching**: Reduces load on Keycloak
+5. **Role-Based Access Control**: Restricts endpoints based on user roles
+6. **RESTful API Design**: Multiple endpoints with different security levels
+
+== Best Practices
+
+1. **Use Introspection Selectively**: Apply introspection to security-critical 
endpoints, use JWT for high-throughput APIs
+2. **Enable Caching**: Always enable caching in production to reduce Keycloak 
load
+3. **Tune Cache TTL**: Balance security requirements with performance needs
+4. **Monitor Performance**: Track introspection call latency and adjust caching
+5. **Use HTTPS in Production**: Protect token transmission and introspection 
calls
+6. **Secure Client Secrets**: Use environment variables or secret management 
systems
+7. **Handle Failures Gracefully**: Implement error handling for network 
failures
+8. **Consider Circuit Breakers**: Protect against Keycloak downtime
+
+== Next Steps
+
+* Add refresh token handling
+* Implement multiple security levels for different endpoints
+* Add API documentation with OpenAPI/Swagger
+* Implement request/response logging
+* Add metrics and monitoring
+* Implement rate limiting
+* Add CORS configuration for web applications
+* Test token revocation scenarios
+* Implement session management
+
+== Learn More
+
+* https://tools.ietf.org/html/rfc7662[OAuth 2.0 Token Introspection (RFC 7662)]
+* https://camel.apache.org/components/latest/keycloak-component.html[Camel 
Keycloak Component Documentation]
+* https://www.keycloak.org/docs/latest/securing_apps/[Keycloak Securing 
Applications]
+* https://www.keycloak.org/docs/latest/authorization_services/[Keycloak 
Authorization Services]
+
+== Help and Contributions
+
+If you hit any problem using Camel or have some feedback, then please
+https://camel.apache.org/community/support/[let us know].
+
+We also love contributors, so
+https://camel.apache.org/community/contributing/[get involved] :-)
+
+The Camel riders!
diff --git a/keycloak-introspection-rest/application.properties 
b/keycloak-introspection-rest/application.properties
new file mode 100644
index 0000000..27b4d20
--- /dev/null
+++ b/keycloak-introspection-rest/application.properties
@@ -0,0 +1,39 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Keycloak Server Configuration
+# These properties are referenced by the security policy beans defined in 
rest-api.camel.yaml
+# Port 8080 is used when running Keycloak via: camel infra run keycloak
+# Port 8180 is used when running Keycloak manually via Docker (see README.adoc)
+keycloak.server.url=http://localhost:8080
+keycloak.realm=camel
+keycloak.client.id=camel-client
+keycloak.client.secret=************
+
+# Token Introspection Configuration
+# Enable token introspection for real-time validation
+# This allows detection of revoked tokens before their expiration
+keycloak.introspection.enabled=true
+# Enable caching to reduce load on Keycloak
+keycloak.introspection.cache.enabled=true
+# Cache TTL in seconds (120 = 2 minutes)
+# Balance between security (lower TTL) and performance (higher TTL)
+keycloak.introspection.cache.ttl=120
+
+# Additional Camel configuration
+camel.main.name = KeycloakIntrospectionRestExample
+camel.server.port=8081
diff --git a/keycloak-introspection-rest/rest-api.camel.yaml 
b/keycloak-introspection-rest/rest-api.camel.yaml
new file mode 100644
index 0000000..a29fae2
--- /dev/null
+++ b/keycloak-introspection-rest/rest-api.camel.yaml
@@ -0,0 +1,207 @@
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements.  See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License.  You may obtain a copy of the License at
+##
+##      http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+# camel-k: dependency=camel:keycloak
+
+# Global exception handler for authorization failures
+# Handles CamelAuthorizationException to return proper HTTP status codes
+- onException:
+    exception:
+      - "org.apache.camel.CamelAuthorizationException"
+    handled:
+      constant: true
+    steps:
+      - setHeader:
+          name: CamelHttpResponseCode
+          constant: 403
+      - setHeader:
+          name: Content-Type
+          constant: application/json
+      - setBody:
+          simple: |
+            {
+              "error": "Forbidden",
+              "message": "Access denied. ${exception.message}",
+              "timestamp": "${date:now:yyyy-MM-dd'T'HH:mm:ss}",
+              "status": 403
+            }
+      - log:
+          message: "Authorization failed: ${exception.message}"
+
+# Bean definition for Keycloak security policy with Token Introspection enabled
+# This policy validates tokens in real-time via Keycloak's introspection 
endpoint (RFC 7662)
+# Introspection allows detection of revoked tokens before their expiration time
+- beans:
+  - name: keycloakIntrospectionPolicy
+    type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
+    properties:
+      serverUrl: "{{keycloak.server.url}}"
+      realm: "{{keycloak.realm}}"
+      clientId: "{{keycloak.client.id}}"
+      clientSecret: "{{keycloak.client.secret}}"
+      requiredRoles: "admin"
+      # Enable OAuth 2.0 Token Introspection (RFC 7662)
+      useTokenIntrospection: "{{keycloak.introspection.enabled}}"
+      # Enable caching to reduce Keycloak API calls
+      introspectionCacheEnabled: "{{keycloak.introspection.cache.enabled}}"
+      # Cache TTL in seconds
+      introspectionCacheTtl: "{{keycloak.introspection.cache.ttl}}"
+
+  # Standard policy without introspection for comparison
+  - name: keycloakStandardPolicy
+    type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
+    properties:
+      serverUrl: "{{keycloak.server.url}}"
+      realm: "{{keycloak.realm}}"
+      clientId: "{{keycloak.client.id}}"
+      clientSecret: "{{keycloak.client.secret}}"
+      requiredRoles: "admin"
+      # Uses local JWT parsing (default, no introspection)
+
+# Public endpoint - no authentication required
+- route:
+    id: public-api
+    from:
+      uri: "platform-http:/api/public"
+      steps:
+        - setBody:
+            simple: |
+              {
+                "message": "This is a public endpoint, no authentication 
required",
+                "timestamp": "${date:now:yyyy-MM-dd'T'HH:mm:ss}",
+                "security": "none"
+              }
+        - setHeader:
+            name: Content-Type
+            constant: application/json
+        - log:
+            message: "Public API called"
+
+# Protected endpoint with Token Introspection - requires admin role
+# Tokens are validated in real-time via Keycloak's introspection endpoint
+# This allows detection of revoked tokens before their expiration
+- route:
+    id: protected-introspection-api
+    from:
+      uri: "platform-http:/api/protected-introspection"
+      steps:
+        - policy:
+            ref: keycloakIntrospectionPolicy
+        - setBody:
+            simple: |
+              {
+                "message": "This is a protected endpoint using Token 
Introspection (RFC 7662)",
+                "timestamp": "${date:now:yyyy-MM-dd'T'HH:mm:ss}",
+                "security": "introspection",
+                "role_required": "admin",
+                "validation": "real-time via Keycloak introspection endpoint",
+                "features": [
+                  "Detects revoked tokens before expiration",
+                  "Centralized validation",
+                  "Caching enabled (TTL: 
{{keycloak.introspection.cache.ttl}}s)"
+                ]
+              }
+        - setHeader:
+            name: Content-Type
+            constant: application/json
+        - log:
+            message: "Protected API with Introspection called successfully"
+
+# Protected endpoint with standard JWT validation (for comparison)
+# Uses local JWT parsing without contacting Keycloak
+- route:
+    id: protected-standard-api
+    from:
+      uri: "platform-http:/api/protected-standard"
+      steps:
+        - policy:
+            ref: keycloakStandardPolicy
+        - setBody:
+            simple: |
+              {
+                "message": "This is a protected endpoint using standard JWT 
validation",
+                "timestamp": "${date:now:yyyy-MM-dd'T'HH:mm:ss}",
+                "security": "local-jwt",
+                "role_required": "admin",
+                "validation": "local JWT signature verification",
+                "features": [
+                  "Fast offline validation",
+                  "No network calls to Keycloak",
+                  "Cannot detect revoked tokens before expiration"
+                ]
+              }
+        - setHeader:
+            name: Content-Type
+            constant: application/json
+        - log:
+            message: "Protected API with standard JWT called successfully"
+
+# Info endpoint - shows the difference between introspection and standard 
validation
+- route:
+    id: info-api
+    from:
+      uri: "platform-http:/api/info"
+      steps:
+        - setBody:
+            simple: |
+              {
+                "example": "Keycloak Token Introspection REST API",
+                "endpoints": {
+                  "public": {
+                    "path": "/api/public",
+                    "security": "none",
+                    "description": "Public endpoint, no authentication 
required"
+                  },
+                  "protected_introspection": {
+                    "path": "/api/protected-introspection",
+                    "security": "token_introspection",
+                    "role": "admin",
+                    "description": "Real-time token validation via Keycloak 
introspection endpoint (RFC 7662)",
+                    "features": [
+                      "Detects revoked tokens",
+                      "Centralized validation",
+                      "Caching enabled"
+                    ]
+                  },
+                  "protected_standard": {
+                    "path": "/api/protected-standard",
+                    "security": "local_jwt",
+                    "role": "admin",
+                    "description": "Local JWT signature verification without 
introspection",
+                    "features": [
+                      "Fast offline validation",
+                      "No network overhead",
+                      "Cannot detect token revocation"
+                    ]
+                  }
+                },
+                "introspection_config": {
+                  "enabled": "{{keycloak.introspection.enabled}}",
+                  "cache_enabled": "{{keycloak.introspection.cache.enabled}}",
+                  "cache_ttl_seconds": "{{keycloak.introspection.cache.ttl}}"
+                },
+                "keycloak_config": {
+                  "server_url": "{{keycloak.server.url}}",
+                  "realm": "{{keycloak.realm}}",
+                  "client_id": "{{keycloak.client.id}}"
+                }
+              }
+        - setHeader:
+            name: Content-Type
+            constant: application/json
+        - log:
+            message: "Info API called"

Reply via email to