richard.herbert
07/06/2023, 1:45 PMaccess_token
produced by Azure AD returned to me from a Nuxt SPA.
I can drop the access_token
into jwt.io and it will decode but it says it has an "Invalid signature".
When I offer it to the ColdBox module cbSecurity decode()
method when the algorithm is set to RS256
it says "Cannot decode token: Invalid PEM key".
The Azure AD consultant is saying.
so looks like the API may have to do a little leg work itself. In .net, you pass in the well-known url and the auth middleware knows what to do. Here it looks like they need to be provided the pub cert to validate the signature and plumb that into their CF app. As a starting point, they can get the cert used for that token from <https://login.microsoftonline.com/*******************/discovery/v2.0/keys>, and finding the appropriate kid (married up with the kid in the token)
So tactical 'let just get it working' would be to provide that cert to the CF app. Ideal/most robust would be the CF API accepting a config param on startup specifying the well-known endpoint (<https://login.microsoftonline.com/*******************/v2.0/.well-known/openid-configuration>) - that then references the jwks url, and read the kid in the passed token to lookup the appropriate cert on the jwks url. Means if anything ever changes, the CF app should gracefully handle it all
I've looked at the content behind those two URL and they look like JSON packets rather than certificates which is what I thought I needed to provide to be able to check the signature on the access_token
As you may have guessed, this is outside of my comfort zone. Can someone help me translate this before I go into a meeting tomorrow about it?Brian
07/06/2023, 1:56 PMrichard.herbert
07/06/2023, 2:02 PMaccess_token
in an Authorization header and been asked to decode it. I'm guess the token is good as jwt.io can decode it but with the warning that the signature is not valid. Which I guess is fair as they shouldn't know what the key is. I can try and see what the cbSecurity.decode() method is doing and falling over with but that's the extent of the CF code-side of things.
I was expecting to be given a PEM certificate that I could use to check the signature with but those JSON packets don't look like certs.Brian
07/06/2023, 2:07 PMrichard.herbert
07/06/2023, 2:54 PMaccess_token
in the Authorization header. We won't be going to AAD again. The app is all front-end Nuxt and backend CFML API. Nothing on the Azure side apart from this authentication via AD.
Or am I missing something fundamental here?jcberquist
07/06/2023, 9:03 PM.parseHeader(jwt)
(see https://github.com/jcberquist/jwt-cfml#getting-the-token-header). You would take the "kid" from the parsed header and find the key with that "kid" in the keys MS provides. Then you would call .decode(jwt, jwk, 'RS256')
to decode and verify the JWT. (see https://github.com/jcberquist/jwt-cfml#decoding-tokens)
Hope this helps!paul
07/07/2023, 3:42 AMrichard.herbert
07/07/2023, 6:56 PMBase 64 decode the tokenI didn't realise that but useful knowledge. I can now decode the claim out of the
access_token
with that but I'd still like to validate the signature.
@jcberquist There's a lot in your reply, which I appreciate, but some of the terminology is unfamiliar to me. This what I've done and where I'm now stuck.
By base64 decoding the access_token
header I can get algorithm and token type which give me the kid
value.
From <https://login.microsoftonline.com/*******************/v2.0/.well-known/openid-configuration>
I can read the jwks_uri
value that looks like <https://login.microsoftonline.com/*******************/discovery/v2.0/keys>
and from there I can find the key where the kid
values match. With that I can get the x5c
value for that key.
I think I have all the parts but this is where I get stuck.
When I do decode( access_token, x5c, 'RS256')
I get "_Invalid PEM key_".
I'm obviously doing something wrong or missed a step but I'm at a loss to know what!
Your help would be appreciated. I'm happy to share actual values with you by DM if you are willing to take a look. Also I'm at the point where I'm happy to pay for some of your time.jcberquist
07/07/2023, 8:49 PMx5c
value, but the entire JSON key object (converted to a CFML struct)? Specifically it should have the keys n
and e
(as an RSA public key).richard.herbert
07/07/2023, 9:05 PMrichard.herbert
07/07/2023, 9:06 PMJohn F
07/08/2023, 2:21 PMcfhttp(method="get", url=LoginAuth.GetJwksUri(), result="JwksRequest")
if(JwksRequest.ResponseHeader.Status_Code != "200"){
// handle not being able to connect to the auth service
}
var Keys = JwksRequest.FileContent.DeserializeJson().keys
var JwtUtils = new <http://path.to|path.to>.jwt.library
var SigningKeyId = JwtUtils.GetHeader(form.id_token).kid
var SigningKey = Keys.filter(key => return key.kid == SigningKeyId)
var Jwk = JwtUtils.parseJwk(SigningKey.first())
try {
var IdTokenResult = JwtUtils.decode(
token = form.id_token,
key = Jwk,
algorithms = "RS256",
claims = {
aud : LoginAuth.GetClientId(),
tid : LoginAuth.GetTenantId(),
..... more claims as needed ........
}
)
} catch(any e){
// handle not being able to validate and decode
}
// lookup the user and log them in if you find a match
richard.herbert
07/10/2023, 8:31 AMaccess_token
signature can't be verified as it is currently formatted. Which is reassuring that I was doing everything right but the token was never going to verify. I need to go back to the author of that token with this information.
https://stackoverflow.com/questions/76001593/azure-jwt-verification-in-go-is-not-working