Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for JWKS? #24

Open
carcinocron opened this issue Oct 13, 2019 · 9 comments
Open

Support for JWKS? #24

carcinocron opened this issue Oct 13, 2019 · 9 comments

Comments

@carcinocron
Copy link

How would you verify and read a JWT signed by a JWKS? Here are some reference libs from other languages:

https://github.com/auth0/node-jwks-rsa
https://github.com/nov/json-jwt/wiki#decode--verify

@stakach
Copy link
Member

stakach commented Oct 15, 2019

It's outlined in the readme: https://github.com/crystal-community/jwt#usage
Just change the algorithm in the example to RS256

@kalinon
Copy link

kalinon commented Jul 16, 2020

So the issue is that i dont see how we can assemble the jkws pem key via the methods available in openssl_ext. I currently have not been able to do it at least.

@kalinon
Copy link

kalinon commented Jul 16, 2020

I believe the request is to support verifying a JWT token via the JWKS method. i.e.:

jwt_token = "aaaa.bbbb.cccc"
info = JSON.parse(Halite.get("https://oauth.com/.well-known/openid-configuration").body)
keys = JSON.parse(Halite.get(info["jwks_uri"].as_s).body)
payload, header = JWT.decode(jwt_token, keys, verify: true, validate: true)

More links on the JWKS auth data:

https://8gwifi.org/jwkconvertfunctions.jsp
https://developer.byu.edu/docs/consume-api/use-api/implement-openid-connect/jwks-public-key-documentation

@stakach
Copy link
Member

stakach commented Jul 16, 2020

@kalinon if I'm reading this correctly there is a desire to have a helper class that can construct and decode the JWKS structure into something a little more useful?

plus, potentially a HTTP wrapper to help with making requests using those keys?

@kalinon
Copy link

kalinon commented Jul 17, 2020

@kalinon if I'm reading this correctly there is a desire to have a helper class that can construct and decode the JWKS structure into something a little more useful?

plus, potentially a HTTP wrapper to help with making requests using those keys?

Perhaps the HTTP wrapper may be out of scope on this request, at a minimum i think we need to be able to pass a JWKS object to JWT.decode or perhaps enhance openssl_ext to allow the creation of RSA public keys from the JWKS information.

I admit i am not an expert in libcrypto or openssl, but it seems being able to set the n, e and other variables is required? I did see empty specs in the openssl_ext for this functionality: https://github.com/randomstate/openssl_ext/blob/master/spec/rsa_spec.cr#L140

The general workflow of JWKS for RS256 is:

  1. reach out to the jwks_uri to get key information
  2. transform the key information into a public key
  3. use public key to verify token

Number 2 is not currently possible via the jwt or openssl_ext libs as far as i can tell.

@kalinon
Copy link

kalinon commented Jul 17, 2020

Here is the RFC: https://tools.ietf.org/html/rfc7517

@rishavs
Copy link

rishavs commented Jul 5, 2021

Any chance of this being added? It will help usecases like integrating google/apple sign ins into our apps or using AWS services using the authenticated api.

For eg.
the google-sign-in's key is at;

pp! pub_key_jwk = HTTP::Client.get "https://www.googleapis.com/oauth2/v3/certs"
pp! pub_key_pem = HTTP::Client.get "https://www.googleapis.com/oauth2/v1/certs"
and I would want to decode like this;
payload, header = JWT.decode(token, pub_key_pem , JWT::Algorithm::HS256)

@rishavs
Copy link

rishavs commented Jul 17, 2021

So after some headache, I have a very simple and reductive JWK to JWT which uses use mod and exp.

require "base64"
 
pp! jwk = {
  "n": "3aOynmXd2aSH0ZOd0TIYd5RRaNXhLW306dlYw26nMp6QPGaJuOeMhTO3BO8Zt_ncRs4gdry4mEaUOetCKTUOyCCpIM2JAn0laN_iHfGKTYsNkjr16FiHWYJmvNJ1Q1-XXjWqNNKMFIKHKtMrsP2XPVD6ufp-lNQmt4Dl0g0qXJ4_Y_CKuP-uSlFWZuJ_0_2ukUgevvKtOZNcbth0iOiFalBRDr-2i1eNSJWOknEphy7GRs-JGPboTdHC7A3b-0dVFGMEMJFhxcEJHJgLCsQGdYdkphLJ5f21gCNdhp3g16H3Cqts2KTXgO4Rr8uhwZx5yiUjTuizD9wc7uDso4UJ7Q",
  "use": "sig",
  "kty": "RSA",
  "kid": "b6f8d55da534ea91cb2cb00e1af4e8e0cdeca93d",
  "alg": "RS256",
  "e": "AQAB"
}
 
mod_hex = Base64.decode(jwk["n"]).hexstring
exp_hex = Base64.decode(jwk["e"]).hexstring
 
pub_key_hex = "30820122300D06092A864886F70D01010105000382010F003082010A0282010100" + mod_hex + "0203" + exp_hex
 
pp! pub_key = Base64.encode(String.new(pub_key_hex.hexbytes))

This only uses

parameter n: Base64 URL encoded string representing the modulus of the RSA Key.
parameter e: Base64 URL encoded string representing the public exponent of the RSA Key.

out of all possible jwk fields

parameter d: Base64 URL encoded string representing the private exponent of the RSA Key.
parameter p: Base64 URL encoded string representing the secret prime factor of the RSA Key.
parameter q: Base64 URL encoded string representing the secret prime factor of the RSA Key.
parameter dp: Base64 URL encoded string representing the first factor CRT exponent of the RSA Key. d mod (p-1)
parameter dq: Base64 URL encoded string representing the second factor CRT exponentof the RSA Key. d mod (q-1)
parameter qi: Base64 URL encoded string representing the first CRT coefficient of the RSA Key. q^-1 mod p

@dukenguyenxyz
Copy link

I made a lib for this here: https://github.com/place-labs/jwks

I also wouldn't mind merging this into this repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants