microsoft-authentication-library-for-java icon indicating copy to clipboard operation
microsoft-authentication-library-for-java copied to clipboard

[Bug] Cannot call the OIDC endpoint with access token from the broker

Open marbon87 opened this issue 1 year ago • 19 comments
trafficstars

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

  1. An external component (KeyCloak) integrates with OIDC providers by making a call to the userinfo_endpoint, which it reads from the OIDC endpoint.
  2. I can get a WAM token for Graph, but I cannot call the endpoint (401). I am able to call when using a browser!

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

package org.example;

import com.microsoft.aad.msal4j.IAuthenticationResult;
import com.microsoft.aad.msal4j.MsalException;
import com.microsoft.aad.msal4j.PublicClientApplication;
import com.microsoft.aad.msal4j.SilentParameters;
import com.microsoft.aad.msal4jbrokers.Broker;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Set;

public class Example {

    private static final Set<String> scope = Set.of("user.read", "openid", "profile", "upn", "preferred_username");
    private static final String clientId = "my-client-id";

    public static void main(String args[]) throws Exception {
        Broker broker = new Broker.Builder()
                .supportWindows(true).build();

        PublicClientApplication pca = PublicClientApplication.builder(clientId)
                .broker(broker)
                .build();

        IAuthenticationResult result = acquireTokenIntegratedWindowsAuth(pca, scope);
        System.out.println("Account username:  " + result.account().username());
        System.out.println("Access token:      " + result.accessToken());
        System.out.println("Id token:          " + result.idToken());


        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://graph.microsoft.com/oidc/userinfo"))
                .header("Authorization", "Bearer " + result.accessToken())
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println("User-Info Status:              " + response.statusCode());
        System.out.println("User-Info Result:              " + response.body());

    }

    private static IAuthenticationResult acquireTokenIntegratedWindowsAuth(PublicClientApplication pca,
                                                                           Set<String> scopes) throws Exception {

        IAuthenticationResult result;
        try {
            SilentParameters silentParameters =
                    SilentParameters
                            .builder(scopes)
                            .tenant("<my-tenent>")
                            .forceRefresh(true)
                            .scopes(Set.of("https://graph.microsoft.com/.default"))
                            .build();
            result = pca.acquireTokenSilently(silentParameters).join();
        } catch (MsalException ex) {
            throw ex;
        }
        return result;
    }
}

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

marbon87 avatar Jul 05 '24 08:07 marbon87