arun11299 / cpp-jwt

JSON Web Token library for C++
MIT License
387 stars 112 forks source link

jwt::InvalidKeyError #99

Open clobotorre opened 1 year ago

clobotorre commented 1 year ago

I have this minimal jwt verification example that throws a jwt::InvalidKeyError exception:

include "jwt/jwt.hpp"

int main() {
    std::string token = "(omitted)";    
    std::string secret = "-----BEGIN PUBLIC KEY-----\nMIID"(omitted)"\n-----END PUBLIC KEY-----";   

    auto dec_obj = jwt::decode(token, jwt::params::algorithms({"RS256"}), jwt::params::secret(secret), jwt::params::verify(true));

    return 0;
}

The token was obtained from an openId issuer on an user authentication flow. From the token header I got the alg and the kid attributes.

Using the issuer jwks_uri and the kid from the token header I got the x5c string:

{ "kty": "RSA", "use": "sig", "kid": "(omitted)", "x5t": "(omitted)", "n": "(omitted)", "e": "(omitted)" "x5c": ["MIID(omitted)"], "issuer": "(omitted)", }

As stated on https://github.com/arun11299/cpp-jwt/issues/51, I added to the x5c string a '\n' after each block of 64 characters, and finally enclosed it between "-----BEGIN PUBLIC KEY-----\n and -----END PUBLIC KEY-----

What was wrong here?

What should I do to verify the token with this library using the 'n' and 'e' attributes instead the kid?

arun11299 commented 1 year ago

Hi @clobotorre Are you able to decode the secret using openssl command line or even some online decoders ?

clobotorre commented 1 year ago

I'm sorry, I don't know how to do that. Could you explain how to do it?

clobotorre commented 1 year ago

Update: I creates a file (say x5c) and split the x5c string got from jwks_uri in lines of 64 characters length I added a first line in the x5c file with: -----BEGIN CERTIFICATE-----

I added a last line in the x5c file with: -----END CERTIFICATE-----

Then I execute this: cat x5c | openssl x509 -pubkey -noout

Output from previous command was: -----BEGIN PUBLIC KEY----- (omitted) -----END PUBLIC KEY-----

Now join the previous lines with '\n' and use it as 'secret' parameter in the call to auto dec_obj = jwt::decode(token, jwt::params::algorithms({"RS256"}), jwt::params::secret(secret), jwt::params::verify(true));

Then it succeded.

So, the question is: How can I do what openssl command did with your library? Do I have to use another third party library?

arun11299 commented 1 year ago

@clobotorre Openssl only needs that the string you provide is a valid certificate. I usually use online certificate validators; just google "online cert validation". BUT, I would advise against sharing valid in-use certs. For openssl command line, please check https://www.ibm.com/support/pages/openssl-commands-check-and-verify-your-ssl-certificate-key-and-csr

clobotorre commented 1 year ago

@arun11299 : I think you didn't understand my last question. In such a case I will explain it again.

Whenever a user tries to authenticate in my application, it redirects the user to the issuer authentication flow At the end of that authentication flow the issuer redirects the user to a URL of my app, with a JWT on that request. My app must validate that JWT to allow the user login This JWT contains in the header an attribute called kid I have a key set provided by the openId issuer throught its jwks_uri. Each key has an unique kid attribute, so for each specific user login process my app receives a specific kid, with wich a specific key can be found in the jwks_uri key set. That key contains something like this: { "kty": "RSA", "use": "sig", "kid": "(omitted)", "x5t": "(omitted)", "n": "(omitted)", "e": "(omitted)" "x5c": ["MIID(omitted)"], "issuer": "(omitted)", }

What I need is to know how my app can validate the JWT received. The JWT validation consists on several claims validation your library can do and a signature verification using the received key.

As long as I could see, the x5c attribute is a public certificate, and using a x509 library my app could manage to extract a public key from that certificate, and use that public key with your library to verify the JWT signature.

The questions for you are: 1) Is there any way to verify a JWT with your library using the "x5c" attribute, without a third party library? 2) Is there any way to verify a JWT with your library using the "n" and "e" attributes, without a third party library?

arun11299 commented 1 year ago

@clobotorre It's been quite a while, so I may be forgetting few things here and there. Apologies for that. So, If I understand correctly, your JWT signature header has 'x5c' attribute which contains a public key and you want to use that as a secret to validate the JWT ? If that's the case, then I think you can start with doing a jwt::decode twice. First time with verify set to false, in which case you would still get the decoded object. Now you can call the decode again with the secret set as the x5c attribute and verify set to True. There maybe better internal APIs to avoid second decode.

I am not sure what you mean by using 'n' and 'e' value in the second question.

Hope this helps.