Liu He hi & thanks for join me here at Q&A portal,
AzureCLI@2 task bug with the exposed $idToken, not with Azure login itself. The task login can succeed while the environment variable keeps returning a stale OIDC token. Do not reuse $idToken from addSpnToEnvironment for downstream token exchange until Microsoft fixes the task behavior.
AzureCLI@2 docs say addSpnToEnvironment: true exposes servicePrincipalId, tenantId, and either servicePrincipalKey or idToken to the script environment. https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/azure-cli-v2?view=azure-pipelines
Your repro is strong because the task authenticates successfully, but the decoded $idToken keeps the old nbf and exp. That means Azure DevOps is likely caching the token exported to the script, while the task internally gets a fresh token for its own az login flow.
dont pass $idToken to later steps as client_assertion. Request a fresh OIDC token inside the step that needs it, or keep the downstream token exchange inside the same AzureCLI@2 step immediately after login. If u are using Terraform, use the newer OIDC refresh variables flow instead of manually passing a cached assertion. Microsoft describes the refresh approach https://devblogs.microsoft.com/devops/introducing-azure-devops-id-token-refresh-and-terraform-task-version-5/
Open a Developer Community issue or Azure DevOps support ticket with the exact repro, task version, agent OS, hosted vs self-hosted agent, service connection ID, and decoded token nbf/exp values from multiple runs. https://developercommunity.visualstudio.com/t/Azure-DevOps-Pipelines-%E2%80%94-AzureCLI2-OIDC/11079123
This is not Entra rejecting a valid token randomly. Entra is correct: the assertion is expired. The bug is that the pipeline keeps handing u the old assertion.
rgds,
Alex
&
If my answer was helpful pls mark it and additional thx if u follow me at Q&A portal