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

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(),
        );
        if (!iat.isAtSameMomentAs(clock.now())) {
          throw JWTInvalidException('invalid 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;
    }
  }
}