-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Allow JWT::decode to accept an empty string as a valid kid #581
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Allow JWT::decode to accept an empty string as a valid kid #581
Conversation
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
a09f76f
to
993a11c
Compare
I've signed the CCA, is there anyone who has time to review this? |
@ryanneufeld thank you for your submission! I'll take a look. Do you know if the spec defines this as a valid use of |
It's not explicitly specified, except that it's a case-sensitive string: https://datatracker.ietf.org/doc/html/rfc7517#section-4.5 In the wild, I've observed JWK data with an extra key containing a kid of "" from Teleport, so it's definitely a Thing. |
As Doug mentioned. There are use-cases in the wild where this patch would enable support without special code to handle it at the implementation layer. |
@bshaffer Any updates on this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not clear to me this functionality is a valid use of the spec. For that reason I'm reticent to add it.
src/JWT.php
Outdated
if ($keyOrKeyArray instanceof CachedKeySet) { | ||
// Skip "isset" check, as this will automatically refresh if not set | ||
return $keyOrKeyArray[$kid]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you removing these lines?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new lines below cover this test as the CachedKeySet implements ArrayAccess
The resulting logic is the same
https://github.com/firebase/php-jwt/blob/main/src/CachedKeySet.php#L19C1-L19C42
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you read the comment of the removed line, you'll see that the isset
check triggers a refresh of the credentials, which we don't want to or need to do.
Can you point to the part of the RFC that forbids this? https://datatracker.ietf.org/doc/html/rfc7517#section-4.5
So an empty value is a case-sensitive string, though not an ideal one. |
@ryanneufeld are you being serious? |
I'm not sure how to respond to this question, you said you're not sure if it meets the spec. I'm not sure which spec you're referring to, so if you were to point me in the right direction I could address your concerns. So, yes, I am being serious, not combative. |
My concern is not that the spec forbids it, my concern is that this adds logic which is not defined by any spec. Supporting an empty string as a KID is one thing, but selecting a key by default when the KID is empty is another. |
@bshaffer I see your point. I suppose the idea here is that we need a way to pick a key. The idea here is that if there are two keys, and one has an empty KID, and no KID is passed in for selection, then allow the one with the empty key to match. The alternative involves parsing the JWT's multiple times in order to validate them. I welcome any suggestions/collaboration you have to offer for resolving this situation. |
3986874
to
cafe96d
Compare
@bshaffer After looking into more closely, I made a refactor that I think will satisfy your concerns, while maintaining the previous functionality. Additionally this will increase the code coverage with some more tests. |
afd0264
to
90b3aa3
Compare
There are instances when using CachedKeySet where a key is returned with an empty string as the kid. This is a valid use case and should be allowed. For example Teleport Proxy uses this pattern to allow for a default key. The getKey method can be simplified, as well as refactored to follow the same pattern as the CachedKeySet class which casts null kids to an empty string. This change also adds a test to ensure that an empty string kid is a valid kid.
90b3aa3
to
841dac7
Compare
See https://g.co/gemini/share/76e85b5fc2d8. The two main concerns which I also share are
I think it'd be a better approach for Teleport to start producing standard JWKs rather than have this library support non-standard functionality. |
There are instances when using CachedKeySet where a key is returned with an empty string as the kid. This is a valid use case and should be allowed.
For example Teleport Proxy uses this pattern to allow for a default key.
Newer versions of teleport also return:
The getKey method can be simplified, as well as refactored to follow the same pattern as the CachedKeySet class which casts null kids to an empty string.
This change also adds a test to ensure that an empty string kid is a valid kid.