jonasroussel / dart_jsonwebtoken

A dart implementation of the famous javascript library 'jsonwebtoken'
MIT License
87 stars 29 forks source link

Verifying Firebase Auth JWT #13

Closed jimmyff closed 3 years ago

jimmyff commented 3 years ago

Hi,

I'm attempting to verify Firebase JWT tokens in my cloud function (running on cloudrun). I'm following the guidelines here which refer to the public keys hosted here.

When I'm verifying the JWT, I'm providing a RSAPublicKey key. I assumed the value of this would be the certificate string corresponding to the matching kid (in the JWT header) from the public keys file mentioned above. When I try to verify it I get Invalid RSAPublicKey error. Checking the code I see that a PublicRSAKey needs to start with -----BEGIN RSA PUBLIC KEY----- however the public keys file all start with -----BEGIN CERTIFICATE-----. the parser.dart file shows no headers that mention certificate.

Is it possible to verify the Firebase JWT's using this package? If so could you possibly point me in the right direction? 😅

Thanks


At the moment I have a little bit of test code that looks like so:

import 'dart:convert';
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';

// https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library
bool validateFirebaseJWT(String token) {
  final parts = token.split('.');
  final header =
      json.decode(utf8.decode(base64Decode(_base64Padded(parts[0]))));

  if (!_googlePublicKeys.containsKey(header['kid']))
    throw Exception('No matching public key');

  final kid = header['kid']!;
  final key = _googlePublicKeys[kid]!;
  final jwt = JWT.verify(token, RSAPublicKey(key));

  print('JWT subject: ${jwt.subject}');
  print('JWT audience: ${jwt.audience}');
  print('JWT issuer: ${jwt.issuer}');
  print('JWT jwtId: ${jwt.jwtId}');
  print('JWT payload: ${jwt.payload}');
  print('JWT header: ${jwt.header}');
  return true;
}

String _base64Padded(String value) {
  final lenght = value.length;

  switch (lenght % 4) {
    case 2:
      return value.padRight(lenght + 2, '=');
    case 3:
      return value.padRight(lenght + 1, '=');
    default:
      return value;
  }
}

// Hosted here: https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com
const Map<String, String> _googlePublicKeys = {
  "8f43204a17915e8be7ccd7cb264df6ea383c49ab":
      "-----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIICRh9AZ3kIy0wDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMjEw\nNzAzMDkyMDIzWhcNMjEwNzE5MjEzNTIzWjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAKw7TI2FsKTuCo829eqKsOb9mskZ6giHMcSsjrT+yRRT3rA3\nk/QcZ/L148EC3tMRtnnSMgDbBBPXol3zRooDMNpphjQY88BEK77LyMXD3ZDSi0Dl\ngF4OJJ1YMLtuxg8jUlyYooXQ+hH/XOSjjFAkBTpiC3svTqfn/57Iu8Z61egcnyyC\n3Wm+rt4rXPsmni/97sEx/HRWwJ/5RTA0tDNnfyFploMBUInN36TUcj7g7vmY3xsc\ne/zfJeKLReEnhWv7mTDV/L5LJOYH2ghQpGZes9YCR9VnxwBn5qLE5wJCSVtH9y3u\n5kok1uv3Q24gcailGi6N7ujy0zUiSCscwZPoOh0CAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBAA+OHI08nqK4aBKWI8rg0PtDJb0skcrq29/BtQK8YvFm\nEE/zzwSZRy7z1zWW6SOPprepDwVCalrSGuSt31+pGZquijNXdzoSpKr210QBW/Y3\nxD4dR25+IYHiR8ivU/M2yBKsd2GtnrK1Mgq/2XRXUjLj2ELP/yL+ir6tkOyBqSRX\nxSmww0QdSlJDC0VauU5bxxGLWmXfWXcRR8j56l8UkRfKp71MPJF9F1GEf7loTBe2\n8+EeU1CLUrCYCRrquBHHZMgz2ITVrH4fFftYGyDkmIy01SnmAjdq45i8JS3RLTkm\ntHglMPn7Qoc8N7od8JXi+6y4nXM6wGoVnAOYTuQx8Wg=\n-----END CERTIFICATE-----\n",
  "8b21d5a5ce68c523ee74329b47d844a7bfc84cff":
      "-----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIIaoFFlesPL+QwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMjEw\nNjI1MDkyMDIxWhcNMjEwNzExMjEzNTIxWjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBALSeCjMcyWU6qy8KneBEANK92kK/tj7X1KneB53bdVfXMOc4\nZVn5l+Q+zJhkHYfb5RYYWW+E9oQucBG3xRBRUACmdpD/oOPHR/C0GB8d56ZW8KPf\nn3jY9czdKOwKtCL/hB4/jMxeb1bjv13ECZw1eXFPdebzDHB6xY4jpEiQEcQkp15m\n1bdjON7PAeLtjrLHF4faNcFPyBCcQ9SqB3K4vQPWNcfgUcVk2yOQLhTA7B6ok4WH\nepYGiyberpGmSWoVTj5nBJix/AwYSGXpCxzCk53dV9/K/QBJiWFIenCYZK8wxCmS\nL5Yu1LSnb6HQv7uoGtXs6dHVX6MPVm0OLQCSIb8CAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBAD4iT46nObdo/r0ivwVuIqt8x3Sfz9wSVvXVcO6Z+lqi\nG0eYnvazTeud/EvpmlzlIWob7A4u0svAmimoN8rEj3ZV+fDdM49uruIQyXuurEg0\nJl/IpLRgd+Srr/TjHfOENfWSF9aVeTbWKtWwktpsbUrsKqaMgcp1F0ryFfm85DTv\np9X1Q+LwRq7MZIxgB8+yJV+GYl5v/BzyWROlkwI/WVOtj8nRrOvxAkRxF8BGsP+A\n0OTymYuNKzqDkYfxbCDdTNjZGDthcJviMq1/2k2T/lib5sHdtfGp+JT8/KS/OssW\nj+sdopyR6bW4GpOcJ4mLvR/p/u8MVh1fo2uQ18HDMhc=\n-----END CERTIFICATE-----\n"
};
jimmyff commented 3 years ago

Ah, I believe I need to extract the RSA public key from the certificate, I'll try using the PointyCastle library for that.

fabiotavares commented 1 year ago

I have the same problem. How to extract public key from certificate?