I have an angularjs SPA web app which uses ADAL-JS (and adal-angular). It's set up to authenticate vs our corporate AD in MS Azure. The log-in flow seems to work correctly, and the SPA receives an id_token.
Next, when the user clicks a button, the SPA makes a request to a REST API I am hosting on AWS API Gateway. I am passing the id_token on the Authorization: Bearer <id_token>
header.
The API Gateway receives the header as intended, and now has to determine if the given token is good or not to either allow or deny access.
I have a sample token, and it parses correctly on https://jwt.io/ but I have so far failed to find the Public Key or Certificate I should use to verify the signature. I have looked in:
I think I should use the value of the x5c property of the key in https://login.microsoftonline.com/common/discovery/keys matching the kid and x5t properties from the JWT id_token (currently a3QN0BZS7s4nN-BdrjbF0Y_LdMM
, which leads to an x5c value starting with "MIIDBTCCAe2gAwIBAgIQY..." ). However, the https://jwt.io/ page reports "Invalid Signature" (I also tried wrapping the key value with "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----").
Also, is there a (possibly python) library that can facilitate the verification of a given id_token as in the case above (so that I won't have to go grab the signing key on the fly myself?)... The best I could find (ADAL for python) doesn't seem to provide this feature?
The best solution I could put together so far:
Grab the certificate (the first value in the x5c
property array) from either https://login.microsoftonline.com/common/discovery/keys
or https://login.microsoftonline.com/common/discovery/v2.0/keys
, matching kid
and x5t
from the id_token.
Wrap the certificate in -----BEGIN CERTIFICATE-----\n
and \n-----END CERTIFICATE-----
(the newlines seem to matter), and use the result as Public Key (in conjunction with the id_token, on https://jwt.io/ ).
Of course, your actual use case will likely be to have some program validate the incoming JWT id_tokens, so your goal won't be to simply get the token to validate through the web UI on https://jwt.io/.
For instance, in python, I need something like this:
#!/usr/bin/env python
import jwt
from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.backends import default_backend
PEMSTART = "-----BEGIN CERTIFICATE-----\n"
PEMEND = "\n-----END CERTIFICATE-----\n"
mspubkey = "The value from the x5c property"
IDTOKEN = "the id_token to be validated"
tenant_id = "your tenant id"
cert_str = PEMSTART + mspubkey + PEMEND
cert_obj = load_pem_x509_certificate(cert_str, default_backend())
public_key = cert_obj.public_key()
decoded = jwt.decode(IDTOKEN, public_key, algorithms=['RS256'], audience=tenant_id)
if decoded:
print "Decoded!"
else:
print "Could not decode token."
For a list of JWT libraries in various languages, see the JWT Site. I'm using pyjwt, and its cryptography dependency (which has binary dependencies, so needs to be built and packaged for the target OS).
And then, of course, you can verify additional details such as the claims as recommended here.
For a JVM solution, using com.nimbusds:numbus-jose-jwt:4.29
is the most straight forward way to parse and validate a signed RSA256 id_token. The following Scala code parses the JWT token with a JSON Web Key:
val jwt = SignedJWT.parse(token)
val n = new Base64URL("Your Modulus Component of RSA Key")
val e = new Base64URL("AQAB")
val rsaKey = new RSAKey.Builder(n, e).keyUse(KeyUse.SIGNATURE).algorithm(JWSAlgorithm.RS256).build()
val verified = jwt.verify(new RSASSAVerifier(rsaKey))
Your application would still need to fetch the JSON Web Key Set from Azure Active Directory B2C discovery/v2.0/key
dynamically to get the set of keys potentially used by AAD B2C. This should probably be cached and have a TTL of not more than 24 hours for efficiency.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With