lepture / authlib

The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS,JWE,JWK,JWA,JWT included.
https://authlib.org/
BSD 3-Clause "New" or "Revised" License
4.52k stars 452 forks source link

Quoting (URL-encoding) Base authentication username / password is incorrect #629

Closed igielski closed 1 month ago

igielski commented 7 months ago

Describe the bug

Version 1.3.0 introduces a change in the encoding of the Basic Authentication header (commit d2d1f494e625b7ee9c64f70165bd6d5faf28fe21). In the comment to the commit you're mentioning this RFC section: https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1, but I think that rather this one is applicable: https://datatracker.ietf.org/doc/html/rfc2617#section-2

I've never seen basic auth username and password being url encoded before. The servers (e.g. cloud foundry UAA) seem to reject such requests. It also doesn't make sense to url-encode it if it's then base64-encoded

Error Stacks

--

To Reproduce

A minimal example to reproduce the behavior: happens always in version 1.3.0 if basic authentication is used to get a token.

Expected behavior

Basic authentication username and password shouldn't be URL encoded before being base64 encoded.

Environment:

Additional context

--

jbarbadillo commented 1 month ago

I have found the same buggy behavior after updating authlib from 1.2.1 to 1.3.1. A customer that was using a secret with the following chars at the end '==' is now receiving a badly converted base64 string.

That was clearly caused by using quote() before conversion to base64. This example shows how to reproduce this:

version 1.2.1 correct conversion

text = "fakeid:fakesecret=="
to_native(base64.b64encode(to_bytes(text, 'latin1')))
# retrieves 'ZmFrZWlkOmZha2VzZWNyZXQ9PQ=='

version 1.3.1 wrong conversion

text = f"{quote('fakeid')}:{quote('fakesecret==')}"     # introduces extra characters 'fakeid:fakesecret%3D%3D'
to_native(base64.b64encode(to_bytes(text, 'latin1')))
# retrieves 'ZmFrZWlkOmZha2VzZWNyZXQlM0QlM0Q='

Result

The OIDC server decoding this secret with version 1.3.1 will obtain a wrong secret with extra chars at the end: fakesecret%3D%3D

lepture commented 1 month ago

According to the RFC:

The client identifier is encoded using the "application/x-www-form-urlencoded" encoding algorithm per Appendix B, and the encoded value is used as the username; > the client password is encoded using the same algorithm and used as the password.

lepture commented 1 month ago

The reason why it needs to be urlencoded:

client_id = 'demo:foo'
client_secret = 'secret:bar=='

Without urlencode, the basic auth will be:

base64('demo:foo:secret:bar==')

With urlencode, it will be:

base64('demo%3Afoo:secret%3Abar%3D%3D')
lepture commented 1 month ago

Added unquote for the server: https://github.com/lepture/authlib/commit/63c9fb698912dd7c87eaaa7979640fead1cb3694

lepture commented 1 month ago

Reverted https://github.com/lepture/authlib/commit/d2d1f494e625b7ee9c64f70165bd6d5faf28fe21

He can quote the client id and secret at first with his own code.

lepture commented 1 month ago

1.3.2 should work.

jbarbadillo commented 1 month ago

1.3.2 should work.

Thanks! I will let you know if anything else found.