Open marbon87 opened 4 months ago
Hello @marbon87 : Just to clarify a couple of things:
"sub"
claim that matches what is in the "xms_st"
claim of the access token. Is the "sub"
in the working ID token the same as the "sub"
in ID token you get from MSAL? (and the access token from MSAL is just missing "xms_st"
)After some testing I'm having trouble reproducing your exact issue, my tokens either correctly have that "xms_st"
claim or I run into a different issue before getting the token.
However, my initial thought is that by default we will set the authority to https://login.microsoftonline.com/common/
, and I noticed that your working URL has https://login.microsoftonline.com/my-tenant/
. So, you may need to specify an authority in your PublicClientApplication
such as https://login.microsoftonline.com/your-tenant-id/
in order for the access token to be created with the right ID token info.
- When you say that you can get working tokens in the browser you mean you're getting them from that URL manually, right? Not from MSAL's interactive/browser-based flow?
Correct.
- For the working tokens, I assume the ID token has a
"sub"
claim that matches what is in the"xms_st"
claim of the access token.
Correct.
- Is the
"sub"
in the working ID token the same as the"sub"
in ID token you get from MSAL? (and the access token from MSAL is just missing"xms_st"
)
Correct: Both id tokens have the same sub-claim, starting with -qr...
. This value is equal to the xms_st.sub-Claim in the working acsess-token.
The sub-claim of the workin access-token matches the sub-claim from MSAL. The MSAL-access-token totally misses the xms_st.sub-Claim.
After some testing I'm having trouble reproducing your exact issue, my tokens either correctly have that
"xms_st"
claim or I run into a different issue before getting the token.However, my initial thought is that by default we will set the authority to
https://login.microsoftonline.com/common/
, and I noticed that your working URL hashttps://login.microsoftonline.com/my-tenant/
. So, you may need to specify an authority in yourPublicClientApplication
such ashttps://login.microsoftonline.com/your-tenant-id/
in order for the access token to be created with the right ID token info.
I set the authority but get the same error:
PublicClientApplication pca = PublicClientApplication.builder(clientId)
.broker(broker)
.authority("https://login.microsoftonline.com/tenant-id")
.build();
Can you clarify if you are using the Id Token or the access token?
The broker uses Entra's v1 endpoint, and so Id Tokens will be v1, which are somewhat different than the v2 endpoint Id Tokens (which you are using). Access tokens however should be the same, they are determined by the resource (Graph).
Hi @bgavrilMS , i am using only access tokens to call the userinfo endpoint as shown in the example above.
Is https://graph.microsoft.com/.default the correct URI for the userinfo endpoint?
If i try https://login.microsoftonline.com/tenant-idopenid/userinfo i also get a 400 reponse with WWW-Authenticate-Header:
Bearer correlation_id="..........", error="invalid_request", error_codes="[9001014]", error_description="AADSTS9001014: This token was not issued for the UserInfo endpoint. This may have been a token for Graph or another resource. Trace ID: f7b3c682-7356-4cc7-a42f-3fc9d7bd5e00 Correlation ID: 49f31763-c0ff-4dab-8e88-32dd1725dcfb Timestamp: 2024-07-09 08:16:49Z", error_uri="https://login.microsoftonline.com/error?code=9001014", timestamp="2024-07-09 08:16:49Z", trace_id="f7b3c682-7356-4cc7-a42f-3fc9d7bd5e00"
Hi @bgavrilMS , do you have any updates on this?
The userinfo endpoint is part of the OIDC document, which all IdP are required to publish. You can find Entra's here:
https://login.microsoftonline.com/common/.well-known/openid-configuration
I can imagine that KeyCloak will try to find the userinfo endpoint by looking at the iss
claim from the AAD token and adding /.well-known to it.
Let me try this out on a personal tenant...
@marbon87 - let me see if I understand correctly: who calls the userinfo endpoint ? KeyCloak or your app?
I wasn't able to get a token for the user endpoint, Entra keeps giving me a token with Graph scopes. And the user endpoint refuses it - with error error_description="AADSTS9001014: This token was not issued for the UserInfo endpoint. This may have been a token for Graph or another resource."
Is this what you are getting? (the error message is part of the 400)
@marbon87 - let me see if I understand correctly: who calls the userinfo endpoint ? KeyCloak or your app?
Keycloak calls the userinfo enpdoint.
I wasn't able to get a token for the user endpoint, Entra keeps giving me a token with Graph scopes. And the user endpoint refuses it - with error error_description="AADSTS9001014: This token was not issued for the UserInfo endpoint. This may have been a token for Graph or another resource."
Is this what you are getting? (the error message is part of the 400)
Exactly.
Ah ok, I think I figured it out. Entra has v1 and v2 endpoints. The OIDC document for v2 is here (notice the v2.0 segment)
https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
And so the userinfo endpoint is:
The userinfo is indeed hosted by Graph, but this is an implementation detail.
The key point here is that when you configure federation between KeyCloak and Entra, you must tell KeyCloak to use the v2 endpoints of AAD. So the authority from KeyCloak's perspective is https://login.microsoftonline.com/common/v2.0/
. MSAL libraries "abstract" this away and will add "v2.0" on their own.
HTH
Sorry, but this is also not working. If i call https://graph.microsoft.com/oidc/userinfo manually (with curl) with the access-token from MSAL4j i get the following error:
{"error":{"code":"UnknownError","message":"Token must contain sub claim.","innerError":{"date":"2024-08-26T12:32:37","request-id":"2047b161-fcf0-4fe1-ad7d-55eb8deafac6"
How does your token look like? (make sure to hide any PII like name etc) Here's mine from https://jwt.ms
I sent it to you by email. Could you share your java code to get the token? Mine is above.
Thanks I got it. I think it's a broker issue.
I am able to get a response if I use the browser to authenticate, but I get the Token must contain sub claim
error if I use the broker. Obvs the token contains the sub claim (it's mandatory per OIDC).
Here's my C# code that repros the issue.
internal class Program
{
private const string ClientId = "3bee2617-ab99-4ba5-b390-be397057344f";
//private const string TenantId = "839846c0-9cef-4455-9542-0c36d831d026";
private const string TenantId = "organizations";
private static readonly Uri AuthorityUri = new Uri($"https://login.microsoftonline.com/{TenantId}");
private static readonly Uri RedirectUrl = new Uri("http://localhost");
private static readonly string[] Scopes = new[] { "User.Read" };
private static bool s_useBroker = true;
private static async Task Main(string[] args)
{
[DllImport("user32.dll")]
static extern nint GetForegroundWindow();
var brokerOptions = s_useBroker ?
new BrokerOptions(BrokerOptions.OperatingSystems.Windows) :
new BrokerOptions(BrokerOptions.OperatingSystems.None);
var pca = PublicClientApplicationBuilder
.Create(ClientId)
.WithAuthority(AuthorityUri)
.WithRedirectUri(RedirectUrl.ToString())
.WithParentActivityOrWindow(() => GetForegroundWindow())
.WithBroker(brokerOptions)
.Build();
var result = await pca.AcquireTokenInteractive(Scopes)
.WithPrompt(Prompt.SelectAccount)
.ExecuteAsync();
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(result.TokenType, result.AccessToken);
var response2 = await client.GetAsync("https://graph.microsoft.com/oidc/userinfo"); // OIDC - fails with broker, works with browser
var stringResponse2 = await response2.Content.ReadAsStringAsync();
Console.Write(stringResponse2);
var response3 = await client.GetAsync("https://graph.microsoft.com/v1.0/me"); // works with broker and with browser
var stringResponse3 = await response3.Content.ReadAsStringAsync();
Console.Write(stringResponse3);
}
}
That the token from the browser is working is mentioned in my first post. Browser is not an option, that's why i wanted to use MSAL4j. Furthermore i do not have any knowledge in .NET.
Do you have a dedicated contact or business support for this kind of issue? We are actually paying a lot for MS Entra...
Yes, please do escalate this issue via Azure support and via your account manager to get more attention to it.
CC @localden and @ashok672
I'm editing the issue to make it clear, as it's a pretty long thread.
@marbon87 - can you convince KeyCloack to call https://graph.microsoft.com/v1.0/me
instead of the userinfo endpoint? I think they are similar.
https://graph.microsoft.com/v1.0/me does not work either because the response is missing, especiall the sub-claim is missing in the response.
This is a known, recently discovered defect, in eSTS implementation of the protocol used by Windows broker to issue v2 tokens.
We don't have a concrete timeline, but the plan is for eSTS to address this next quarter.
https://graph.microsoft.com/v1.0/me seems to be working now. Is this uri expected to be used for userinfo?
Library version used
1.16.0
Java version
21
Is this a new or an existing app?
This is a new app or experiment
Summary of the issue
userinfo_endpoint
, which it reads from the OIDC endpoint.OIDC endpoint: https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration UserInfo endpoint: https://graph.microsoft.com/oidc/userinfo Scope requested: User.Read
See a simple repo (in C#) in https://github.com/AzureAD/microsoft-authentication-library-for-java/issues/835#issuecomment-2310442115
Note that I can call
https://graph.microsoft.com/v1.0/me
endpoint with the WAM token.Issue description and reproduction steps
We are using keycloak as an internal idp and want to use the external to internal token exchange feature.
Therefor i acquire a token silently with MSAL4j and post the access token to keycloak. The problem is that keycloak call the MS Graph userinfo-Endpoint but get's the error: "Token must contain sub claim."
When i acquire an access token by calling the following uri in the browser and use the access-token from the redirect, the token exchange is working:
https://login.microsoftonline.com/my-tenant/oauth2/v2.0/authorize?client_id=my-client-id&response_type=token+id_token&redirect_uri=https://localhost&scope=user.read+openid+profile+email&response_mode=fragment&state=12345&nonce=678910
I compared the two access tokens from MSAL4j and in the browser and guess that the problem in the MSAL4j-access token is the missing xms_st.sub-Claim in the access token.
What do i have to configure, to get that scope in the access token from MSAL4j?
Relevant code snippets
Expected behavior
MS Graph API Userinfo-Endpoint should respond with status code 200.
Identity provider
Microsoft Entra ID (Work and School accounts and Personal Microsoft accounts)
Regression
No response
Solution and workarounds
No response