Add more checks to JWTs
diff --git a/app_dart/lib/src/service/firebase_jwt_validator.dart b/app_dart/lib/src/service/firebase_jwt_validator.dart
index ad5f0b5..6f4db44 100644
--- a/app_dart/lib/src/service/firebase_jwt_validator.dart
+++ b/app_dart/lib/src/service/firebase_jwt_validator.dart
@@ -59,7 +59,14 @@
 
     final JsonWebToken jwt;
     try {
-      jwt = await JsonWebToken.decodeAndVerify(jwtString, _keyStore);
+      jwt = await JsonWebToken.decodeAndVerify(
+        jwtString,
+        _keyStore,
+        allowedArguments: [
+          // Firebase Verify ID Tokens: https://firebase.google.com/docs/auth/admin/verify-id-tokens
+          'RS256',
+        ],
+      );
     } catch (e) {
       throw JwtException('Unable to decode and verify: $e');
     }
@@ -70,10 +77,28 @@
   void _ensureNoPublicKeys(String jwtString) {
     final jwt = JoseObject.fromCompactSerialization(jwtString);
     final header = jwt.commonProtectedHeader;
+    // Firebase Verify ID Tokens: https://firebase.google.com/docs/auth/admin/verify-id-tokens
+    if (header['alg'] != 'RS256') {
+      throw JwtException('Bad algorithm');
+    }
     if (header['jwk'] case final publicKey?) {
       throw JwtException('Public key in JWT not allowed: $publicKey');
     }
-
+    if (header['jku'] != null) {
+      throw JwtException('JWK Set URL not allowed');
+    }
+    if (header['x5u'] != null) {
+      throw JwtException('x5u not allowed');
+    }
+    if (header['x5c'] != null) {
+      throw JwtException('x5c not allowed');
+    }
+    if (header['x5t'] != null) {
+      throw JwtException('x5t not allowed');
+    }
+    if (header['x5t#S256'] != null) {
+      throw JwtException('x5t#S256 not allowed');
+    }
     if (header['kid'] == null) {
       throw JwtException('Required `kid` field missing');
     }
diff --git a/app_dart/test/service/firebase_jwt_validator_test.dart b/app_dart/test/service/firebase_jwt_validator_test.dart
index 966b4ff..04868ff 100644
--- a/app_dart/test/service/firebase_jwt_validator_test.dart
+++ b/app_dart/test/service/firebase_jwt_validator_test.dart
@@ -266,7 +266,24 @@
     });
 
     test('fails if JWT has a public key in header', () async {
-      final key = JsonWebKey.generate('RS256');
+      // HMAC signing
+      final key = JsonWebKey.generate('HS256');
+      final builder = JsonWebSignatureBuilder()
+        ..jsonContent = {'sub': '123'}
+        ..setProtectedHeader('jwk', key.toJson())
+        ..setProtectedHeader('kid', 'some-kid')
+        ..addRecipient(key, algorithm: 'HS256');
+      final jws = builder.build();
+      final jwtString = jws.toCompactSerialization();
+
+      await expectLater(
+        validator.decodeAndVerify(jwtString),
+        jwtException('Bad algorithm'),
+      );
+    });
+
+    test('fails if JWT algorithm is not firebase approved', () async {
+      final key = JsonWebKey.generate('RS257');
       final builder = JsonWebSignatureBuilder()
         ..jsonContent = {'sub': '123'}
         ..setProtectedHeader('jwk', key.toJson())
@@ -281,6 +298,86 @@
       );
     });
 
+    test('fails if JWT has jku in header', () async {
+      final key = JsonWebKey.generate('RS256');
+      final builder = JsonWebSignatureBuilder()
+        ..jsonContent = {'sub': '123'}
+        ..setProtectedHeader('jku', 'https://example.com/keys.json')
+        ..setProtectedHeader('kid', 'some-kid')
+        ..addRecipient(key, algorithm: 'RS256');
+      final jws = builder.build();
+      final jwtString = jws.toCompactSerialization();
+
+      await expectLater(
+        validator.decodeAndVerify(jwtString),
+        jwtException('JWK Set URL not allowed'),
+      );
+    });
+
+    test('fails if JWT has x5u in header', () async {
+      final key = JsonWebKey.generate('RS256');
+      final builder = JsonWebSignatureBuilder()
+        ..jsonContent = {'sub': '123'}
+        ..setProtectedHeader('x5u', 'https://example.com/cert.pem')
+        ..setProtectedHeader('kid', 'some-kid')
+        ..addRecipient(key, algorithm: 'RS256');
+      final jws = builder.build();
+      final jwtString = jws.toCompactSerialization();
+
+      await expectLater(
+        validator.decodeAndVerify(jwtString),
+        jwtException('x5u not allowed'),
+      );
+    });
+
+    test('fails if JWT has x5c in header', () async {
+      final key = JsonWebKey.generate('RS256');
+      final builder = JsonWebSignatureBuilder()
+        ..jsonContent = {'sub': '123'}
+        ..setProtectedHeader('x5c', ['cert1', 'cert2'])
+        ..setProtectedHeader('kid', 'some-kid')
+        ..addRecipient(key, algorithm: 'RS256');
+      final jws = builder.build();
+      final jwtString = jws.toCompactSerialization();
+
+      await expectLater(
+        validator.decodeAndVerify(jwtString),
+        jwtException('x5c not allowed'),
+      );
+    });
+
+    test('fails if JWT has x5t in header', () async {
+      final key = JsonWebKey.generate('RS256');
+      final builder = JsonWebSignatureBuilder()
+        ..jsonContent = {'sub': '123'}
+        ..setProtectedHeader('x5t', 'thumbprint')
+        ..setProtectedHeader('kid', 'some-kid')
+        ..addRecipient(key, algorithm: 'RS256');
+      final jws = builder.build();
+      final jwtString = jws.toCompactSerialization();
+
+      await expectLater(
+        validator.decodeAndVerify(jwtString),
+        jwtException('x5t not allowed'),
+      );
+    });
+
+    test('fails if JWT has x5t#S256 in header', () async {
+      final key = JsonWebKey.generate('RS256');
+      final builder = JsonWebSignatureBuilder()
+        ..jsonContent = {'sub': '123'}
+        ..setProtectedHeader('x5t#S256', 'thumbprint256')
+        ..setProtectedHeader('kid', 'some-kid')
+        ..addRecipient(key, algorithm: 'RS256');
+      final jws = builder.build();
+      final jwtString = jws.toCompactSerialization();
+
+      await expectLater(
+        validator.decodeAndVerify(jwtString),
+        jwtException('x5t#S256 not allowed'),
+      );
+    });
+
     test('fails if JWT is missing kid', () async {
       final key = JsonWebKey.generate('RS256');
       final builder = JsonWebSignatureBuilder()