Uploaded image for project: 'Red Hat build of Keycloak'
  1. Red Hat build of Keycloak
  2. RHBK-3724

SPIFFE client authentication does not work when JWT SVID includes `iss` claim [GHI#43394]

XMLWordPrintable

    • False
    • Hide

      None

      Show
      None
    • False

      Before reporting an issue

      [x] I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.

      Area

      No response

      Describe the bug

      Attempting to obtain credentials using client assertion and SPIFFE Identity Provider and receiving an error obtaining credentials. See Actual Behavior for full details

      Environment Background

      • SPIFFE running on a Kubernetes cluster with federation endpoint exposed. Utilizing TLS certificates from public issuer to avoid TLS concerns
      • Using inspiration from this repository for setting up and configuring the scenario

      Version

      nightly, 26.4.0

      Regression

      [ ] The issue is a regression

      Expected behavior

      Credentials can be obtain using a SPIFFE provided JWT

      Actual behavior

      The follow error is reported on the client side

      {"error":"unauthorized_client","error_description":"Unexpected error when authenticating client"}
      

      The following error is returned on the server side

      2025-10-13 09:48:58,311 ERROR [org.keycloak.services] (executor-thread-25) KC-SERVICES0015: Unexpected error when authenticating client: java.lang.NullPointerException: Cannot invoke "org.keycloak.authentication.FlowStatus.toString()" because "status" is null
      	at org.keycloak.authentication.ClientAuthenticationFlow.processResult(ClientAuthenticationFlow.java:145)
      	at org.keycloak.authentication.ClientAuthenticationFlow.processFlow(ClientAuthenticationFlow.java:90)
      	at org.keycloak.authentication.AuthenticationProcessor.authenticateClient(AuthenticationProcessor.java:964)
      	at org.keycloak.protocol.oidc.utils.AuthorizeClientUtil.authorizeClient(AuthorizeClientUtil.java:49)
      	at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.checkClient(TokenEndpoint.java:178)
      	at org.keycloak.protocol.oidc.endpoints.TokenEndpoint.processGrantRequest(TokenEndpoint.java:134)
      	at org.keycloak.protocol.oidc.endpoints.TokenEndpoint$quarkusrestinvoker$processGrantRequest_3903cccf0670c489ab77dc2ba1ba757573ec6d78.invoke(Unknown Source)
      	at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
      	at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:183)
      	at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
      	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$15.runWith(VertxCoreRecorder.java:645)
      	at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2651)
      	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2630)
      	at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1622)
      	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1589)
      	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
      	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
      	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
      	at java.base/java.lang.Thread.run(Thread.java:1583)
      
      2025-10-13 09:48:58,315 WARN  [org.keycloak.events] (executor-thread-25) type="CLIENT_LOGIN_ERROR", realmId="64c60662-6d77-4577-b708-893ab39eabdf", realmName="spiffe", clientId="myclient", userId="null", ipAddress="192.168.127.1", error="invalid_client_credentials", grant_type="client_credentials", client_assertion_issuer="https://spire-spiffe-oidc-discovery-provider.mydomain.com", client_assertion_sub="spiffe://mydomain.com/sa/workload-app"
      

      How to Reproduce?

      Setup

      1. Start Keycloak locally

      podman run --rm --name mykeycloak -p 127.0.0.1:8080:8080 \
      

      -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=change_me \
      quay.io/keycloak/keycloak:nightly \
      start-dev -features=client-auth-federated,spiffe --spi-connections-http-clientdefault-disable-trust-manager=true

      
      

      3. Create realm called spiffe
      4. Create Identity Provider

      ./kcadm.sh create identity-provider/instances -r spiffe -f - << EOF
      {
        "alias": "https://spire-spiffe-oidc-discovery-provider.mydomain.com",
        "providerId": "spiffe",
        "hideOnLogin": true,
        "config": {
      

      "issuer": "spiffe://mydomain.com",
      "bundleEndpoint": "https://federation.mydomain.com"

        }
      }
      EOF
      

      4. Create Client

      ./kcadm.sh create clients -r spiffe  -f - << EOF
      {
        "clientId": "myclient",
        "serviceAccountsEnabled": true,
        "clientAuthenticatorType": "federated-jwt",
        "attributes": {
      

      "jwt.credential.issuer": "https://spire-spiffe-oidc-discovery-provider.mydomain.com",
      "jwt.credential.sub": "spiffe://mydomain.com/ns/spire-federated-identities/sa/workload-app"

        }
      }
      EOF
      

      5. Attempt to obtain credentials

      curl -s -X POST \ 
        -d grant_type=client_credentials \
        -d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-spiffe \
        -d client_assertion="$JWT_SVID" \
        -d client_id=myclient \
        http://localhost:8080/realms/spiffe/protocol/openid-connect/token
      

      Anything else?

      No response

              Unassigned Unassigned
              pvlha Pavel Vlha
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Created:
                Updated:
                Resolved: