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

Cannot validate signature. #609

Closed
jvandervelden opened this issue May 3, 2017 · 77 comments
Closed

Cannot validate signature. #609

jvandervelden opened this issue May 3, 2017 · 77 comments
Labels
Customer reported Indicates issue was opened by customer Investigate We are not quite sure what the issue is.

Comments

@jvandervelden
Copy link

jvandervelden commented May 3, 2017

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

@brentschmaltz
Copy link
Member

@jvandervelden is there a possibility you can share the 'jwt'. You can email me directly if it contains sensitive info.

@brentschmaltz brentschmaltz added Investigate We are not quite sure what the issue is. Customer reported Indicates issue was opened by customer labels May 3, 2017
@jvandervelden
Copy link
Author

jvandervelden commented 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
Copy link
Member

brentschmaltz commented May 5, 2017

@jvandervelden
Copy link
Author

jvandervelden commented 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
Copy link
Member

brentschmaltz commented 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
Copy link
Author

@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
Copy link
Member

brentschmaltz commented 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
Copy link
Member

@jvandervelden I am going to close this as not supported.

@jvandervelden
Copy link
Author

@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:
image

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
Copy link
Author

@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
Copy link

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
Copy link
Member

@chetanku a token from Graph that has a 'nonce' requires special processing to validate the signature

@chetanku
Copy link

chetanku commented Apr 16, 2018

@brentschmaltz Do we have any documentation around special processing?
Is there anyway we can remove the nonce from the header?
One more question:
Can we use the access token we get from 'https://login.microsoftonline.com/tenantID/oauth2/v2.0/authorize'
for securing back end(validation from backend API)? or do we need id_token in response?
Also, I read in some articles that the aud in the header needs to be changed to your API. Currently, it is https://graph.microsoft.com

Thanks for your help.

@rjurado01
Copy link

I have the same error and it was due to I have setting into scope field of token request (doc) the graph app uri: https://graph.microsoft.com/.default.

I have change it for my App ID URI adding /.default and it works.

@lokori
Copy link

lokori commented May 4, 2018

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.

@metaclassing
Copy link

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.

@btastic
Copy link

btastic commented May 26, 2018

Could please someone provide a way to do the "special processing"?

@somdey
Copy link

somdey commented Jul 15, 2018

Same here I too have "nonce" in my token. Could please someone talk about 'special processing' ?

@brentschmaltz
Copy link
Member

@smndey @btastic @metaclassing @lokori I've been OOF most of the past month. Back now.
I need to understand how you obtain that token and why you want to accept it.
If the audience is 'microsoft.Graph' you shouldn't be accepting it. Only tokens that are for the host, should be accepted.

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.

@metaclassing
Copy link

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.

@V1122am
Copy link

V1122am commented Jul 17, 2018

Could please someone provide a way to do the "special processing"?

@jvandervelden
Copy link
Author

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.

@brentschmaltz
Copy link
Member

@metaclassing
Thanks for your feedback.

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.

@zbrad
Copy link

zbrad commented Oct 17, 2018

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?

@brentschmaltz
Copy link
Member

brentschmaltz commented Oct 18, 2018

@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.
Since this token is meant for graph and graph can validate it, it is all perfectly fine. It's questionable to make access decisions based off a token that wasn't issue to the receiver.

https://tools.ietf.org/html/rfc6749#section-1.4

@homutov
Copy link

homutov commented Nov 9, 2018

To Validate this token, the ‘nonce’ will need to be replace with the SHA2 of the ‘nonce’ in the header.

@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)?

@brentschmaltz
Copy link
Member

@homutov sure

            string hashAlgorithm = null;
            try
            {
                var alg = header.Property(JwtHeaderParameterNames.Alg).Value.Value<string>();
                if (!TokenValidator.HashAlgorithmMap.TryGetValue(alg, out hashAlgorithm))
                    hashAlgorithm = SecurityAlgorithms.Sha256;

                nonceProperty.Value = GetHashedNonce(hashAlgorithm, nonceProperty.Value.Value<string>());
            }
            catch(Exception ex)
            {
                throw new TokenCreationException(LogHelper.FormatInvariant(LogMessages.S2S32205, ex));
            }



    private static string GetHashedNonce(string algorithm, string nonce)
    {
        HashAlgorithm hashAlgorithm = null;
        try
        {
            if (string.IsNullOrEmpty(algorithm))
            {
                hashAlgorithm = SHA256.Create();
            }
            else
            {
                switch (algorithm)
                {
                    case SecurityAlgorithms.Sha256:
                        hashAlgorithm = SHA256.Create();
                        break;

                    case SecurityAlgorithms.Sha384:
                        hashAlgorithm = SHA384.Create();
                        break;

                    case SecurityAlgorithms.Sha512:
                        hashAlgorithm = SHA512.Create();
                        break;

                    default:
                        throw new TokenCreationException("hash algorithm not supported");
                }
            }
            return Base64UrlEncoder.Encode(hashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(nonce)));
        }
        finally
        {
            if (hashAlgorithm != null)
                hashAlgorithm.Dispose();
        }
    }

@polzka90
Copy link

@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?

@polzka90
Copy link

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...
https://stackoverflow.com/questions/31495063/what-is-the-difference-between-id-token-and-access-token-in-auth0#:~:text=An%20access_token%20is%20useful%20to,often%20used%20by%20your%20app.

@raphaeljoie
Copy link

raphaeljoie commented Nov 17, 2020

Hey

Stop. Stop everything in this thread. Access tokens are opaque blobs of text that are for the resource only. If you're a client getting a token for Graph, assume that it's an encrypted string that you should never look at - sometimes it will be. We use a special token format for Graph that they know how to validate - you shouldn't be looking at access tokens if they're not for you.
@hpsin

Okay, but

To validate an id_token or an access_token, your app should validate both the token's signature and the claims
https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens#validating-tokens

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 alg.

else (there is a way to validate), I appreciate @brentschmaltz 's input, but it's not very convenient :/
I know there is a crazy load of extended example using fancy frameworks and flows. But can't you provide a pseudo-code process to validate raw Microsoft JWT payload. Like

validateToken(token):
    ...
    return True

input = raw string Microsoft JWT
output = boolean. True when it's known to be coming from Microsoft. False when it's not a valid AT

You, at the moment, be able to read that AT since it's a JWT is just a coincidence and you should tread the token as a binary blob you cannot read if you are not the resource.
@mahoekst

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!
image

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.

@jmprieur
Copy link
Contributor

@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:
https://github.com/azure-samples/active-directory-dotnet-webapi-manual-jwt-validation

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?

@raphaeljoie
Copy link

Hey @jmprieur thanks for the update :)
I'm not an ASP.NET expert and I have a hard time to read this example. Can you bring it to a higher level?

The web API does validate it

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

  • how to do it,
  • or how to make sure that nobody else gets confused after reading the doc.

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?

@hpsin
Copy link

hpsin commented Nov 17, 2020

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.

@raphaeljoie
Copy link

@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?

@hpsin
Copy link

hpsin commented Nov 17, 2020

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?)

@YEMEAC
Copy link

YEMEAC commented Jul 27, 2021

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 ... scopes:[my-scope].

After that you should get an access_token that passes the validation for example using https://jwt.davetonge.co.uk/ just paste it there

@bh3605
Copy link

bh3605 commented Oct 5, 2022

@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?

@alfonsrv
Copy link

alfonsrv commented Jan 27, 2024

But why does the https://login.microsoftonline.com/common/discovery/keys endpoint have to expose the same kids 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
Copy link

still I don't quite get why we cannot validate a Graph API token

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.

why does the https://login.microsoftonline.com/common/discovery/keys endpoint have to expose the same kids as referenced in the tokens used for Graph API? I feel like this just adds unnecessary confusion.

I agree.

@chandankgonu
Copy link

chandankgonu commented 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
Copy link

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.

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 neighbor id_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
Copy link
Contributor

jmprieur commented 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
Copy link

@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
Copy link

@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
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Customer reported Indicates issue was opened by customer Investigate We are not quite sure what the issue is.
Projects
None yet
Development

No branches or pull requests