Callable for customizing JWT payload#804
Conversation
| $func = $this->config['jwt_extra_payload']; | ||
| $extra = $func($client_id, $user_id, $scope); | ||
| if (is_array($extra)) { | ||
| $payload = array_merge($extra, $payload); |
There was a problem hiding this comment.
I would add $payload to the callable arguments instead of this array_merge
There was a problem hiding this comment.
Do you mean that callable must be defined like this? (pay attention that $payload passed by reference)
function(&$payload, $client_id, $user_id, $scope) {}
I think that standard JWT claims should be protected from external changes. That's why I put $payload last in array_merge()
There was a problem hiding this comment.
no, I man instead of:
$extra = call_user_func($this->config['jwt_extra_payload'], $client_id, $user_id, $scope);
if (is_array($extra)) {
$payload = array_merge($extra, $payload);
}do this:
$payload = call_user_func($this->config['jwt_extra_payload'], $payload);There was a problem hiding this comment.
I don't see why can't change those if we need. specification does not say they are required and even if this lib does require some when we override them here it is most likely we will handle this change in other places as well.
@bshaffer what do you think?
There was a problem hiding this comment.
Doing so callable may break JWT. Standard JWT claims should be protected from external changes.
There was a problem hiding this comment.
this feature is to generate those claims for example if you would want increase jwt token expire time for some user you could not. But if you only want to add new parameters then yes its ok
There was a problem hiding this comment.
I don't like any of this. It violates the paradigms the library was built on. I love doing callbacks like this, but it ought to be consistent. If it's coming down to just an array merge, I think #795 is the place to do this.
| 'scope' => $scope | ||
| ); | ||
|
|
||
| if (isset($this->config['jwt_extra_payload']) && is_callable($this->config['jwt_extra_payload'])) { |
There was a problem hiding this comment.
if it is not empty and not callable maybe better throw exception because it is most likely something wrong with implementation and should be fixed instead of silently ignore this.
|
|
||
| if (isset($this->config['jwt_extra_payload']) && is_callable($this->config['jwt_extra_payload'])) { | ||
| $func = $this->config['jwt_extra_payload']; | ||
| $extra = $func($client_id, $user_id, $scope); |
There was a problem hiding this comment.
maybe better use call_user_func() instead of variable?
There was a problem hiding this comment.
Yes! My mistake.
| $payload = array_merge($extra, $payload); | ||
| } | ||
| } else { | ||
| throw new \InvalidArgumentException("config['jwt_extra_payload'] is not callable"); |
There was a problem hiding this comment.
because of if (isset($this->config['jwt_extra_payload'])) will throw exception on empty values like null, '', 0 or false
|
I think this is new feature and requires tests. |
| if (isset($this->config['jwt_extra_payload'])) { | ||
| if (is_callable($this->config['jwt_extra_payload'])) { | ||
| $extra = call_user_func($this->config['jwt_extra_payload'], $client_id, $user_id, $scope); | ||
| if (is_array($extra)) { |
There was a problem hiding this comment.
I don't think this is required
There was a problem hiding this comment.
Yes it is, otherwise the array_merge below will throw an error.
There was a problem hiding this comment.
@bshaffer this is about array_merge error vs custom error? result will be the same :D but maybe yes more clear error message is better
| ); | ||
|
|
||
| if (isset($this->config['jwt_extra_payload'])) { | ||
| if (is_callable($this->config['jwt_extra_payload'])) { |
There was a problem hiding this comment.
I would prefer these exceptions be handled like this:
if (!is_callable($this->config['jwt_extra_payload']))) {
throw new \InvalidArgumentException("config['jwt_extra_payload'] is not callable");
}
$extra = call_user_func($this->config['jwt_extra_payload'], $client_id, $user_id, $scope);
if (!is_array($extra)) {
throw new \InvalidArgumentException("config['jwt_extra_payload'] callable must return array");
}
$payload = array_merge($extra, $payload);There was a problem hiding this comment.
@bshaffer I still don't like the idea that it is impossible to change values in $payload.
| @@ -129,16 +129,17 @@ protected function createPayload($client_id, $user_id, $scope = null) | |||
| ); | |||
|
|
|||
| if (isset($this->config['jwt_extra_payload'])) { | |||
There was a problem hiding this comment.
since I dont like nesting I would change this to
if (!isset($this->config['jwt_extra_payload'])) {
return $payload;
}
//...|
Let's vote:
OR
|
|
This is looking great. We need to add the parameter here also! |
|
How about to change parameter name to |
|
@afilippov1985 yes, I think |
bshaffer
left a comment
There was a problem hiding this comment.
Everything looks great, two minor suggestions. Sorry this has taken so long... let's get this baby merged!!
|
|
||
| if (isset($this->config['jwt_extra_payload_callable'])) { | ||
| if (!is_callable($this->config['jwt_extra_payload_callable'])) { | ||
| throw new \InvalidArgumentException("config['jwt_extra_payload_callable'] is not callable"); |
There was a problem hiding this comment.
nit, but I'd rather this just be "jwt_extra_payload_callable is not callable"
| throw new \InvalidArgumentException("config['jwt_extra_payload_callable'] is not callable"); | ||
| } | ||
|
|
||
| $extra = call_user_func($this->config['jwt_extra_payload_callable'], $client_id, $user_id, $scope); |
There was a problem hiding this comment.
Why don't we just pass this function $payload and expect the returned array to be the new payload, e.g.:
$payload = call_user_func($this->config['jwt_extra_payload_callable'], $payload);There was a problem hiding this comment.
This may break proper work of JWT
See our conversation with @svycka - https://github.com/bshaffer/oauth2-server-php/pull/804/files/86bd64e745ee34fa03bfb3456e5d2a2ab0a1c07e#r98169436
I agree to replace this
$payload = array_merge($extra, $payload);
to this
$payload = array_merge($payload, $extra);
There was a problem hiding this comment.
then, we should also rename the parameter to jwt_override_payload_callable
There was a problem hiding this comment.
I'm convinced. Ty for the explanation.
Even easier way for customizing JWT payload
Issue #750
Issue #793
PR #795
Usage:
one more example: