TykTechnologies / tyk

Tyk Open Source API Gateway written in Go, supporting REST, GraphQL, TCP and gRPC protocols
Other
9.69k stars 1.09k forks source link

[TT-13401] OAuth2 client_credentials authentication does not seem to be RFC6749 compliant #5909

Open lolleko opened 10 months ago

lolleko commented 10 months ago

Branch/Environment/Version

Describe the bug

Failing to authenticate via client_credentials Because client_id & client_secret do not seem to be urlendecoded after base64 decoding.

Reproduction steps

  1. We will use the following client credentials in the example:
client_id: $s6BhdRkqt3@
client_secret: $7Fjfp0ZBr1KtDRbnfVdmIw@
  1. Urlencode the 2 as sepcified by RFC6749
client_id(urlencoded): %24s6BhdRkqt3%40
client_secret(urlencoded): %247Fjfp0ZBr1KtDRbnfVdmIw%40
  1. Encoding the urlencoded variants to baset64 separated by a colon will lead to the following header:
Authorization: Basic JTI0czZCaGRSa3F0MyU0MDolMjQ3RmpmcDBaQnIxS3REUmJuZlZkbUl3JTQw
  1. Providing this header to the oauth/token endpoint via curl:
curl --location 'abc.com/oauth/token' --header 'Content-Type: application/x-www-form-urlencoded' --header 'Authorization: Basic JTI0czZCaGRSa3F0MyU0MDolMjQ3RmpmcDBaQnIxS3REUmJuZlZkbUl3JTQw'  --data-urlencode 'grant_type=client_credentials' 

Actual behavior

No token is returned :(

{"error":"invalid_request","error_description":"The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed."}

Expected behavior

A token should be returned.

Additional context

In fact, a token is returned if we omit step 2 from the reproduction steps.

client_id: $s6BhdRkqt3@
client_secret: $7Fjfp0ZBr1KtDRbnfVdmIw@

Header encoded directly in base64 (skipping urlencode)

Authorization: Basic JHM2QmhkUmtxdDNAOiQ3RmpmcDBaQnIxS3REUmJuZlZkbUl3QA

Passing this token using the curl command from step 5 will return a token.

If I understand RFC6749 correctly urlencoding id and secret is required when using the authorization header. This is also how it is implemented in the x/oauth2 pkg: https://github.com/golang/oauth2/blob/master/internal/token.go#L199 In fact, if I remove the url.QueryEscape from that file, I am also able to authenticate with tyk using x/oauth2

So I think tyk or whatever pkg you are using for oauth2 (osin?) should also follow this behaviour to be RFC6749 compliant. Therefore, first decode the base64 header, second split at the colon, third urlendecode.

mhuaco commented 8 months ago

@lolleko Thank you for bringing this to our attention. How are you generating the client_id and secret. Could you please share the doc you're referencing? I ask because when I create an OAuth client via our Tyk dashboard, I'm not seeing the special character '$@' included in the client ID and secret.

Regards Marvin

lolleko commented 7 months ago

Hey Marvin,

Thanks for getting back to me. We are generating our ID and secret ourselves, we are not using the dashboard. I manually created ID and secret and included the special characters '$@' to showcase this issue. Like I said, tyk OAuth works as expected as long as we do not include these special characters in our generated IDs/Secrets.

This issue occurs not only for '$@', but for all characters that need to be urlenencoded (https://docs.microfocus.com/OMi/10.62/Content/OMi/ExtGuide/ExtApps/URL_encoding.htm) Also, it doesn't matter where you put them (I just put them in the beginning and end as a simple example)

So something like s6#Bhd?Rkqt3 or sdaskdop@mlkj$li will also cause issues.

lolleko commented 7 months ago

Ahhh and regarding the referenced docs, I think I put all the relevant references in the Issue description, which one are you missing?