Skip to content

Conversation

@jiasli
Copy link
Member

@jiasli jiasli commented Jun 24, 2025

Related command
az login

Description
#31778 added --claims-challenge to az login.

When a PUT or DELETE request is blocked by MFA policy with a 401 response, ARMChallengeAuthenticationPolicy will trigger silent re-authentication. If silent re-authentication fails, Azure CLI shows re-authentication message with --claims-challenge and base64-encoded value. Running this az login --claims-challenge xxx command will trigger the MFA process.

The JSON value of the claims challenge is base64-encoded to avoid quoting issue (#15529). Even though base64-encoded string may contain +/-_= characters, they will not be interpreted by shell.

Below is a test in PowerShell 7.5.2:

> az login --claims-challenge eyJhY2Nlc3NfdG9rZW4iOnsiYWNycyI6eyJlc3NlbnRpYWwiOnRydWUsInZhbHVlcyI6WyJwMSJdfX19+/-_= --debug
cli.knack.cli: Command arguments: ['login', '--claims-challenge', 'eyJhY2Nlc3NfdG9rZW4iOnsiYWNycyI6eyJlc3NlbnRpYWwiOnRydWUsInZhbHVlcyI6WyJwMSJdfX19+/-_=', '--debug']

and Bash:

$ az login --claims-challenge eyJhY2Nlc3NfdG9rZW4iOnsiYWNycyI6eyJlc3NlbnRpYWwiOnRydWUsInZhbHVlcyI6WyJwMSJdfX19+/-_= --debug
cli.knack.cli: Command arguments: ['login', '--claims-challenge', 'eyJhY2Nlc3NfdG9rZW4iOnsiYWNycyI6eyJlc3NlbnRpYWwiOnRydWUsInZhbHVlcyI6WyJwMSJdfX19+/-_=', '--debug']

so quoting the base64-encoded claims challenge is not necessary, but there could be unknown shells that do interpret these characters, so we quote it to follow the best practice.

Testing Guide

> az keyvault create -g testpolicy1 -n testkv
Run the command below to authenticate interactively; additional arguments may be added as needed:
az logout
az login --tenant "3f145493-536c-40aa-8a6d-ca91dd64cd3b" --scope "https://management.core.windows.net//.default" --claims-challenge "eyJhY2Nlc3NfdG9rZW4iOnsiYWNycyI6eyJlc3NlbnRpYWwiOnRydWUsInZhbHVlcyI6WyJwMSJdfX19"
(RequestDisallowedByPolicy) Resource 'testkv' was disallowed by policy. ...
Code: RequestDisallowedByPolicy
Message: Resource 'testkv' was disallowed by policy. ...
Target: testkv

History Notes

[Core] Provide actionable error recommendation when a command fails because of Multi-Factor Authentication (MFA) policy violation

@azure-client-tools-bot-prd
Copy link

azure-client-tools-bot-prd bot commented Jun 24, 2025

️✔️AzureCLI-FullTest
️✔️acr
️✔️latest
️✔️3.12
️✔️3.9
️✔️acs
️✔️latest
️✔️3.12
️✔️3.9
️✔️advisor
️✔️latest
️✔️3.12
️✔️3.9
️✔️ams
️✔️latest
️✔️3.12
️✔️3.9
️✔️apim
️✔️latest
️✔️3.12
️✔️3.9
️✔️appconfig
️✔️latest
️✔️3.12
️✔️3.9
️✔️appservice
️✔️latest
️✔️3.12
️✔️3.9
️✔️aro
️✔️latest
️✔️3.12
️✔️3.9
️✔️backup
️✔️latest
️✔️3.12
️✔️3.9
️✔️batch
️✔️latest
️✔️3.12
️✔️3.9
️✔️batchai
️✔️latest
️✔️3.12
️✔️3.9
️✔️billing
️✔️latest
️✔️3.12
️✔️3.9
️✔️botservice
️✔️latest
️✔️3.12
️✔️3.9
️✔️cdn
️✔️latest
️✔️3.12
️✔️3.9
️✔️cloud
️✔️latest
️✔️3.12
️✔️3.9
️✔️cognitiveservices
️✔️latest
️✔️3.12
️✔️3.9
️✔️compute_recommender
️✔️latest
️✔️3.12
️✔️3.9
️✔️computefleet
️✔️latest
️✔️3.12
️✔️3.9
️✔️config
️✔️latest
️✔️3.12
️✔️3.9
️✔️configure
️✔️latest
️✔️3.12
️✔️3.9
️✔️consumption
️✔️latest
️✔️3.12
️✔️3.9
️✔️container
️✔️latest
️✔️3.12
️✔️3.9
️✔️containerapp
️✔️latest
️✔️3.12
️✔️3.9
️✔️core
️✔️latest
️✔️3.12
️✔️3.9
️✔️cosmosdb
️✔️latest
️✔️3.12
️✔️3.9
️✔️databoxedge
️✔️latest
️✔️3.12
️✔️3.9
️✔️dls
️✔️latest
️✔️3.12
️✔️3.9
️✔️dms
️✔️latest
️✔️3.12
️✔️3.9
️✔️eventgrid
️✔️latest
️✔️3.12
️✔️3.9
️✔️eventhubs
️✔️latest
️✔️3.12
️✔️3.9
️✔️feedback
️✔️latest
️✔️3.12
️✔️3.9
️✔️find
️✔️latest
️✔️3.12
️✔️3.9
️✔️hdinsight
️✔️latest
️✔️3.12
️✔️3.9
️✔️identity
️✔️latest
️✔️3.12
️✔️3.9
️✔️iot
️✔️latest
️✔️3.12
️✔️3.9
️✔️keyvault
️✔️latest
️✔️3.12
️✔️3.9
️✔️lab
️✔️latest
️✔️3.12
️✔️3.9
️✔️managedservices
️✔️latest
️✔️3.12
️✔️3.9
️✔️maps
️✔️latest
️✔️3.12
️✔️3.9
️✔️marketplaceordering
️✔️latest
️✔️3.12
️✔️3.9
️✔️monitor
️✔️latest
️✔️3.12
️✔️3.9
️✔️mysql
️✔️latest
️✔️3.12
️✔️3.9
️✔️netappfiles
️✔️latest
️✔️3.12
️✔️3.9
️✔️network
️✔️latest
️✔️3.12
️✔️3.9
️✔️policyinsights
️✔️latest
️✔️3.12
️✔️3.9
️✔️privatedns
️✔️latest
️✔️3.12
️✔️3.9
️✔️profile
️✔️latest
️✔️3.12
️✔️3.9
️✔️rdbms
️✔️latest
️✔️3.12
️✔️3.9
️✔️redis
️✔️latest
️✔️3.12
️✔️3.9
️✔️relay
️✔️latest
️✔️3.12
️✔️3.9
️✔️resource
️✔️latest
️✔️3.12
️✔️3.9
️✔️role
️✔️latest
️✔️3.12
️✔️3.9
️✔️search
️✔️latest
️✔️3.12
️✔️3.9
️✔️security
️✔️latest
️✔️3.12
️✔️3.9
️✔️servicebus
️✔️latest
️✔️3.12
️✔️3.9
️✔️serviceconnector
️✔️latest
️✔️3.12
️✔️3.9
️✔️servicefabric
️✔️latest
️✔️3.12
️✔️3.9
️✔️signalr
️✔️latest
️✔️3.12
️✔️3.9
️✔️sql
️✔️latest
️✔️3.12
️✔️3.9
️✔️sqlvm
️✔️latest
️✔️3.12
️✔️3.9
️✔️storage
️✔️latest
️✔️3.12
️✔️3.9
️✔️synapse
️✔️latest
️✔️3.12
️✔️3.9
️✔️telemetry
️✔️latest
️✔️3.12
️✔️3.9
️✔️util
️✔️latest
️✔️3.12
️✔️3.9
️✔️vm
️✔️latest
️✔️3.12
️✔️3.9

@azure-client-tools-bot-prd
Copy link

azure-client-tools-bot-prd bot commented Jun 24, 2025

️✔️AzureCLI-BreakingChangeTest
️✔️Non Breaking Changes

@yonzhan
Copy link
Collaborator

yonzhan commented Jun 24, 2025

Support interactive re-authentication with claims challenge

@github-actions
Copy link

The git hooks are available for azure-cli and azure-cli-extensions repos. They could help you run required checks before creating the PR.

Please sync the latest code with latest dev branch (for azure-cli) or main branch (for azure-cli-extensions).
After that please run the following commands to enable git hooks:

pip install azdev --upgrade
azdev setup -c <your azure-cli repo path> -r <your azure-cli-extensions repo path>

@jiasli
Copy link
Member Author

jiasli commented Jun 24, 2025

An MFA error can be triggered with az keyvault create -g testpolicy1 -n kv06171 --debug:

cli.azure.cli.core.sdk.policies: Request URL: 'https://management.azure.com/subscriptions/9fb3fda4-e572-422a-a972-1011d3593176/resourceGroups/testpolicy1/providers/Microsoft.KeyVault/vaults/kv06171?api-version=2023-02-01'
cli.azure.cli.core.sdk.policies: Request method: 'PUT'
...

cli.azure.cli.core.sdk.policies: Response status: 401
cli.azure.cli.core.sdk.policies: Response headers:
...
cli.azure.cli.core.sdk.policies:     'WWW-Authenticate': 'Bearer realm="", authorization_uri="https://login.microsoftonline.com/common/oauth2/authorize", error="insufficient_claims", claims="eyJhY2Nlc3NfdG9rZW4iOnsiYWNycyI6eyJlc3NlbnRpYWwiOnRydWUsInZhbHVlcyI6WyJwMSJdfX19"'
...
cli.azure.cli.core.sdk.policies: Response content:
cli.azure.cli.core.sdk.policies: Body is streamable

The claims challenge eyJhY2Nlc3NfdG9rZW4iOnsiYWNycyI6eyJlc3NlbnRpYWwiOnRydWUsInZhbHVlcyI6WyJwMSJdfX19 decodes to {"access_token":{"acrs":{"essential":true,"values":["p1"]}}}.

Notice SDK doesn't load the response body at all and shows Body is streamable. However, the response body contains detailed information on the policy that rejected the request.

@jiasli jiasli force-pushed the claims_challenge branch from ae4bc8b to 9091fee Compare June 27, 2025 10:01
@jiasli jiasli marked this pull request as ready for review July 4, 2025 09:56
@jiasli jiasli changed the title [Core] Support interactive re-authentication with claims challenge {Auth} Add --claims-challenge to the re-authentication message Jul 10, 2025
else:
login_command = _generate_login_command(**kwargs)
recommendation = "Interactive authentication is needed. Please run:\n{}".format(login_command)
login_command = _generate_login_command(claims_challenge=claims_challenge, **kwargs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth replacing kwargs with tenant and scopes, given the limited number of arguments?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion. This (removing kwargs) is what I did in #31778.

@jiasli
Copy link
Member Author

jiasli commented Jul 14, 2025

We ask the user to do interactive re-authentication unconditionally, as explained below.

WAM flow's acquire_token_silent() can return InteractionRequired in case of error, because PyMsalRuntime has that concept in their API, but browser flow's acquire_token_silent() doesn't return InteractionRequired. (https://identitydivision.visualstudio.com/Engineering/_workitems/edit/3313444)

As discussed with @rayluo:

Historically, in the browser code path, we do not have - and do not need - InteractionRequired in acquire_token_silent(), because the expected action is always to call a non-silent API, typically the acquire_token_interactive(). In particular, even for some edge cases where interaction will not really get you a token, we still think an interaction can provide better error description in the User Experience (for example, the interaction can guide user to install Intune step by step.)

Therefore:

evelyn-ys
evelyn-ys previously approved these changes Jul 14, 2025
@jiasli jiasli force-pushed the claims_challenge branch from f2e60e9 to cff760a Compare July 15, 2025 08:13
@jiasli
Copy link
Member Author

jiasli commented Jul 15, 2025

The duplicated error message is given by Python SDK: Azure/azure-sdk-for-python#41937

return ' '.join(login_command)
# Explicit logout is preferred, making sure MSAL cache is purged:
# https://github.com/AzureAD/microsoft-authentication-library-for-python/issues/335
return 'az logout\n' + ' '.join(login_command)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We always ask the user to explicitly log out, in case some commands (such as az ad) don't support handling 401 challenge. See AzureAD/microsoft-authentication-library-for-python#335.

@jiasli jiasli merged commit 5c3cf2f into Azure:dev Jul 16, 2025
48 checks passed
@jiasli jiasli deleted the claims_challenge branch July 16, 2025 08:43
@jiasli
Copy link
Member Author

jiasli commented Aug 4, 2025

A screenshot of the example output:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants