verify static method
Verify a token.
key
must be
- SecretKey with HMAC algorithm
- RSAPublicKey with RSA algorithm
- ECPublicKey with ECDSA algorithm
- EdDSAPublicKey with EdDSA algorithm
issueAt
allows to verify that the token wasn't issued too long ago. The
value is a timestamp (number of seconds since epoch) that is compared to
the value of the 'iat' claim. Verification fails if the 'iat' claim is
before issueAt
.
Implementation
static JWT verify(
String token,
JWTKey key, {
bool checkHeaderType = true,
bool checkExpiresIn = true,
bool checkNotBefore = true,
Duration? issueAt,
Audience? audience,
String? subject,
String? issuer,
String? jwtId,
}) {
try {
final parts = token.split('.');
final header = jsonBase64.decode(base64Padded(parts[0]));
if (header == null || header is! Map<String, dynamic>) {
throw JWTInvalidException('invalid header');
}
if (checkHeaderType && header['typ'] != 'JWT') {
throw JWTInvalidException('not a jwt');
}
final algorithm = JWTAlgorithm.fromName(header['alg']);
final body = utf8.encode(parts[0] + '.' + parts[1]);
final signature = base64Url.decode(base64Padded(parts[2]));
if (!algorithm.verify(key, Uint8List.fromList(body), signature)) {
throw JWTInvalidException('invalid signature');
}
dynamic payload;
try {
payload = jsonBase64.decode(base64Padded(parts[1]));
} catch (ex) {
payload = utf8.decode(base64.decode(base64Padded(parts[1])));
}
if (payload is Map) {
// exp
if (checkExpiresIn && payload.containsKey('exp')) {
final exp = DateTime.fromMillisecondsSinceEpoch(
(payload['exp'] * 1000).toInt(),
);
if (exp.isBefore(clock.now())) {
throw JWTExpiredException();
}
}
// nbf
if (checkNotBefore && payload.containsKey('nbf')) {
final nbf = DateTime.fromMillisecondsSinceEpoch(
(payload['nbf'] * 1000).toInt(),
);
if (nbf.isAfter(clock.now())) {
throw JWTNotActiveException();
}
}
// iat
if (issueAt != null) {
if (!payload.containsKey('iat')) {
throw JWTInvalidException('invalid issue at');
}
final iat = DateTime.fromMillisecondsSinceEpoch(
(payload['iat'] * 1000).toInt(),
);
final issueAtTime =
DateTime.fromMillisecondsSinceEpoch(issueAt.inMilliseconds);
// Verify that the token isn't expired
if (iat.isBefore(issueAtTime)) {
throw JWTInvalidException('expired issue at');
}
}
// aud
if (audience != null) {
if (payload.containsKey('aud')) {
if (payload['aud'] is String && payload['aud'] != audience.first) {
throw JWTInvalidException('invalid audience');
} else if (payload['aud'] is List &&
!ListEquality().equals(payload['aud'], audience)) {
throw JWTInvalidException('invalid audience');
}
} else {
throw JWTInvalidException('invalid audience');
}
}
// sub
if (subject != null) {
if (!payload.containsKey('sub') || payload['sub'] != subject) {
throw JWTInvalidException('invalid subject');
}
}
// iss
if (issuer != null) {
if (!payload.containsKey('iss') || payload['iss'] != issuer) {
throw JWTInvalidException('invalid issuer');
}
}
// jti
if (jwtId != null) {
if (!payload.containsKey('jti') || payload['jti'] != jwtId) {
throw JWTInvalidException('invalid jwt id');
}
}
return JWT(
payload,
header: header,
audience: _parseAud(payload['aud']),
issuer: payload['iss'],
subject: payload['sub'],
jwtId: payload['jti'],
);
} else {
return JWT(payload);
}
} catch (ex, stackTrace) {
if (ex is Exception && ex is! JWTException) {
throw JWTUndefinedException(ex, stackTrace);
} else {
rethrow;
}
}
}