-
Notifications
You must be signed in to change notification settings - Fork 420
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
Cannot validate signature. #609
Comments
@jvandervelden is there a possibility you can share the 'jwt'. You can email me directly if it contains sensitive info. |
@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 |
@jvandervelden I just ran this through validation. How did you obtain that token? |
@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. |
@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. |
@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. |
@jvandervelden i need to understand your topology better. |
@jvandervelden I am going to close this as not supported. |
@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: Token: Header: 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. |
@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. |
Hello, |
@chetanku a token from Graph that has a 'nonce' requires special processing to validate the signature |
@brentschmaltz Do we have any documentation around special processing? Thanks for your help. |
I have the same error and it was due to I have setting into I have change it for my App ID URI adding |
It would be very interesting to hear what this "special processing" means in practice. Could @brentschmaltz or someone else elaborate a bit? Obviously I need to do something because signature validation fails, but what? I'm using Python and would just like to validate that user didn't forge the JWT token. |
I feel like between the various implementations for AAD floating around using access_token there needs to be some much improved communication from Microsoft. I stumbled across this thread by accident after spending an hour trying to figure out why I was unable to validate a token independently (sending every token to the graph API for verification is not the fastest thing in the world to be doing). The whole "special processing" phrase has popped up across several discussions now and I am concerned about the opaque nature of this implementation especially around something as important as authentication which MUST be open and well documented to be considered trustworthy and free from security defects. |
Could please someone provide a way to do the "special processing"? |
Same here I too have "nonce" in my token. Could please someone talk about 'special processing' ? |
@smndey @btastic @metaclassing @lokori I've been OOF most of the past month. Back now. The 'nonce' is a mechanism, that allows the receiver to determine the token was forwarded. The signature is over the transformed nonce, so if you try and validate it directly, the signature will fail. Graph can determine that this token was replayed. |
Good afternoon @brentschmaltz I suspect there are a variety of use cases and desires in the greater community of developers who want to consume identity, especially in an enterprise setting. From a purely academic perspective, I do not believe secrecy results in better security. If Microsoft plans to thrive in a open web service landscape it needs to provide significantly more transparency in token generation, token validation, as well as changes to the AAD API (There have been a couple examples lately where un-communicated changes resulted in BC breaks. Software that was working for months mysteriously stopped with token-can-not-be-generated errors) From a performance perspective in AAD 1 applications that do not have a NONCE I would not want to have to check with the graph API every time a user presents me a token to validate it is good, and have taken to using a shared redis cache between calls to keep from having to do that. The most applicable example I have though is using MSAL with front-end web applications that call to multiple back-end APIs. The front end needs to authenticate the user and use their identity token to request a graph API scoped access token to call the magic /me endpoint for displaying basic user information. In the current model the front end SPA also needs to use the same identity token to request access tokens for 3 back-end API services that are not the graph API. Currently the challenge is on initial authentication this model would send the user to AAD for authorization 3 times for 3 different apps with scopes as each back end API has its own client id and secret. This authorization flow is not ideal (or acceptable as the number of back-end APIs grows) and requires a solution such as the use of a dedicated front-end API or implement an API gateway to scale the number of back-ends doing common authentication and authorization at which point the value add of AAD is somewhat diminished. One feature people have wanted for years is a variable approach to security for consuming identity services, such as a multi-audience access token. The back end API's generally only consume the access token to authenticate the user and perform their own authorization. My web services tend to call the graph API using their own client id and secret to get an access token and retrieve user group information et al eliminating much of the user authorization (or worse, admin authorization) required. I am aware that this approach is considered "less secure" because API 1 could use the same graph token to authenticate to API 2 as the user, but that may be a known and acceptable risk for some applications enabling a much smoother authentication flow and avoiding the need to juggle tokens in the UI. Ultimately if I decide to trust a token generated for an audience other than my client id, that is my call to make. Similarly if I decide that I want to trust the token for longer than AAD is willing to issue it for (days rather than hours) then I control that logic as well. Microsoft appears to be using opaque token validation logic to prevent me from controlling the security / convenience trade-off with my software. |
Could please someone provide a way to do the "special processing"? |
We learned that validating the Graph token is not required. The graph token you get from either doing a web flow or api impersonation will be validated when you make the actual Graph api call. We don't care if it's valid, that will be shown in time when we go do the request and get a 401/403 back. You don't want to use the Graph token as your main app's token, you will want to create an app registration in the portal, which these tokens you can validate. For multiple api endpoints, that's an architecture decision you make. You can go with an api gateway and have all your services/endpoints behind 1, this allows you to only have 1 token for multiple services. Or you can decide to have each api it's own "application" and require a separate token for each. If you go with the separate tokens you can just follow the impersonation flow and use the main app token to get the sub endpoint tokens and the experience is seamless to the user. In the current web any given app needs to keep track of multiple tokens anyway since it will hit multiple resources not necessarily on the same domain or even the same OAuth authority. If you are seeing an 'nonce' in your main app's token, I've seen this when doing the redirect to login.microsoft.com and having '?nonce=' in the url parameters. |
@metaclassing Let me propose this perspective as I don’t believe there is an attempt to hide anything here. Note: this ‘nonce’ is different than the ‘nonce’ in the JWT Payload. MsGraph recognized an opportunity to improve security for users. They achieved this by putting a ‘nonce’ into the jwt header. The JWS is signed with a SHA2 of the nonce, the ‘nonce’ is replaced before the JWS is serialized. To Validate this token, the ‘nonce’ will need to be replace with the SHA2 of the ‘nonce’ in the header. Now this can change since there is no public contract. We do recognize the need for customization. This IdentityModel library has multiple extensibility points for validation: Audience, Issuer, Lifetime, Signature, SigningKey, TokenReplay. A delegate is settable on TokenValidationParameters. If there is something you need, please let us know, we are very open to suggestions. I can’t speak to AAD API breakage, but I can speak to Identity and Access where multiple down-level services are accessed for a single call. As you pointed out, accepting a token for a different audience opens a forwarding attack. There is a model in the works that addresses this issue: https://tools.ietf.org/html/draft-ietf-oauth-signed-http-request-03 App1 obtains a token for App2 that represents a trust between them. When App1 requests a token for App2, a public key is sent with the request to the IdentityProvider. When App1 calls App2, the call is essentially signed. The original token that represents the caller can be included. This model provides the identity of the original caller, protects against leaking of tokens and provides high confidence to App2 that it was App1 that called. The token presented to App2 has the audience for App2. The identity token will have the audience of App1. Custom validation can scope a set of audiences on the identity token. |
At the end of the day, Msft (Azure AD) is currently generating JWT Tokens that fail signature validation. Therefore Msft is non-IETF compliant by failing to generate valid JWT Tokens, eg tokens which can be validated by their provided signature. So, when will Msft fix this? |
@zbrad it is not completely accurate to say that tokens generated by AzureAD are not compliant. There is no implementation defined in oAuth as to what constitutes an access_token for a ResourceServer. It is a contract between the IdentityProvider and the ResourceServer. |
@brentschmaltz I've tried to replace the nonce in the header, but still was not able to validate the access token signature. Could you, please, be more specific about the details of that replacement (e.g. SHA2 = SHA256 with Hex string representation or what)? |
@homutov sure
|
@jschaufele i follow your example and i get the a token that i can validate the signature, but i notice that the token doesnt have user information, i am making some wrong? |
i did what i need, it was a rubbish xD, i was using the access_token to send to my api and make the verification when what i need to use is the id_token... |
Hey
Okay, but
If there is no way to validate the signature of the access tokens, can you update the doc. In that case, it may be time saving to warn about the non-open validation process for non-Microsoft'ish devs who may be used to "common" meaning of JWT else (there is a way to validate), I appreciate @brentschmaltz 's input, but it's not very convenient :/
input = raw string Microsoft JWT
I understand that maybe an AT is just a blob that shouldn't be interpreted . But, why is it possible to configure the content of the access token in portal.azure.com! It's good to do a marketing around JWT usage in docs and in portal. But if you need to make another call to validate the content of the access token, Microsoft should indeed make sure that it doesn't looks like a JWT to make sure there is no confusion. |
@raphaeljoie: access tokens are for the web API. The web API does validate it (ASP.NET / ASP.NET Core do it automatically). If you want to customize the validation, this sample can help: access token should not be validated by clients (which acquire them from the identity provider) as this is not for them. What would be the point of the client validating them? |
Hey @jmprieur thanks for the update :)
what does it mean? How does it happen? Does it happen locally or do you need to make a call to Microsoft Azure Active Directory to validate? The reason why I want to validate a token locally is not the point of my question. I was reading from the doc that it is possible and now trying to understand
The side question is: if it's not possible to validate locally the content of an access token, what is the purpose of that content that is configurable from the portal? |
The configuration of optional claims is for access tokens that contain your aud - tokens issued for your API. You cannot edit Graph or other apps tokens. |
@hpsin indeed, I removed the optional claim but nothing changed. The scope of the configuration was unclear to me. I was dreaming of another answer but it makes sense: no way to use/validate an access token dedicated to another client. What do you suggest as a fallback if I want to both use Graph API and secure my own API without a user backend? a mix of openid + access token? |
If you want to protect an API, then you can create your own API and register scopes for it, and use those. See here for details: https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-configure-app-expose-web-apis And you're correct - you can request a token for Graph, in your client, to call Graph, and then request another token for your own API. Accepting tokens for a different client registration on your API is called the confused deputy problem, and is a common security vulnerability and reliability issue (e.g. if Graph encrypts their tokens tomorrow, does your app self-destruct?) |
After reading all this and 2 days trying to find a fix here is what worked for me. Also notice that the UI of the Azure portal is constantly changing. I assume you have read the whole threat before getting here so i maybe skip some "obvious details". So i wanted to validate the access token in my backend as most here but it would give invalid signature, azure modifies the token before sending it to us so when we try to validate it with the public api will always fail. The way to force azure to not modify the token is to make a request to our own scope not to their graph scopes. So create a new scope in the portal that identifies your backend-api/resource/endpoint: Your App > Expose an API > Add Scope. Fill the fields. For Who can consent? i selected admins and users. The scope name should show something like: api://name-of-your-app/name.of.your.scope Now in the application that you are developing change the request you are doing for login with the msal library adding that scope and only that one if you mix it with other scopes for example for Microsoft graph it will not work. So the request should be something like After that you should get an access_token that passes the validation for example using https://jwt.davetonge.co.uk/ just paste it there |
@hpsin I've read a lot these past two days, and everything you said makes 100% sense. I was passing a Graph access token to my web API and the service could not validate it. So now what? My SPA does call the Graph API on the front end and I also have to call my web api. Now I know I need to use a token that's specifically for my API. I've come to grips that if I want my SPA to have features driven from the Graph API then I need to separately manage two tokens for calling the Graph API and my API. I'm using Azure AD. Am I able to do some sort of token exchange so I don't have to prompt users to sign in twice? Start with a token meant for my API that's given from AAD and exchange it for a Graph token, or do I have that process backwards? I feel the majority of confusion here is a lack of understanding access tokens are only meant for the API they are meant for, and maybe people aren't understanding the access token they get when they use AAD is for the Graph Api. You don't have to do any validation or anything to them which leaves people exposing an API in their App's Registration and specifying a custom scope, which will then let them be able to validate the token, but what about when you need two tokens. One for a custom API and one for the Graph API? |
But why does the https://login.microsoftonline.com/common/discovery/keys endpoint have to expose the same 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. |
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. |
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 |
it is the best explanation for what happened. we just must not validate those MS tokens on the other hand, the 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] |
@maxkoryukov : why would you validate an MS token if you are not the owner of the web API that accepts this token? |
@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. |
@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 |
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. |
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
The text was updated successfully, but these errors were encountered: