lib-lti1p3-core
lib-lti1p3-core copied to clipboard
"error":"invalid_jwt_token","error_description":"iat missing"
After a succed login and launch validation, when I want to getContextMembershipForPayload (Lti1p3Nrps), it fails by responding "iat missing". I tried using OAT\Library\Lti1p3Core\Service\Client\LtiServiceClient directly. Same happens.
Whole error:
Cannot get context membership for payload: Cannot get context membership for claim: Cannot get context membership: Cannot get access token: Client error: POST https://developer.anthology.com/api/v1/gateway/oauth2/jwttoken
resulted in a 400 Bad Request
response: {"error":"invalid_jwt_token","error_description":"iat missing"}
So it fails in getAccessToken from LtiServiceClient
The thing is that if I print the token claims... iat appears. So... very very strange.
Any ideas?
Thanks in advance
Same problem. I can see this is a Blackboard issue, isn't it? how did you solve it @alextoro85?
Hi @richard015ar,
If I'm not wrong... I think the issue here was Blackboard is not accepting microseconds.
So, you can overwrite /src/Security/Jwt/Builder/Builder.php and just after $now = Carbon::now();
add:
$now->setMicrosecond(0);
That did the trick, thank you @alextoro85! you saved me several hours debugging it. It's a little bit disappointing knowing that I'll have to fork or manually change it to make it work, only for Blackboard, tbh.
/I know @richard015ar, very disappointing, as a tip, if you are using composer you can do something like I did:
"autoload": {
"psr-4": {
"App\\": "src/"
},
"exclude-from-classmap": [
"vendor/oat-sa/lib-lti1p3-core/src/Security/Jwt/Builder/Builder.php"
],
"files": [
"app/override/lib-lti1p3-core/src/Security/Jwt/Builder/Builder.php"
]
}
Nice approach! I will definitely try it now!
Checking the Specification for JWT https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6.
[4.1.6](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6). "iat" (Issued At) Claim
The "iat" (issued at) claim identifies the time at which the JWT was
issued. This claim can be used to determine the age of the JWT. Its
value MUST be a number containing a NumericDate value. Use of this
claim is OPTIONAL.
According to JWT specification, IAT claim "MUST" be a NumericDate Value.
And NumericDate is defined in the document as follows,
NumericDate
A JSON numeric value representing the number of seconds from
1970-01-01T00:00:00Z UTC until the specified UTC date/time,
ignoring leap seconds. This is equivalent to the IEEE Std 1003.1,
2013 Edition [[POSIX.1](https://datatracker.ietf.org/doc/html/rfc7519#ref-POSIX.1)] definition "Seconds Since the Epoch", in
which each day is accounted for by exactly 86400 seconds, other
than that non-integer values can be represented. See [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339)
[[RFC3339](https://datatracker.ietf.org/doc/html/rfc3339)] for details regarding date/times in general and UTC in
particular.
Since time format for toDateTimeImmutable
is hardcoded in Carbon
to 'Y-m-d H:i:s.u'
, we get a non integer value for IAT.
/**
* Return native toDateTimeImmutable PHP object matching the current instance.
*
* @example
* ```
* var_dump(Carbon::now()->toDateTimeImmutable());
* ```
*
* @return DateTimeImmutable
*/
public function toDateTimeImmutable()
{
return new DateTimeImmutable($this->rawFormat('Y-m-d H:i:s.u'), $this->getTimezone());
}
MR in #189 does resolve the problem due to a side effect that format format method seems to ignore the .u
part when microseconds is set to 0.