validateGCPRequestJWT method

Future<bool> validateGCPRequestJWT(
  1. Request request, {
  2. String? verifyAudience,
})

Implementation

Future<bool> validateGCPRequestJWT(
  shelf.Request request, {
  String? verifyAudience,
}) async {
  try {
    String? authHeader = request.headers['authorization'];
    if (authHeader == null || !authHeader.startsWith('Bearer ')) {
      warn("Invalid Authorization header");
      return false;
    }

    String token = authHeader.substring('Bearer '.length);
    JsonWebSignature jws;
    try {
      jws = JsonWebSignature.fromCompactSerialization(token);
    } catch (_) {
      warn("Invalid JWT, could not parse");
      return false;
    }

    JoseHeader commonProtected = jws.commonProtectedHeader;
    String? kid = commonProtected.keyId;

    if (kid == null) {
      warn("Invalid JWT, no kid");
      return false;
    }

    Map<String, JsonWebKey> jwks = await _fetchGoogleCerts();
    JsonWebKey? publicKey = jwks[kid];
    if (publicKey == null) {
      warn("Invalid JWT, no public key cant verify right key");
      return false;
    }

    if (jws.recipients.isEmpty) {
      warn("Invalid JWT, no recipients.");
      return false;
    }
    JoseRecipient recipient = jws.recipients[0];
    List<int>? verifiedPayloadBytes = jws.getPayloadFor(
      publicKey,
      commonProtected,
      recipient,
    );

    if (verifiedPayloadBytes == null) {
      // That means signature validation failed.
      warn("Invalid JWT, signature validation failed");
      return false;
    }

    Map<String, dynamic> payload = jws.unverifiedPayload.jsonContent;
    String? issuer = payload['iss'] as String?;

    if (issuer != 'accounts.google.com' &&
        issuer != 'https://accounts.google.com') {
      warn(
        "Invalid JWT, invalid issuer. $issuer is not accounts.google.com or https://accounts.google.com.",
      );
      return false;
    }

    if (verifyAudience != null) {
      String? audience = payload['aud'] as String?;
      if (verifyAudience != audience) {
        warn(
          "Invalid JWT, invalid audience. Expected $verifyAudience but got $audience",
        );
        return false;
      }
    }

    dynamic expValue = payload['exp'];

    if (expValue is! int) {
      warn("Invalid JWT, invalid exp type");
      return false;
    }

    int exp = expValue;
    int nowInSeconds = DateTime.now().toUtc().millisecondsSinceEpoch ~/ 1000;
    if (exp < nowInSeconds) {
      warn("Invalid JWT, expired $exp < $nowInSeconds");
      return false;
    }
    return true;
  } catch (e, es) {
    warn(
      "Encountered an exception while trying to verify JWT, so we cant verify.",
    );
    error("Failed to verify JWT: $e");
    error(es);
    return false;
  }
}