Repository navigation
Description
Library version used
1.20.1
Java version
21.0.8
Scenario
PublicClient (AcquireTokenInteractive, AcquireTokenByUsernamePassword)
Is this a new or an existing app?
This is a new app or experiment
Issue description and reproduction steps
I'm working on an extension for VS Code that runs a Java backend server in headless mode. I'm planning on adding support for EntraID, and from what I understand that requires being able to open the default browser to authenticate. Since the backend server is running in headless mode (java.awt.headless=true), the browser fails to be launched on Windows, since the following method relies on java.awt.Desktop which is not available on headless mode:
AcquireTokenByInteractiveFlowSupplier class:
private static void openDefaultSystemBrowserInWindows(URL url){
try {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(url.toURI());
LOG.debug("Opened default system browser");
} else {
throw new MsalClientException("Unable to open default system browser",
AuthenticationErrorCode.DESKTOP_BROWSER_NOT_SUPPORTED);
}
} catch (URISyntaxException | IOException ex) {
throw new MsalClientException(ex);
}
}
On the other hand, when running on Mac, that platform's method doesn't rely on AWT, and instead relies on a native command, so launching the browser works without problems even in headless mode:
private static void openDefaultSystemBrowserInMac(URL url){
Runtime runtime = Runtime.getRuntime();
try {
// CodeQL [SM00680] False positive: this URL is validated earlier in the interactive flow
runtime.exec("open " + url);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Relevant code snippets
Relevant stacktrace:
Suppressed: com.microsoft.aad.msal4j.MsalClientException: Unable to open default system browser
at com.microsoft.aad.msal4j@1.20.1/com.microsoft.aad.msal4j.AcquireTokenByInteractiveFlowSupplier.openDefaultSystemBrowserInWindows(AcquireTokenByInteractiveFlowSupplier.java:155)
at com.microsoft.aad.msal4j@1.20.1/com.microsoft.aad.msal4j.AcquireTokenByInteractiveFlowSupplier.openDefaultSystemBrowser(AcquireTokenByInteractiveFlowSupplier.java:139)
at com.microsoft.aad.msal4j@1.20.1/com.microsoft.aad.msal4j.AcquireTokenByInteractiveFlowSupplier.getAuthorizationResult(AcquireTokenByInteractiveFlowSupplier.java:70)
at com.microsoft.aad.msal4j@1.20.1/com.microsoft.aad.msal4j.AcquireTokenByInteractiveFlowSupplier.execute(AcquireTokenByInteractiveFlowSupplier.java:46)
at com.microsoft.aad.msal4j@1.20.1/com.microsoft.aad.msal4j.AuthenticationResultSupplier.get(AuthenticationResultSupplier.java:69)
at com.microsoft.aad.msal4j@1.20.1/com.microsoft.aad.msal4j.AuthenticationResultSupplier.get(AuthenticationResultSupplier.java:18)
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
... 6 moreExpected behavior
To be able to launch the browser needed for authentication on Windows with headless mode, just like it can be done on Mac.
Identity provider
Microsoft Entra ID (Work and School accounts and Personal Microsoft accounts)
Regression
No response
Solution and workarounds
A suggestion would be to also use a native method on Windows, like "start".
Activity
Avery-Dunn commentedon Oct 16, 2025
Hello humbertogrobles : Could you describe your scenario a bit more? If it's running on a backend server, why would you need to use a flow that is meant for direct user interaction?
Public client flows are intended for apps that run on the client's device, if you have a backend server you'd probably want to use a confidential client flow: https://learn.microsoft.com/en-us/entra/identity-platform/msal-client-applications
Have a look at some of our confidential client/server-side samples, one of them might be better suited for what you're doing: https://github.com/Azure-Samples/ms-identity-msal-java-samples/tree/main/1-server-side
humbertogrobles commentedon Oct 16, 2025
Avery-Dunn thanks for the prompt response! Let me explain a bit more. In this VS Code extension we're currently using the JDBC drivers to connect to Oracle DBs. This is out in production now, and we're looking into adding support for EntraID by using the ojdbc extensions, in particular ojdbc-provider-azure:
https://github.com/oracle/ojdbc-extensions/blob/main/ojdbc-provider-azure/README.md
This extension uses MSAL4J as an internal dependency to do the authentication. The backend server we're using is launched to support the VS Code extension frontend and execute all the business logic, and all of this runs locally on the user's device.
Regarding the value I chose for the "Scenario" field, I didn't really know what to put there, so I chose what I thought was the correct value, but let me know if you need any more info to determine if that's the correct scenario or not.
Avery-Dunn commentedon Oct 16, 2025
For the scenario, I'd recommend you read up on that first link I pasted about public vs confidential client: https://learn.microsoft.com/en-us/entra/identity-platform/msal-client-applications
But in short, if your users need to enter their own individual credentials (for example, on a login screen) then it's a public client scenario, and if your application uses its own credentials for all your users' requests (for example, a certificate or managed identity) then it's confidential client.
However, just to clarify: you aren't using the
msal4jpackage directly, right? You're using the auth APIs in thatojdbc-provider-azurepackage, which usesmsal4junder the hood? If so, it may take a while to update: they seem they getmsal4jthrough theazure-identitypackage, so it'd be multiple layers of package updates.We can look into alternate browser behavior on our end, but I wouldn't even be able to give an ETA on when the investigation would start. In the meantime, it looks like that
ojdbc-provider-azurepackage has other options for the credentials, so maybe you can look into one of the non-browser options: https://github.com/oracle/ojdbc-extensions/blob/main/ojdbc-provider-azure/README.md#defaultazurecredentialhumbertogrobles commentedon Oct 16, 2025
Thanks for the information Avery-Dunn . I've read the document and I think that the Public Client Scenario is correct.
Regarding the usage of MSAL4J, you're correct, we're not using it directly, we use the ojdbc drivers, which dynamically load any providers present in the classpath (in this case ojbc-provider-azure) which then internally uses msal4j. Thanks for looking into this, I understand it may take time to solve and for the fix to reach all the way down the pipeline, and in the meantime will look into the other options you mentioned.