verify method
Verify a signed JWT.
It is highly recommended to provide the issuer
param, which
prevents this method from fetching openid-configuration from unknown /
malicious sources.
All of the following conditions must be true or else this method will throw:
- iat (issued at) must be before now
- exp (expiration) must be after now
- kid (key id) must be set or
publicKey
must be non-null - iss (issuer) must be set
issuer
must be null or equal to issaudience
must be null or equal to aud- signature must be valid
The key signature is checked either against the given publicKey
, or
the key that is provided by the issuers JWKS.
JWKS keys are usually cached by KeyService.
Implementation
Future<void> verify({
String? issuer,
String? audience,
RSAPublicKey? publicKey,
}) async {
if (alg != 'RS256') {
throw ApiRequestException.unauthorized(
'Unsupported signing algorithm "$alg".');
}
if (iat?.isAfter(DateTime.now()) == true) {
throw ApiRequestException.unauthorized('Invalid issue timestamp.');
}
if (exp?.isBefore(DateTime.now()) == true) {
throw ApiRequestException.unauthorized('Token expired.');
}
if (kid == null && publicKey == null) {
throw ApiRequestException.unauthorized('Missing key id in token header.');
}
if (iss == null) {
throw ApiRequestException.unauthorized('Missing issuer in token.');
}
if (issuer != null && iss != issuer) {
throw ApiRequestException.unauthorized('Issuer mismatch.');
}
if (audience != null && aud != audience) {
throw ApiRequestException.unauthorized('Audience mismatch.');
}
final key = publicKey ??
await resolve<KeyService>().getKey(Uri.parse(iss!), alg!, kid!);
final body = utf8.encode(token.split('.').take(2).join('.'));
final signer = Signer('SHA-256/RSA');
signer.init(false, PublicKeyParameter<RSAPublicKey>(key));
if (signer.verifySignature(
Uint8List.fromList(body), RSASignature(signature))) {
return;
}
throw ApiRequestException.unauthorized('Invalid signature.');
}