Client Credentials (not) using URL-Encoding for OAuth2

The occasion

Spring Security just made an interesting change to their OAuth2 Client.
https://github.com/spring-projects/spring-security/issues/9610

For years they have used regular old Basic Authentication for confidential Token Requests, instead of the pre-URL-encoded variation the OAuth2-Spec describes.
https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1
I personally wasn’t even aware that OAuth2 uses a modified Basic Auth variant.

So, I thought I’ll have a look what Keycloak does and did a quick check with Postman.

The setup

Create a confidential client with.

  • client_id: local+test
  • client_secret: 9b51491b-b4be-4272-b72a-3a76805d5154

Manually do Authorization Code Flow.

The result

  1. Token request with test+local:9b51491b-b4be-4272-b72a-3a76805d5154 succeeds
  2. Token request with test%2Blocal:9b51491b-b4be-4272-b72a-3a76805d5154 fails (invalid client credentials)

The interpretation

So naturally one would come to the conclusion that Keycloak uses regular old Basic Auth, instead of the in the OAuth Spec described variation.
Now this will in most cases not be relevant, as UUIDs aren’t subject to any changes from URL encoding & people will in most cases not choose clientIDs with special characters in them.

The question

  1. Is my conclusion on the Basic Auth Protocol valid?
  2. Does the Keycloak Team intend to address the Basic Auth Protocol for Client Authentication at some point, or is your stand: Don’t use special characters?

How did you perform quick check with Postman? Did postman add also header Content-Type: application/x-www-form-urlencoded? Maybe postman did own url encoding, so value is double url encoded. You should to debug request first to see if you are posting correct header/single url encoded values.

I would say that Keycloak is not doing proper url decoding - it is based on my old experience. But that may be fixed, so you need to test it properly first.

I did decode the Authorization Headers from the Request Log as control.
I’m fairly certain there aren’t any hidden shenanigans going on.