Not Acceptable (406) returned by Keycloak for certs URI

Hi :

I have a third party vendor web application (Angular based served by IIS) which I previously integrated with our Keycloak 11 instance (Implicit flow). It has been working fine. The vendor has released a new version which I am testing, but the integration to Keycloak no longer works.

Getting specifics from the vendor has been challenging, but it seems they have updated some third party library which appears to have changed its default behaviour. Doing a little tracing and I see that the application server queries Keycloak on /auth/realms/{my_realm}/protocol/openid-connect/certs with an Accept header of application/jwk-set+json. Keycloak is replying with a 406 (not acceptable).

Is this an Access Type issue? It was previously Public so is the behaviour now consistent with Confidential and if so which Client Authenticator applies?

Pab

At least from another major OIDC provider (CA Identity Manager), I get a 406 too.

curl -IH "Accept: jwk-set+json" https://sso.acesso.gov.br/jwk
HTTP/2 406 
…

OIDCdiscovery for that domain is at https://sso.acesso.gov.br/.well-known/openid-configuration

Hope this helps.

Thanks for the reply, but I’m not sure it does. I am in no way a OIDC expert, but I was working under the assumption that a configuration change of Keycloak would result in it expecting and accepting the application/jwk-set+json header I mentioned. Is the header not meant as a parameter to the receiving OIDC server to alter its behaviour per the protocol?

The provider you tested against may simply not have the functionality enabled either.

Check OIDC standard/RFC if they require support for that header.

I did further research and I believe this is a bug (at least a feature request), per the spec for JSON Web Key.

Could you provide exact specification from RFC, where is specified that server must accept that request header, pls?

Thanks you both for the continued interest.

I think I’m starting to understand. He may be referring to Section 7 of RFC 7517. The new version of the OIDC client library my vendor is using must have simply started being explicit by specifying the MIME type in the Accept header. Given that the server’s response is in this format it seems reasonable to expect the server to recognize the MIME type in the Accept header.

Given that Keycloak responds to this URI appropriately when the application/jwk-set+json MIME type is not specified, am I correct in thinking that Wildfly/Undertow is responding with the 406 before even passing it to Keycloak? If so, how can I add the new MIME type to the list of accepted values to get around this temporarily?

I don’t believe that this RFC is saying what MUST be accepted by the server in the Accept header. It defines only what MUST be returned in the cty (Content Type header - request headers != response headers).

See google example:


# curl -v -H "Accept: jwk-set+json" https://www.googleapis.com/oauth2/v3/certs
...
> GET /oauth2/v3/certs HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.googleapis.com
> Accept: jwk-set+json
>
< HTTP/1.1 200 OK
< Date: Thu, 02 Dec 2021 08:40:56 GMT
< Expires: Thu, 02 Dec 2021 14:14:17 GMT
< Content-Type: application/json; charset=UTF-8
...
<
{
  "keys": [
...

Requested Accept: jwk-set+json, but application/json returned (that’s correct, it doesn’t contain private key, so it doesn’t need to be jwk-set+json type).

I would say it will be nice to have if server accepts anything in the accept header, which is not default Keycloak behaviour in this case, but I don’t believe it is some RFC violation.

For me it looks like your vendor is very strict. Probably it has tested lib with IDP, which has different (opinionated) implementation and they are expecting that all other IDPs will have the same behaviour.

Interesting discussion. I think you’re correct. The spec is only specific about the response, not the request. I had a look at section 14 of the HTTP spec regarding the Accept header which states : If an Accept header field is present, and if the server cannot send a response which is acceptable according to the combined Accept field value, then the server SHOULD send a 406 (not acceptable) response.

Technically, Google is compliant, but only because the weaker “SHOULD” (and not “MUST”) is stated in the spec. Google is simply ignoring the Accept header. This is arguably incorrect behaviour, but technically correct.

Practically, I think it would be appropriate for the IDP to allow the client to specify “application/jwk-set+json” in the request Accept header if it is expected in the response. This is the format Keycloak is responding in is it not?

Theoretical aside, I still need a way to get around this in the short term. I’ve set an Undertow expression-filter in standalone.xml with expression=“set(attribute=’%{i,Accept}’,value=’*/*’)” and this does the trick, but am I opening myself to other potential problems? I’d feel a little better if I could “tighten” this up a bit.

Pab

Yes, it is SHOULD for HTTP 1.1. And it is MUST for older HTTP 1.0 (but Google doesn’t implement it correctly for 10).

Anyway, it isn’t a bug. It is a nice to have feature (because many JWK endpoint implementations have less strict implementation - source: Accept application/jwk-set+json as content type. [SDK-2131] · Issue #77 · auth0/jwks-rsa-java · GitHub).

I would use workaround: drop Accept header for JWK endpoint URLS on the reverse proxy level.
Solution: ask your third party vendor web application to fix it. They shouldn’t rely on this behaviour, when RFC doesn’t specify it strictly as MUST.

1 Like