verify static method

JWT verify(
  1. String token,
  2. JWTKey key, {
  3. bool checkHeaderType = true,
  4. bool checkExpiresIn = true,
  5. bool checkNotBefore = true,
  6. Duration? issueAt,
  7. Audience? audience,
  8. String? subject,
  9. String? issuer,
  10. String? jwtId,
})

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;
    }
  }
}