# Use different signing key and certificate pairs per configured client or IDP

**URL:** <https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939>\
**Category:** Getting advice\
**Tags:** identity-brokering, oidc, saml\
**Created:** [May 9, 2024, 12:05pm UTC](https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939 "2024-05-09T12:05:31Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![bluefloyd](https://yyz2.discourse-cdn.com/free1/user_avatar/forum.keycloak.org/bluefloyd/32/4989_2.png) [@bluefloyd](https://forum.keycloak.org/u/bluefloyd)\
**Post date:** [May 9, 2024, 12:05pm UTC](https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939/1 "2024-05-09T12:05:31Z")

</div>

From the official documentation and experimenting (with the Keycloak Admin Console, import/export and Terraform provider) I understand that the highest prio RSA key is used for the following:

- OAuth/OIDC clients: Keycloak signs the issued JWTs with it.
- SAML IDP connection (“SAML clients”): Keycloak signs the generated SAML Responses with it.
- SAML SP connections (“Identity Providers”). Keycloak signs the generated SAML AuthnRequests with it.

Is it possible to decouple these?

The problem I am trying to solve is the following:

- Keycloak is used in PROD with the initial (self-generated, environment specific) realm RSA key+certificate, which has a validity of 10 years
- now we are about to connect the first SAML IDP (“Identity Provider” in terms of Keycloak, so Keycloak acting as SAML SP)
- the owner of the remote IDP has strict expectations about the certificate to be used for signing and verifying the signature of the SAML AuthnRequests: a CA signed certificate must be used
- in case we change the Keycloak operational realm RSA key+certificate (or simply add a new with a higher priority), some of the connected OAuth clients will need to be forced to use the new certificate (unless they are able to get it from the JWK’s URI). Some apps might need a config change (or a restart). SPA apps might need a browser refresh to get the latest well-known-config (+ JWK URI info). Some of these apps are not in our sphere of influence so restarting or changing a config would lead to service disruption. In case of SPAs we are not able to force all users to make a refresh, so weird things could happen (authorization issues maybe redirect loops) until the latest JWK data is loaded.

Certificate and key management is complex and I see the advantages of DRY-ing out the number of keys+certs used, but it would be great to be able to specify (or just override) the key+cert per configured client (SAML/OIDC/OAuth) and/or IDP broker (SAML/OIDC/OAuth) connection. Then each certificate could have their own lifecycle (like the SIG and ENC realm key+cert pairs already do!).

I am aware that Keycloak gracefully accepts (validates) JWTs signed with a lower priority key+cert (e.g. when calling the REST admin API or userinfo), but it issues new JWTs (and also SAML messages) with the new realm RSA key+cert. This is handy, but solves a different problem.

Another likely scenario would be the use-case of multiple remote IDPs connected to the same Keycloak broker (acting as SAML SP towards multiple remote IDPs): imagine having tens of IDPs connected.  
How should the realm certificate be rotated so that we avoid service disruptions? It’s kind of impossible to rotate the certificate trust in each remote IDP at the same time when those are owned/managed by different users from different timezones. Ideally we would like to be able to rotate one certificate at a time.

What would be the best practice to handle this kind of situations?  
A possible workaround for the second use case I mentioned would be to add an extra realm for each connected IDP (with SSO from these IDP-SSO realms to the main operational realm). I am looking for something simpler if possible. Any ideas/hints would be appreciated 🙂 Thanks

---

<div class="post-metadata">

**Author:** ![Ketec](https://yyz2.discourse-cdn.com/free1/user_avatar/forum.keycloak.org/ketec/32/10955_2.png) [@Ketec](https://forum.keycloak.org/u/Ketec)\
**Post date:** [July 25, 2024, 7:35am UTC](https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939/2 "2024-07-25T07:35:32Z")

</div>

Bumping this up.  
Same issue. I need different signing keys for SAML requests (gov sso-s are strict).

Multiple realms is not an option - the token introspect, kc api interactions etc are in one realm. Login page is also realm specific. One product cannot reliably function in multiple realms.  
Managing a growing number of realms would also be a nightmare.

And some clients use multiple different SSO that may require different signing key.

I tried custom SPI - but their admin extensions are near impossible to write with the react based theme. Extending SAML idp does not include any fields (looks like hard coded by providerid in react).

---

<div class="post-metadata">

**Author:** ![dasniko](https://yyz2.discourse-cdn.com/free1/user_avatar/forum.keycloak.org/dasniko/32/2969_2.png) [@dasniko](https://forum.keycloak.org/u/dasniko)\
**Post date:** [July 25, 2024, 8:11am UTC](https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939/3 "2024-07-25T08:11:18Z")

</div>

I’m currently experimenting with client-specific signing certificates, not related to external IdPs, only client \<\> KC interaction…

My current approach is to store key & cert in client attributes. Unfortunately this can’t be done through the admin UI, but only through admin API. But at least it’s possible in some way…

Then, I have currently overwritten the `DefaultKeyManager` class, especially the `getActivekey(realm, use, algorithm)` method, to look into the client if there are client signing key attributes to use. If yes, they will be used, if not, the default realm keys will be used.

Unfortunately, the `DefaultKeyManager` is not SPI base, so that one can easily overwrite/extend/replace it. Additionally, it gets hard created through the `new` operator in the `KeyclaokSession`.  
Luckily, Keycloak uses just the classpath, not the module-system. So, it’s possible to overwrite the whole class `org.keycloak.keys.DefaultKeyManager` in a custom JAR, which is loaded later than the default Keycloak JAR with the original class. This way, I can use my implementation.  
Downside: lot of copied code which has to be checked/verified/maintained for each new Keyclaok version.

---

<div class="post-metadata">

**Author:** ![Ketec](https://yyz2.discourse-cdn.com/free1/user_avatar/forum.keycloak.org/ketec/32/10955_2.png) [@Ketec](https://forum.keycloak.org/u/Ketec)\
**Post date:** [July 25, 2024, 9:09am UTC](https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939/4 "2024-07-25T09:09:42Z")

</div>

The weird thing is, that reading through the code, it almost has support for signing keys per IDP.

```auto

            if (getConfig().isWantAuthnRequestsSigned()) {
                KeyManager.ActiveRsaKey keys = session.keys().getActiveRsaKey(realm);

                String keyName = getConfig().getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
                binding.signWith(keyName, keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate())
                        .signatureAlgorithm(getSignatureAlgorithm())
                        .signDocument();
                if (! postBinding && getConfig().isAddExtensionsElementWithKeyInfo()) { // Only include extension if REDIRECT binding and signing whole SAML protocol message
                    authnRequestBuilder.addExtension(new KeycloakKeySamlExtensionGenerator(keyName));
                }
            }

```

But it only has key name option for UI, i might be looking at the wrong signature, but i’m 99% sure this is the one used to sign outgoing requests.  
All it would really need is to provide actual field, not search by key name.

But it’s also in the middle of a large function in SAMLIdentityProvider, not the nicest thing to override, and cant extend as a alternative saml provider (since they hardcoded providerid in react templates). And many dependencies all over the code.

---

<div class="post-metadata">

**Author:** ![dasniko](https://yyz2.discourse-cdn.com/free1/user_avatar/forum.keycloak.org/dasniko/32/2969_2.png) [@dasniko](https://forum.keycloak.org/u/dasniko)\
**Post date:** [July 25, 2024, 10:12am UTC](https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939/5 "2024-07-25T10:12:04Z")

</div>

> [@Ketec](#):
>
> and cant extend as a alternative saml provider

You can overwrite the default saml provider in a way like this. Important is to use the same providerId (when extending like in the following example, this is done automatically) and using a higher `order` than the default one (perhaps you’ll also have to provide a custom config class):

```java
public class CustomIdentityProviderFactory extends SAMLIdentityProviderFactory {

	private DestinationValidator destinationValidator;
	
	@Override
	public SAMLIdentityProvider create(KeycloakSession session, IdentityProviderModel model) {
		return new CustomSAMLIdentityProvider(session, new SAMLIdentityProviderConfig(model), this.destinationValidator);
	}

	@Override
	public void init(Config.Scope config) {
		super.init(config);
		this.destinationValidator = DestinationValidator.forProtocolMap(config.getArray("knownProtocols"));
	}

	@Override
	public int order() {
		return 10;
	}
}

```

---

<div class="post-metadata">

**Author:** ![Ketec](https://yyz2.discourse-cdn.com/free1/user_avatar/forum.keycloak.org/ketec/32/10955_2.png) [@Ketec](https://forum.keycloak.org/u/Ketec)\
**Post date:** [July 25, 2024, 1:02pm UTC](https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939/6 "2024-07-25T13:02:41Z")

</div>

With the same provider id, yes. It’s just much riskier since it now affects also all the existing integrations.

Used [SAML IDP with custom certificate · GitHub](https://gist.github.com/Szer/fda52c4afaaca9c3a4aee35b7870d2ed) as an inspiration for ideas what to do. But that was written in kotlin for some reason (likely some different build or something).

I wrote a SAML factory SPI, overrides with java Proxy.  
I can test hardcoded version and it looks functional.

The UI and config is an issue.  
I know they introduced the Page/Tab extension SPI, but in 24 it lacks any and all context and everything is saved globally.  
So actual config side still needs some solution.

---

<div class="post-metadata">

**Author:** ![ravthiru](https://yyz2.discourse-cdn.com/free1/user_avatar/forum.keycloak.org/ravthiru/32/9634_2.png) [@ravthiru](https://forum.keycloak.org/u/ravthiru)\
**Post date:** [July 27, 2024, 11:41pm UTC](https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939/7 "2024-07-27T23:41:36Z")

</div>

Hi Dasniko,

Is your solution of replacing DefaultKeyManager works ? or did you find any other solutions to have per client keys?

---

<div class="post-metadata">

**Author:** ![dasniko](https://yyz2.discourse-cdn.com/free1/user_avatar/forum.keycloak.org/dasniko/32/2969_2.png) [@dasniko](https://forum.keycloak.org/u/dasniko)\
**Post date:** [August 1, 2024, 5:37am UTC](https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939/8 "2024-08-01T05:37:42Z")

</div>

ATM, this works for us. But I don‘t know yet, how reliable this will be over time. I‘m of good hope.

---

<div class="post-metadata">

**Author:** ![bedla](https://yyz2.discourse-cdn.com/free1/user_avatar/forum.keycloak.org/bedla/32/11017_2.png) [@bedla](https://forum.keycloak.org/u/bedla)\
**Post date:** [August 2, 2024, 11:37am UTC](https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939/9 "2024-08-02T11:37:46Z")

</div>

Is anybody aware of issue created to solve this topic? thank you

---

<div class="post-metadata">

**Author:** ![ravthiru](https://yyz2.discourse-cdn.com/free1/user_avatar/forum.keycloak.org/ravthiru/32/9634_2.png) [@ravthiru](https://forum.keycloak.org/u/ravthiru)\
**Post date:** [August 15, 2024, 5:54am UTC](https://forum.keycloak.org/t/use-different-signing-key-and-certificate-pairs-per-configured-client-or-idp/25939/10 "2024-08-15T05:54:19Z")

</div>

Thanks Dasniko, Is your code of overriding DefaultKeyManager avilable for everyone to see the implementation ? and why not create realm keys which are ‘disabled’ but ‘active’ and use them for overriding realm keys instead of storing keys as client attributes. How you are able to differentiate keys requested in DefaultKeyManager is for Client ↔ KC or KC ↔ extranal IDP
