Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sdk/identity/azure-identity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
### Bugs Fixed

### Other Changes
- Removed unused jetty, redisson, and lettuce-core dependencies.
- Improved `AzureDeveloperCliCredential` error handling to extract meaningful messages from azd auth token JSON output, providing cleaner error messages to users.

## 1.19.0-beta.1 (2025-11-14)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -746,17 +746,14 @@ AccessToken getTokenFromAzureDeveloperCLIAuthentication(StringBuilder azdCommand

if (redactedOutput.contains("azd auth login") || redactedOutput.contains("not logged in")) {
if (azdCommand.toString().contains("claims")) {
String userFriendlyError = extractUserFriendlyErrorFromAzdOutput(redactedOutput);
if (userFriendlyError != null) {
throw LOGGER
.logExceptionAsError(new ClientAuthenticationException(userFriendlyError, null));
}
throw LOGGER.logExceptionAsError(
new ClientAuthenticationException(getAzdErrorMessage(redactedOutput), null));
}
throw LoggingUtil.logCredentialUnavailableException(LOGGER, options,
new CredentialUnavailableException("AzureDeveloperCliCredential authentication unavailable."
+ " Please run 'azd auth login' to set up account."));
new CredentialUnavailableException(getAzdErrorMessage(redactedOutput)));
}
throw LOGGER.logExceptionAsError(new ClientAuthenticationException(redactedOutput, null));
throw LOGGER.logExceptionAsError(
new ClientAuthenticationException(getAzdErrorMessage(redactedOutput), null));
} else {
throw LOGGER.logExceptionAsError(
new ClientAuthenticationException("Failed to invoke Azure Developer CLI ", null));
Expand Down Expand Up @@ -871,6 +868,12 @@ String extractUserFriendlyErrorFromAzdOutput(String output) {
return redactInfo(messages.get(0));
}

// Gets a user-friendly error message from azd output, with fallback to the raw output
String getAzdErrorMessage(String output) {
String extracted = extractUserFriendlyErrorFromAzdOutput(output);
return extracted != null ? extracted : output;
}

AccessToken authenticateWithExchangeTokenHelper(TokenRequestContext request, String assertionToken)
throws IOException {
String authorityUrl = TRAILING_FORWARD_SLASHES.matcher(options.getAuthorityHost()).replaceAll("") + "/"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,33 @@ public void testMixedValidAndInvalidJson() {
assertEquals("Suggestion: Final message", result);
}

@Test
public void testGetAzdErrorMessageReturnsExtractedMessage() {
// Should return extracted user-friendly message when available
String output = "{\"data\":{\"message\":\"run azd auth login\"}}";
IdentityClient client = new IdentityClientBuilder().clientId("dummy").build();
String result = client.getAzdErrorMessage(output);
assertEquals("run azd auth login", result);
}

@Test
public void testGetAzdErrorMessageFallsBackForNoValidMessages() {
// Should return the raw input when extractUserFriendlyErrorFromAzdOutput returns null
String output = "{\"data\":{\"notamessage\":\"Not a message\"}}\n" + "This is not JSON";
IdentityClient client = new IdentityClientBuilder().clientId("dummy").build();
String result = client.getAzdErrorMessage(output);
assertEquals(output, result);
}

@Test
public void testGetAzdErrorMessageFallsBackForWhitespaceOnlyInput() {
// Should return the whitespace string when extraction returns null
String output = " \n\n \t ";
IdentityClient client = new IdentityClientBuilder().clientId("dummy").build();
String result = client.getAzdErrorMessage(output);
assertEquals(output, result);
}

@Test
public void testManagedCredentialSkipsImdsProbing() {
String accessToken = "token";
Expand Down