|
| 1 | +# ZGW JWT tokens Introspection Provider for Keycloak |
| 2 | + |
| 3 | +This provider adds ZGW token verification and parsing to Keycloak. It exposes a realm endpoint that validates HS256-signed ZGW JWTs by looking up the token's `client_id` in Keycloak and verifying the signature with that client's secret, returning an OAuth2 token introspection response. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +Introspection endpoint: |
| 8 | +- Requires a `client_id` claim |
| 9 | +- Resolves the Keycloak client by `client_id` and verifies the HS256 signature using that client's secret stored in Keycloak (no external secret store) |
| 10 | +- Includes claims from any OIDC Hardcoded Claim protocol mappers configured in keycloak, on the client |
| 11 | +- Enforces token activity (validates `exp`/`nbf` when present) |
| 12 | +- Tokens without `exp` claim will be treated as active, but warning will be logged in keycloak. It's recommended to use short lived tokens. |
| 13 | + |
| 14 | +## Build |
| 15 | + |
| 16 | +1. Ensure you have Java 21 installed (download from https://learn.microsoft.com/en-us/java/openjdk/download) |
| 17 | +2. Download Maven `Binary zip archive` from https://maven.apache.org/download.cgi |
| 18 | +3. Add the bin directory of the created directory apache-maven-* to the PATH environment variable |
| 19 | +4. Run the following command to build the JAR: |
| 20 | + ```bash |
| 21 | + mvn clean package |
| 22 | + ``` |
| 23 | +5. The compiled JAR will be in the `target/` directory: `zgw-token-introspection.jar` |
| 24 | + |
| 25 | +## Deployment |
| 26 | + |
| 27 | +1. Copy the JAR file to your Keycloak deployment: |
| 28 | + - For host install: `{KEYCLOAK_HOME}/providers/` |
| 29 | + - For Docker: mount to `/opt/keycloak/providers/` |
| 30 | + |
| 31 | +2. Restart Keycloak. In dev: |
| 32 | + - `{KEYCLOAK_HOME}/bin/kc.sh start-dev` |
| 33 | + In prod: |
| 34 | + - `{KEYCLOAK_HOME}/bin/kc.sh build && {KEYCLOAK_HOME}/bin/kc.sh start` |
| 35 | + |
| 36 | +## Endpoint |
| 37 | + |
| 38 | +- Path: `/realms/{realm}/zgw-token-introspection/introspect` |
| 39 | +- Method: `POST` |
| 40 | +- Content-Type: `application/x-www-form-urlencoded` |
| 41 | +- Parameter: `token=<JWT>` |
| 42 | + |
| 43 | +## Token requirements |
| 44 | + |
| 45 | +The provider expects JWT tokens generated with the following characteristics: |
| 46 | + |
| 47 | +- **Algorithm**: HS256 |
| 48 | +- **Secret**: Client secret from Keycloak |
| 49 | +- **Required claim**: `client_id` (must match a client in the realm) |
| 50 | +- **Temporal**: Token must be active; `exp` is recommended |
| 51 | + |
| 52 | + |
| 53 | +## Usage |
| 54 | + |
| 55 | +Submit the token to the introspection endpoint: |
| 56 | +```bash |
| 57 | +curl -X POST \ |
| 58 | + "http://localhost:8080/realms/{realm}/zgw-token-introspection/introspect" \ |
| 59 | + -H "Content-Type: application/x-www-form-urlencoded" \ |
| 60 | + --data-urlencode "token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." |
| 61 | +``` |
| 62 | +Returns an OAuth2 introspection-style payload with selected standard and custom claims. |
| 63 | +On success you will receive `{ "active": true, ... }` and claim from token; otherwise `{ "active": false }`. |
| 64 | + |
| 65 | +## Troubleshooting |
| 66 | + |
| 67 | +- Check Keycloak logs for detailed error messages |
| 68 | +- Ensure the client exists in Keycloak and has a secret configured |
| 69 | +- Verify the token is properly formatted and not expired |
| 70 | +- Confirm the signing algorithm is HS256 |
| 71 | +- Make sure the client secret matches what was used to sign the token |
0 commit comments