-
Bug
-
Resolution: Fixed
-
Normal
-
None
-
None
Whilst testing OAuth authentication with MB in a Rails app I encountered an issue with PKCE when the verification method is set to "S256". I believe this is due to an implementation detail in the MusicBrainz server which means it is not compliant with the RFC.
The RFC states the the client should derive a code challenge from the code verifier as follows:
code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
Later on in the process the server should verify the code_verifier using the following logic:
BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) == code_challenge
However the MB server code performs the verification as follows (operands reordered for clarity):
encode_base64url(sha256(decode_base64url($code_verifier)))) eq $code_challenge
Note the call to decode_base64. I believe this may have been added due to a misunderstanding of the following recommendation from the RFC:
The client SHOULD create a "code_verifier" with a minimum of 256 bits of entropy. This can be done by having a suitable random number generator create a 32-octet sequence. The octet sequence can then be base64url-encoded to produce a 43-octet URL safe string to use as a "code_challenge" that has the required entropy.
The base64 encoding is recommended here purely as a means of generating a 43 octet URL safe string with sufficient entropy, not so that the underlying value can be subsequently decoded during the PKCE verification.
The following is example of S256 PKCE verification code from another OAuth implementation that I believe is RFC compliant:
grant.code_challenge == generate_code_challenge(code_verifier)
def generate_code_challenge(code_verifier) Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier), padding: false) end
I'd be happy to submit a simple PR to fix this if confirmed.