Search code examples
keycloak

Getting Keycloak's public key


I realized there are many iterations of this questions. But I can't seem to understand the answer correctly.

We have secured our rabbitmq and rest endpoints with a oauth2 spring server similar to this post. But it doesn't have all of the features we need and want. So we would like to use Keycloak. I have been successful with securing the rest endpoint by just going to the new version of spring security 5.1 and specifing the security.oauth2.resource.jwk.key-set-uri and setting the necessary dependencies and configuration.

While trying to secure the RabbitMQ, I have been running into problems checking the bearer token from the message header because the keycloak jwks endpoint isn't returning the true RSA public key.

RabbitMQ uses the CustomMessageListenerContainer to get the token from the message header and uses the DefaultTokenServices to check the token.

From my understanding, the endpoint that responds with the key is https://keycloak-server/auth/realms/my-realm/protocol/openid-connect/certs Doing a HttpGet on this endpoint, I get a response that looks like the following

{
    "keys": [{
            "kid": "7JUbcl_96GNk2zNh4MAORuEz3YBuprXilmTXjm0gmRE",
            "kty": "RSA",
            "alg": "RS256",
            "use": "sig",
            "n": "nE9gEtzZvV_XisnAY8Hung399hwBM_eykZ9J57euboEsKra8JvDmE6w7SSrk-aTVjdNpjdzOyrFd4V7tFqev1vVJu8MJGIyQlbPv07MTsgYE5EPM4DxdQ7H6_f3vQjq0hznkFvC-hyCqUhxPTXM5NgvH86OekL2C170xnd50RLWw8FbrprP2oRjgBnXMAif1Dd8kwbKKgf5m3Ou0yTVGfsCRG1_LSj6gIEFglxNHvGz0RejoQql0rGMxcW3MzCvc-inF3FCafQTrG5eWHqp5xXEeMHz0JosQ7BcT8MVp9lHT_utiazhQ1uKZEb4uoYOyy6mDDkx-wExpZkOx76bk_Yu-N25ljY18hNllnV_8gVMkX46_vcc-eN3DRZGNJ-Asd_sZrjbXbAvBbKwVxZeOTaXiUdvl8O0G5xX2xPnS_WA_1U4b_V1t28WtnX4bqGlOejW2kkjLvNrpfQ5fnvLjkl9I2B16Mbh9nS0LJD0RR-AkBsv3rKEnMyEkW9UsfgYKLFKuH32x_CXi9uyvNDas_q8WS3QvYwAGEMRO_4uICDAqupCVb1Jcs9dvd1w-tUfj5MQOXB-srnQYf5DbFENTNM1PK390dIjdLJh4k2efCJ21I1kYw2Qr9lHI4X2peTinViaoOykykJiol6LMujUcfqaZ1qPKDy_UnpAwGg9NyFU",
            "e": "AQAB"
        }
    ]
}

From my understanding, the field with key "n" is supposed to be an RSA256 key. Adding it to a RSAVerifier eventually gets an error of "Caused by: org.springframework.security.jwt.codec.InvalidBase64CharacterException: Bad Base64 input character decimal 95 in array position 2."

However, if I login to keycloak admin page and go into the realm settings-> keys and click the public key, a popup shows the public key minus the "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----" headers and footers. Hard coding this enables everything to work.

Is the key encoded? I've tried doing a Base64Utils.decodeFromUrlSafeString and a Base64Utils.decodeFromString. The first returning something smaller and doesn't lool like the key and the later creating an Illegal argument exception Illegal base64 character 5f.

Update: The n being returned is the modulous and e is the public exponent of the public key. But how does one get the actual key string?


Solution

  • The keys are also directly on https://keycloak-server/auth/realms/my-realm
    In a format directly exploitable with your code:

    {
        "realm": "my-realm",
        "public_key": "MIIBI...",
        "token-service": "https://keycloak-server/auth/realms/my-realm/protocol/openid-connect",
        "account-service": "https://keycloak-server/auth/realms/my-realm/account",
        "tokens-not-before": 0
    }