verify function
Verifies token against secret using alg, validates standard
time-based claims (exp, nbf, iat), and returns the decoded payload.
Throws JwtException when the signature is invalid, the token is expired, or any other claim check fails.
try {
final payload = await verify(token, secret);
print(payload['sub']);
} on JwtException catch (e) {
print(e.message); // 'Token expired', 'Invalid signature', etc.
}
Implementation
Future<Map<String, dynamic>> verify(
String token,
String secret, [
String alg = 'HS256',
]) async {
final parts = token.split('.');
if (parts.length != 3) throw const JwtException('Malformed token');
final hmac = _hmacFor(alg, utf8.encode(secret));
if (hmac == null) throw JwtException('Unsupported algorithm: $alg');
final expected =
_b64url(hmac.convert(utf8.encode('${parts[0]}.${parts[1]}')).bytes);
if (parts[2] != expected) throw const JwtException('Invalid signature');
final Map<String, dynamic> claims;
try {
claims = Map<String, dynamic>.from(
jsonDecode(utf8.decode(_b64urlDecode(parts[1]))) as Map,
);
} catch (_) {
throw const JwtException('Malformed payload');
}
final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
if (claims['exp'] case final int exp) {
if (now > exp) throw const JwtException('Token expired');
}
if (claims['nbf'] case final int nbf) {
if (now < nbf) throw const JwtException('Token not yet valid');
}
if (claims['iat'] case final int iat) {
if (iat > now) throw const JwtException('Token issued in the future');
}
return claims;
}