Skip to content

feat(auth): support signed JWT client assertions - #1678

Merged
Motouom merged 2 commits into
adorsys:mainfrom
slaskawi:feat/signed-jwt-client-assertions
Oct 23, 2026
Merged

Motouom merged 2 commits into
adorsys:mainfrom
slaskawi:feat/signed-jwt-client-assertions

Conversation

@slaskawi

@slaskawi slaskawi commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

feat(auth): support signed JWT client assertions

What this PR does / why we need it:

"Signed JWT - Federated" Client Authentication is one of the recent add-ons in Keycloak. The implementation uses OAuth 2.0 Client Assertions which an authentication mechanism suitable for service accounts, which assumes short-lived workload identity tokens, so the CLI does not need to store static credentials or client secrets.

This implementation focuses on supporting Kubernetes Service Account Tokens and can be easily extended for supporting SPIFFE JWT SVIDs. However the latter is a preview feature in Keycloak as the spec is still in draft. We'll probably need to wait a few more releases until it's fully supported.

Highlights of this Pull Request:

  • Adds file-backed Client Assertions for token, refresh, and logout requests.
  • Re-reads the assertion file for every authentication request so projected Kubernetes tokens rotate without application caching.
  • Keeps assertion retrieval behind ClientAssertionProvider so sources such as SPIFFE JWT-SVIDs can be added independently.
  • Documents Keycloak feature requirements and a Kubernetes Job example.
  • Adds a Keycloak 26.6 compatibility lane alongside the existing 26.5 lane.

Which issue this PR fixes (optional, in fixes #<issue number>(, fixes #<issue_number>, ...) format, will close that issue when PR gets merged): N/A — no issue supplied.

How this PR was tested:

Automatically tested in CI across supported Keycloak versions, Java 17 and Java 21, including dedicated Client Assertion tests for token rotation, token requests, logout, configuration, and log redaction.

Screenshots / logs (if relevant): N/A.

Special notes for your reviewer:

This addition would provide a lot of benefits for platforms that do not store credentials, such as UDS Core. We've been experimenting with this approach recently: defenseunicorns/uds-identity-config#853

PR Readiness Checklist:

Complete these before marking the PR as ready to review:

  • tests pass locally (mvn test or relevant subset)
  • added/updated tests for the changes (if applicable)
  • documentation has been updated (if applicable)
  • the CHANGELOG.md release notes have been updated to reflect any significant (and particularly user-facing) changes introduced by this PR

@slaskawi
slaskawi force-pushed the feat/signed-jwt-client-assertions branch 2 times, most recently from 18a850b to c309f67 Compare September 13, 2026 17:58
Signed-off-by: Sebastian Łaskawiec <sebastian.laskawiec@defenseunicorns.com>
@slaskawi
slaskawi force-pushed the feat/signed-jwt-client-assertions branch from c309f67 to c82ef33 Compare September 13, 2026 18:17
@sonarqubecloud

Copy link
Copy Markdown

@slaskawi
slaskawi marked this pull request as ready for review September 14, 2026 05:53
Copilot AI lite review requested due to automatic review settings September 14, 2026 05:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved logout client_id issues affect production authentication, and the README example is incomplete.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds file-backed signed JWT client assertion support for Keycloak, including rotating Kubernetes service-account tokens, request filtering, redaction, tests, documentation, and CI coverage.

Changes:

  • Adds configurable assertion providers and request integration.
  • Adds sensitive-data redaction and token/logout test coverage.
  • Documents Kubernetes usage and adds Keycloak 26.6 CI coverage.
File summaries
File Reviewed change
src/test/resources/client-assertion-token Provides assertion test data.
src/test/java/de/adorsys/keycloak/config/util/resteasy/FileClientAssertionProviderTest.java Tests file-backed assertion loading and validation.
src/test/java/de/adorsys/keycloak/config/util/resteasy/ClientAssertionFilterTest.java Tests assertion request mutation.
src/test/java/de/adorsys/keycloak/config/util/logging/SensitiveDataSanitizingFilterTest.java Tests assertion redaction.
src/test/java/de/adorsys/keycloak/config/provider/KeycloakProviderTest.java Tests provider construction.
src/test/java/de/adorsys/keycloak/config/properties/KeycloakConfigPropertiesTest.java Tests configuration binding.
src/test/java/de/adorsys/keycloak/config/mock/ClientAssertionMockIT.java Tests token and logout flows; logout should verify client_id.
src/test/java/de/adorsys/keycloak/config/AbstractImportIT.java Enables required Keycloak features.
src/main/java/de/adorsys/keycloak/config/util/resteasy/FileClientAssertionProvider.java Reads assertions from files.
src/main/java/de/adorsys/keycloak/config/util/resteasy/ClientAssertionProvider.java Defines the assertion provider interface.
src/main/java/de/adorsys/keycloak/config/util/resteasy/ClientAssertionFilter.java Injects assertions; must preserve client_id and remove only client_secret.
src/main/java/de/adorsys/keycloak/config/util/logging/SensitiveDataSanitizingFilter.java Redacts sensitive assertion data from logs.
src/main/java/de/adorsys/keycloak/config/provider/KeycloakProvider.java Integrates assertion authentication; logout must include the configured client ID.
src/main/java/de/adorsys/keycloak/config/properties/KeycloakConfigProperties.java Adds assertion-file configuration.
README.md Documents configuration and Kubernetes usage; the non-master example needs KEYCLOAK_SKIPSERVERINFO=true.
CHANGELOG.md Records the new feature.
.github/workflows/ci.yaml Adds Keycloak 26.6 CI coverage.
Review details

Suppressed comments (2)

README.md:337

  • This example logs into the non-master kubernetes realm but does not set KEYCLOAK_SKIPSERVERINFO=true. The option table above documents that this is required for non-master realm authentication, and the provider otherwise fetches server info during initialization, so following this example can fail before the import starts. Add the missing environment variable.
            - name: KEYCLOAK_LOGINREALM
              value: kubernetes
            - name: KEYCLOAK_GRANTTYPE
              value: client_credentials
            - name: KEYCLOAK_CLIENTID

src/test/java/de/adorsys/keycloak/config/mock/ClientAssertionMockIT.java:73

  • These assertions encode the opposite of the logout endpoint's contract. Real Keycloak requires client_id to identify the client before authenticating the assertion, but this mock accepts the request without validating it, so the test currently passes for a request that production rejects. Assert that the configured client ID is present instead.
            assertThat(body, not(containsString("client_id=")));
  • Files reviewed: 17/17 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@chance-coleman chance-coleman left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. No issues found in testing locally. CI is green. Approving.

@slaskawi

Copy link
Copy Markdown
Contributor Author

Hey @Nkwenti-Severian-Ndongtsop 👋🏻

Could I kindly ask you to have a look at this PR?

Thank you 🙏🏻

@slaskawi

Copy link
Copy Markdown
Contributor Author

Hey @AssahBismarkabah 👋🏻

Could I kindly ask you to have a look at this PR?

Thank you 🙏🏻

@AssahBismarkabah

Copy link
Copy Markdown
Collaborator

@slaskawi Apologies for the delayed response. I'll look into this

@AssahBismarkabah

Copy link
Copy Markdown
Collaborator

Reviewed. No issues found in testing locally. CI is green. Approving.

@chance-coleman Based on your testing, did you encounter any edge cases or potential issues, or does everything look good?

@Motouom
Motouom self-requested a review October 23, 2026 07:59
@sonarqubecloud

Copy link
Copy Markdown

@Motouom Motouom left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the resolved conflicts and final diff. Local mvnw clean install passed with 349 tests, Checkstyle, SpotBugs, and the dedicated client-assertion test. The Keycloak 26.6.2 CLI JSON import/idempotence test passed, and GitHub CI run 3612 passed across the required matrix. Approving.

@Motouom
Motouom merged commit b857279 into adorsys:main Oct 23, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants