Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting JWKS for Firebase in rfc7517 format

I'm using Firebase to authenticate users in my app. Firebase generates a JWT token that I need to authentify on my server. I use tyk.io to do it. Tyk supports these tokens but requires the data source for the public keys to be in the https://www.rfc-editor.org/rfc/rfc7517 format.

Is there an easy way to get this directly from Google/Firebase?

I know I can get the keys from https://www.googleapis.com/service_accounts/v1/metadata/x509/[email protected] but this is not the expected format.

I can also get jwk from https://www.googleapis.com/service_accounts/v1/jwk/[email protected] which is the right format but doesn't contain the keys (I need the keys in a X5c field, so X.509 Certificate Chain)

like image 701
Pierre Leonard Avatar asked Apr 09 '19 14:04

Pierre Leonard


People also ask

How do I find my JWKS URL?

JSON Web Key Set (JWKS) Auth0 exposes a JWKS endpoint for each tenant, which is found at https://YOUR_DOMAIN/.well-known/jwks.json .

How do I get the JWT token from Firebase authentication?

To achieve this, you must create a server endpoint that accepts sign-in credentials—such as a username and password—and, if the credentials are valid, returns a custom JWT. The custom JWT returned from your server can then be used by a client device to authenticate with Firebase (iOS+, Android, web).

What is JWKS URL?

JWKS is JSON Web Key Set - a JSON notation for sharing public keys which are used to verify the signature of a signed JWT.

What is JWKS endpoint?

The JSON Web Key Set (JWKS) endpoint is a read-only endpoint that returns the Identity Server's public key set in the JWKS format. This contains the signing key(s) that the Relying Party (RP) uses to validate signatures from the Identity Server.


1 Answers

As you noticed reading the Tyk library on GitHub, Tyk has chosen to only support RSA keys published within a certificate, in JWK sets.

PRELIMINARY NOTES:

The RSA key that Google uses to sign a JSON Web token is taken among one of the two keys published at https://www.googleapis.com/service_accounts/v1/jwk/[email protected]

Those two keys are the ones that are used to make the two certificates at https://www.googleapis.com/service_accounts/v1/metadata/x509/[email protected]

Note that these certificates are self-signed, here is the content of one of them:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 4804715264884888226 (0x42adc713b25c52a2)
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: CN=securetoken.system.gserviceaccount.com
        Validity
            Not Before: Apr  2 21:20:50 2019 GMT
            Not After : Apr 19 09:35:50 2019 GMT
        Subject: CN=securetoken.system.gserviceaccount.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:cc:7c:14:e6:5c:95:94:4b:95:74:0d:47:9d:e1:
                    [...]
                    60:d1
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage: critical
                TLS Web Client Authentication
    Signature Algorithm: sha1WithRSAEncryption
    [...]

As you can see, the issuer has the same value than the subject, therefore the certificate chain is made of a single self-signed certificate. This means that you can not check the validity of this certificate using a Certificate Authority: there is no global well-known Certificate Authority that has signed the public RSA keys from Google to make those certificates. But the certificates are downloaded by means of SSL/TLS from a Google web server that is authenticated with a certificat that is signed by GlobalSign, so downloading the certificates using SSL/TLS is sufficient to be sure those certificates contain the RSA keys that Google uses to sign the JWT.

The certificates are valid only during a few weeks and have an overlapping period of validation to avoid clock skews, and there is a rolling key mechanism that is applied nearly every two weeks.

ANSWER TO YOUR QUESTION:

You need to create the public-key source yourself for Google to work with Tyk: you must create a document on your application server that contains the JWK set. We suppose you publish this JWK set here: https://my-application-server.com/jwks.json

So, in your Tyk API Definition, in the JWT secret field, you need to put this JWK set URL: https://my-application-server.com/jwks.json.

For that, see the part about JWT secret field in this page: https://community.tyk.io/t/multiple-auth-schemes-for-single-api-definition/694/4

You need to refresh this document every week, because Google does roll the keys about every two weeks.

This document can be made with the following shell command, using only curl and the JSON Command Line Processor named jq:

curl -s 'https://www.googleapis.com/service_accounts/v1/metadata/x509/[email protected]' | jq '[ to_entries | .[] | {alg: "RS256", kty: "RSA", use: "sig", kid: .key, x5c: (.value | sub(".*"; "") | sub("\n"; ""; "g") | sub("-.*"; "")) } ] | {"keys": .}'

Here is the output of this command line:

% curl -s 'https://www.googleapis.com/service_accounts/v1/metadata/x509/[email protected]' | jq '[ to_entries | .[] | {alg: "RS256", kty: "RSA", use: "sig", kid: .key, x5c: (.value | sub(".*"; "") | sub("\n"; ""; "g") | sub("-.*"; "")) } ] | {"keys": .}'
{
  "keys": [
    {
      "alg": "RS256",
      "kty": "RSA",
      "use": "sig",
      "kid": "7d2f9f3fb83d6337497b6f7cd2cff4dfa5c2e8b8",
      "x5c": "MIIDHDCCAgSgAwIBAgIIQq3HE7JcUqIwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UEAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTkwNDAyMjEyMDUwWhcNMTkwNDE5MDkzNTUwWjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tlbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMx8FOZclZRLlXQNR53h+mYYjo9X4Hi38dAsLrP2iRzt8PowOnqx7hxpr9Ag7NKTSAOXTUAmObCRkEooRLe6jcScu+nttpjqqvtOyzhTl2szbdsiRhveXmOwMMbZ/DCkXll6i2NoeeRxVy4qxMDMPM6pokjsUyuq9wkWH+fiUG8rYSZVhpCqfOtqoTBu0zf+PyuGDPlLKKkE6Y7WKp5Go/tIMS6kTz5vhnA3M0HNWdZDy+06kT0eTxajzcs/QXiqmMzJEsJ7ln0Qh1KnOZwMH578y9GYM3ytMdiybDQM0c4cWtLp0REjlKyzqh0LLA7fmdjmEmIgOSy1wzftcKnfYNECAwEAAaM4MDYwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADggEBAFpLrULiau0nFLjRXxt9lwjgft1elBt265Hu88TU3132Wbh00Yvm7hlOA34gVIVNPcgT5lCxc4qVLXbA6yPtnyDubvULmVxyCSKfX/2M4Td+yPF99xR3VVCpATPAVjtOo819Q/Of+icQlmSoy/I0lFJewwrqcRc0eC9UgzF+EvGXHzIfoNlQgFjf/fnG1OV7d2Zr8bj+Jk/zZwVRstKCTrPgyqCYe/y7PU9q0aIQnMRvYKdLj/TfaBolQ12Tlb2j+nGMrPH5uVsUUu6nZluhaMvmlhp8glvslmjlXCIuce/N8FSw7zVf/ofRrDzTw98N1DZG2aLRyRYdmsXDBqMaac8="
    },
    {
      "alg": "RS256",
      "kty": "RSA",
      "use": "sig",
      "kid": "ff1df5a15b5cf582b61a21385c0cfaedfdb6a748",
      "x5c": "MIIDHDCCAgSgAwIBAgIIcqcNMyhOv18wDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UEAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTkwMzI1MjEyMDUwWhcNMTkwNDExMDkzNTUwWjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tlbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKnDRgOsHY55P2i7wX6Uh8YO/rBWmGgVgeBqCowbHopF5HA1EdF0NXSmBn1Myg+DLFqxf0nvsi8B5pjd/rNtVPX6OUIkAKGPyva/d2aQqsHliCFh81QDs2vHIeIAThbQZP514t/z2M79SWR7A0vRYcWf+I+eTL6Vf1nqO3cFwTJVtwiTPom+NjZKx7ukowtqm1mVef+FqceC5zx8D5wzLLtUx/tMPvnXaysSjNN+86cPKc02kumCqlt7Yuf5G9VptjAVqsQyL/X5WuIVuzkFrfh/IPidw7Wzm3s5u928aLNSNbFpEpeXqJ8utD4AZnfm9mg6PYNtFWIB/L6xf21iZOECAwEAAaM4MDYwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADggEBAEdXAGI27mRT+Qkz9vbGlGbKJZKLG6b6c/SAQkOZJDOX4sJ16WgbfsixGBEWmvMMiEwhWV0hbhTiEC22xUd7cRP6veRlKba4rKoYA0x3GJhpDpAviuKPFkCanLFlFOXouexQIxBudWm32B8YFpLW9ds8m9yFmQZwE5GZs1hJ1jb2z2u7AuZNdQnaQ7mKy7Vmt3yHb9NjPlvmQ//ijFR3Lw4XB3nlYcL77mjjd3fhBodfUFkPJpsY2wOQpRLxDbvjHsXSfsgQ+/a+9IjKj0F2YOu9HnvjTXCopWObA9AGV6HR2L6RGaRLTwH+xV2El8UrzTYFPPN/URLui3XtaGdiREg="
    }
  ]
}

The content of this output must be saved in a file corresponding to https://my-application-server.com/jwks.json

like image 173
Alexandre Fenyo Avatar answered Nov 15 '22 07:11

Alexandre Fenyo