-
Notifications
You must be signed in to change notification settings - Fork 430
Description
I am trying to use this library to validate the tokens I receive from our UI. The UI gets it from a login web app that is registered with Azure AD.
I have setup a simple application that takes a token and tries to validate the signature found here: https://github.com/jvandervelden/test-azure-ad-identiymodel-connect
The class that's doing the validation is here: https://github.com/jvandervelden/test-azure-ad-identiymodel-connect/blob/master/TestStuff/TokenValidator.cs
The error I am getting is: 'IDX10503: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.X509SecurityKey , KeyId: z039zdsFuizpBfBVK1Tn25QHYO0'
Simple application with the error:
Any help would be appreciated.
Using NuGet packages:
Microsoft.IdentityModel.Protocols v2.1.3
Microsoft.IdentityModel.Protocols v2.1.3
Microsoft.IdentityModel.Tokens v5.1.3
System.IdentityModel.Tokens.Jwt v5.1.3
Activity
brentschmaltz commentedon May 3, 2017
@jvandervelden is there a possibility you can share the 'jwt'. You can email me directly if it contains sensitive info.
jvandervelden commentedon May 3, 2017
@brentschmaltz No Problem, it's in the image anyway, and it's a test tenancy.
deleted this token as I now understand it's purpose
brentschmaltz commentedon May 5, 2017
@jvandervelden I just ran this through validation.
_rsa.VerifyData(input, signature, _hashAlgorithm, RSASignaturePadding.Pkcs1);
returns false.
https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/src/Microsoft.IdentityModel.Tokens/AsymmetricSignatureProvider.cs#L358
Called from:
https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/src/System.IdentityModel.Tokens.Jwt/JwtSecurityTokenHandler.cs#L911
How did you obtain that token?
jvandervelden commentedon May 5, 2017
@brentschmaltz We have a custom web app registered with our AD that does logins. When you request a login from our app it redirects you to the login.microsoftonline.com page: (https://login.microsoftonline.com/common/oauth2/authorize?response_type=code%20id_token&scope=openid&response_mode=form_post&redirect_uri=http%3A%2F%2Flocalhost%3A8089%2Fsecure%2Flogin&client_id=409e2f16-9ace-4e18-acc3-4c7f6a6fba3a&resource=https://graph.microsoft.com/&nonce=da3d8159-f9f6-4fa8-bbf8-9a2cd108a261&site_id=500879). This posts pack and access code we then use to get a token from: (https://login.microsoftonline.com/common/oauth2/token) which then gives us back the JWT token that I posted.
We use the ADAL for java library to get the token.
brentschmaltz commentedon May 5, 2017
@jvandervelden OK that explains it then. I missed it before, but if look at the Jwt.Header you will see a 'nonce'. This means you need special processing. Normal processing will fail.
jvandervelden commentedon May 5, 2017
@brentschmaltz So what's your suggestion? Should I remove the nonce from the login url? We are going to attempt to validate these in nginx lua and I don't really want to add extra pain.
brentschmaltz commentedon May 5, 2017
@jvandervelden i need to understand your topology better.
Also what scenario are you trying to implement? The token you have is for graph, why are you trying to validate it?
brentschmaltz commentedon May 6, 2017
@jvandervelden I am going to close this as not supported.
jvandervelden commentedon May 8, 2017
@brentschmaltz Here (https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-token-and-claims) states I should be able to validate the id_token and the access_token the same way. When I get to this section (https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-token-and-claims#validating-tokens) it gives an example project for manually validating tokens (https://github.com/Azure-Samples/active-directory-dotnet-webapi-manual-jwt-validation). I ran this project and gave it an id_token which worked, I then gave it my access token which failed with the same error I was seeing.
I tried updating my login url so I didn't have to provide an 'NONCE' parameter which was fine, I got the access_code and sent that on to the token endpoint. No matter what I do the 'NONCE' value is always in the header of my access_token:
Getting the access_token:

Token:
eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFCbmZpRy1tQTZOVGFlN0NkV1c3UWZkcl92QTF0ZF9LSjU1dWV3elY4dUEtc0dPaXBSS3puUEZQenZxNTVmUDhlaTFDcm95Qk9HWThWVjdtTVhJNndKUlNNbkxUUGxPdlNValV2NFlvLUswX3lBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiejAzOXpkc0Z1aXpwQmZCVksxVG4yNVFIWU8wIiwia2lkIjoiejAzOXpkc0Z1aXpwQmZCVksxVG4yNVFIWU8wIn0.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20vIiwiaXNzIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvNWFmYTgwYjUtN2FjNS00MWY3LWIxZjktMDU4MDE5NWIwZDk5LyIsImlhdCI6MTQ5NDI1NTY0MCwibmJmIjoxNDk0MjU1NjQwLCJleHAiOjE0OTQyNTk1NDAsImFjciI6IjEiLCJhaW8iOiJZMlpnWUxpVXZuYnFkcjM5YWVKYzJtR01MaGRtSjdQY0tlallGSk84NVZlZHd1c1pMaDBBIiwiYW1yIjpbInB3ZCJdLCJhcHBfZGlzcGxheW5hbWUiOiJUZXN0QyMiLCJhcHBpZCI6IjQwOWUyZjE2LTlhY2UtNGUxOC1hY2MzLTRjN2Y2YTZmYmEzYSIsImFwcGlkYWNyIjoiMSIsImlwYWRkciI6IjY0LjIzNS4xMDAuNiIsIm5hbWUiOiJKYXNwZXIgVXB0dXJuIiwib2lkIjoiMGZlNzE4ZjQtNWUxYS00MDI5LTk4MmQtZjU0YjQxZTRkMzA2IiwicGxhdGYiOiIzIiwicHVpZCI6IjEwMDM3RkZFQTBDNEZBMkEiLCJzY3AiOiJEaXJlY3RvcnkuQWNjZXNzQXNVc2VyLkFsbCBVc2VyLlJlYWQiLCJzdWIiOiJKcl80X2U5cnRCNS0zZUdtbmxjMmhqWEpyNXZHMVRoUmZyLXhOeHhSR3drIiwidGlkIjoiNWFmYTgwYjUtN2FjNS00MWY3LWIxZjktMDU4MDE5NWIwZDk5IiwidW5pcXVlX25hbWUiOiJqYXNwZXJAdmFuZGVydmVsZGVucy5jYSIsInVwbiI6Imphc3BlckB2YW5kZXJ2ZWxkZW5zLmNhIiwidXRpIjoiRDFqanZXUGVQMDZLZElKSGdPUS1BQSIsInZlciI6IjEuMCIsIndpZHMiOlsiNjJlOTAzOTQtNjlmNS00MjM3LTkxOTAtMDEyMTc3MTQ1ZTEwIl19.ARoy6EBl1UM1U3_uStikPvOND-Y7otrZxVvyunAMrV6D1Wga1CIJJ5UxFpUE-MAwdebj1Pv_YsQ9o3Ys3i9qroAYoiJUDtycqW0iX1sNeoCndm147K3OlcnIQpcw2zupxOFCkecV_kmVroQGTcod4Gtni3P2uTdmeGAJABgf0wa6D0fplYd_GLwkuz1QAXjHe6LsmGwj-5iG7Oquy1mLTEZ4ptyaGSiM5Bv9GGXK1ZyJrDyJVV06cX-VbHF_EiKZlHFzH2OC8hFgyjdP5hPmQAaeSeFPCIir1qEhhSwIIzl7lzDJzNJjU5_dH88QBgA2NVcN8uWI-QniBvr6GrBG3A
Header:
{
"typ": "JWT",
"nonce": "AQABAAAAAABnfiG-mA6NTae7CdWW7Qfdr_vA1td_KJ55uewzV8uA-sGOipRKznPFPzvq55fP8ei1CroyBOGY8VV7mMXI6wJRSMnLTPlOvSUjUv4Yo-K0_yAA",
"alg": "RS256",
"x5t": "z039zdsFuizpBfBVK1Tn25QHYO0",
"kid": "z039zdsFuizpBfBVK1Tn25QHYO0"
}
So what we are doing is, we have a login web app that handles the authentication portion of our system. The user hits 'https://login.ourwebapp.com/secure/login?webApp=https://cloud.ourwebapp.com/'. This redirects them to 'https://login.microsoftonline.com?redirect=https://login.ourwebapp.com&client_id...'. Once the user logins to the azure portal it posts back the access_token to the login webapp. The login web app then uses the ADAL4j library to get the access_token using the access_code provided. It then redirects the user to the webApp url passed in the initial request with the access_token. The second webApp then utilizes this token to validate the user is authenticated and can access it's data. This second web app is where we need to validate the token to make sure the user is authenticated.
jvandervelden commentedon May 10, 2017
@brentschmaltz thank you for your help, I figured out my issue. I was trying to validate an access token that was for the graph api. I created an access token for my web app and I can validate the token now.
chetanku commentedon Apr 16, 2018
Hello,
How was this resolved?
I have an access token that I receive from Graph API. I am trying to validate it with the key found in the https://login.microsoftonline.com/common/discovery/keys. I am using jwt.io. But it fails with Invalid Signature. The token has nonce value. What kind of special processing is required? My goal is to send the token in headers to my api and get the token validated using jwt token validation method. Any help will be great, stuck in this since past few days.
brentschmaltz commentedon Apr 16, 2018
@chetanku a token from Graph that has a 'nonce' requires special processing to validate the signature
77 remaining items
alfonsrv commentedon Jan 27, 2024
But why does the https://login.microsoftonline.com/common/discovery/keys endpoint have to expose the same
kid
s as referenced in the tokens used for Graph API? I feel like this just adds unnecessary confusion.While all of this makes sense (still I don't quite get why we cannot validate a Graph API token), this evidently very common misunderstanding and dozens of hours troubleshooting could have easily been avoided. Not surprised – since: Micro$oft – but what a frustrating shit show journey it has been.
DinoChiesa commentedon Jan 29, 2024
It's not a JWT. It is a TOKEN, of course, but not a JSON Web TOKEN (JWT). Because it's not a JWT, It cannot be validated as if it is a JWT. It looks similar to a JWT, and that has been a source of confusion. But it's not a JWT. That is why you cannot validate it, as if it were a JWT.
I agree.
chandankgonu commentedon Feb 14, 2024
I have same issue Azure AD as has two types of token one is Application Token(able to validate through the Springboot application), 2nd is user token(generated through redirect to your windows login postman://app/oauth2/callback?code=0.AVQAURia5c-_**** login) this token not able to validate.
getting error --- Failed to authenticate since the JWT was invalid
maxkoryukov commentedon May 6, 2024
it is the best explanation for what happened. we just must not validate those MS tokens
on the other hand, the
access_token
looks like JWT, it behaves like JWT, we find it where we usually see JWT, his neighborid_token
is a JWT (still), and there is a JWKS-architecture — everything tells us "it is JWT". and in fact it is "almost JWT", but "improved" by Microsoft and we get it from another public Identity Provider.we have a number of Identity Providers, how many of them use such "customizations"?
actually, I wouldn't sob here "MS stole hours of my time", in fact - my bad, I should read the docs better because they don't call it "JWT".
now, it's time for conspiracy theories: it is not the first time we have seen this iconic MS approach. At least, with Entra and its tokens, they won't be able to "embrace" [/conspiracy mode off]
jmprieur commentedon May 6, 2024
@maxkoryukov : why would you validate an MS token if you are not the owner of the web API that accepts this token?
maxkoryukov commentedon May 6, 2024
@jmprieur most probably after the whole discussion, I'm way out of the topic.
answering the question: I use several fields from the token and sometimes I need to call Graph API (but in many cases, info from the token is enough).
anyway, the issue's header says "Cannot validate signature". Also my question was: why can't I validate something that is supposed to be "validatable"? It is an open standard of JWT that MS has adopted, excepting the "validation" step where a "special processing" is required (deja vu).
now my application (which strives to be IdP independent) can validate any token, with an exception for Entra's ones.
maxkoryukov commentedon May 8, 2024
@jmprieur @brentschmaltz (or ping other MS people who could help)
this page: https://learn.microsoft.com/en-us/entra/identity-platform/access-token-claims-reference --- also needs an update, because it still states "Access tokens are JSON web tokens" and there is nothing about "special processing" on the page.
A lot of other pages already have warnings "do not try to validate accessToken at home", with these warnings it is easier to avoid a lot of troubles and wasted time
mmuzammil196 commentedon Aug 8, 2024
When working with Azure Entra ID, it's important to understand the purpose of the tokens provided:
Access Token: This token is primarily used for authorizing access to APIs like Microsoft Graph. It is issued for a specific audience (API/resource) and may not contain the necessary claims for user authentication. If you're trying to validate this token for user identity, it might not work as expected because it's not designed for that purpose.
ID Token: The id_token is specifically designed for user authentication. It contains claims such as the user's identity, email, and other profile information. This token is what you should validate when you want to verify the user's identity in your application.
DinoChiesa commentedon Mar 30, 2025
You're saying the access token is not an ID token. OK, this is true, and beside the point. The discussion here is that people are trying to validate the signature on the access token. Nobody above (as far as I know, I haven't reviewed the entire thread carefully) said anything about "validate this token for user identity". The main problem is people are trying to validate the signature and are confused (justifiably in my opinion) about why it does not work. As explained above, the signature cannot be verified because despite appearances, the token is not a JWT.
About all the trouble using tokens dispensed from this endpoint,
Both are right.