-
Notifications
You must be signed in to change notification settings - Fork 264
Add azd auth status command
#6377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: kristenwomack <[email protected]>
Co-authored-by: kristenwomack <[email protected]>
azd auth status command
wbreza
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love the idea - just have some open questions about the flags.
@copilot - Please review token caching and if we support multiple tokens with different tenants/scopes.
cli/azd/cmd/auth_status.go
Outdated
| tenantID string | ||
| scopes []string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to expose these flags on azd auth status? Could the user even have a different status in one tenant vs another? As far as I'm aware we only keep the auth tokens for the most recent auth login.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're correct - removed the tenant-id and scope flags in commit bb9541f. The auth system stores a single current user credential, and these flags don't make sense for a status command. The command now checks whatever the user is currently logged in with using the default login scopes.
| var msg string | ||
| switch res.Status { | ||
| case contracts.LoginStatusSuccess: | ||
| msg = "Logged in to Azure" | ||
| case contracts.LoginStatusUnauthenticated: | ||
| msg = "Not logged in, run `azd auth login` to login to Azure" | ||
| default: | ||
| panic("Unhandled login status") | ||
| } | ||
|
|
||
| // get user account information | ||
| details, err := a.authManager.LogInDetails(ctx) | ||
|
|
||
| // error getting user account or not logged in | ||
| if err != nil { | ||
| log.Printf("error: getting signed in account: %v", err) | ||
| fmt.Fprintln(a.console.Handles().Stdout, msg) | ||
| return nil, nil | ||
| } | ||
|
|
||
| // only print the message if the user is logged in | ||
| a.console.MessageUxItem(ctx, &ux.LoggedIn{ | ||
| LoggedInAs: details.Account, | ||
| LoginType: ux.LoginType(details.LoginType), | ||
| }) | ||
| return nil, nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should consider outputting the expiration date/time of the current token.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added credential expiration to text output in commit bb9541f. The expiration was already in the JSON output, now it's also shown in the text format:
Logged in to Azure as [email protected]
Credential expires on: 2024-01-15 10:30:45 UTC
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, we should!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot ^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added credential expiration to azd auth login --check-status in commit bec39dc for consistency. Both commands now display the expiration time in the same format:
Logged in to Azure as [email protected]
Credential expires on: 2025-12-15 21:41:56 UTC
…text output Addresses review feedback: - Removed tenant-id and scope flags as they don't make sense for status checking - The command now checks the current user's credentials without allowing tenant/scope overrides - Added credential expiration time to text output (already present in JSON) - Simplified the implementation to always use default login scopes Co-authored-by: wbreza <[email protected]>
Reviewed the auth system in commit bb9541f. The system stores a single "current user" credential (not multiple tokens). When Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
For consistency with azd auth status, the --check-status flag now also displays the credential expiration time in the text output format. Co-authored-by: JeffreyCA <[email protected]>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds a new azd auth status command to provide a more intuitive way to check authentication status, replacing the previously required azd auth login --check-status flag. The implementation maintains backward compatibility while improving user experience by following CLI conventions used by tools like the GitHub CLI.
Key Changes
- New dedicated
azd auth statuscommand with support for both text and JSON output formats - Enhanced credential expiration display in both
azd auth statusandazd auth login --check-status - Updated command autocomplete and help documentation
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
cli/azd/cmd/auth_status.go |
New command implementation with authentication status checking, credential verification, and output formatting |
cli/azd/cmd/auth.go |
Registers the new status subcommand under the auth command group with JSON and text output format support |
cli/azd/cmd/auth_login.go |
Updates --check-status flag behavior to display credential expiration time for consistency |
cli/azd/cmd/testdata/TestUsage-azd-auth.snap |
Adds status subcommand to auth command help output |
cli/azd/cmd/testdata/TestUsage-azd-auth-status.snap |
New snapshot test for auth status command help text |
cli/azd/cmd/testdata/TestFigSpec.ts |
Updates Fig autocomplete specification to include the new status subcommand |
| func (a *authStatusAction) Run(ctx context.Context) (*actions.ActionResult, error) { | ||
| scopes := a.authManager.LoginScopes() | ||
|
|
||
| // In check status mode, we always print the final status to stdout. | ||
| // We print any non-setup related errors to stderr. | ||
| // We always return a zero exit code. | ||
| token, err := a.verifyLoggedIn(ctx, scopes) | ||
| var loginExpiryError *auth.ReLoginRequiredError | ||
| if err != nil && | ||
| !errors.Is(err, auth.ErrNoCurrentUser) && | ||
| !errors.As(err, &loginExpiryError) { | ||
| fmt.Fprintln(a.console.Handles().Stderr, err.Error()) | ||
| } | ||
|
|
||
| res := contracts.LoginResult{} | ||
| if err != nil { | ||
| res.Status = contracts.LoginStatusUnauthenticated | ||
| } else { | ||
| res.Status = contracts.LoginStatusSuccess | ||
| res.ExpiresOn = &token.ExpiresOn | ||
| } | ||
|
|
||
| if a.formatter.Kind() != output.NoneFormat { | ||
| return nil, a.formatter.Format(res, a.writer, nil) | ||
| } else { | ||
| var msg string | ||
| switch res.Status { | ||
| case contracts.LoginStatusSuccess: | ||
| msg = "Logged in to Azure" | ||
| case contracts.LoginStatusUnauthenticated: | ||
| msg = "Not logged in, run `azd auth login` to login to Azure" | ||
| default: | ||
| panic("Unhandled login status") | ||
| } | ||
|
|
||
| // get user account information | ||
| details, err := a.authManager.LogInDetails(ctx) | ||
|
|
||
| // error getting user account or not logged in | ||
| if err != nil { | ||
| log.Printf("error: getting signed in account: %v", err) | ||
| fmt.Fprintln(a.console.Handles().Stdout, msg) | ||
| return nil, nil | ||
| } | ||
|
|
||
| // only print the message if the user is logged in | ||
| a.console.MessageUxItem(ctx, &ux.LoggedIn{ | ||
| LoggedInAs: details.Account, | ||
| LoginType: ux.LoginType(details.LoginType), | ||
| }) | ||
|
|
||
| // Display token expiration information | ||
| if res.ExpiresOn != nil { | ||
| expiryMsg := fmt.Sprintf( | ||
| "\nCredential expires on: %s", | ||
| res.ExpiresOn.Format("2006-01-02 15:04:05 MST")) | ||
| a.console.Message(ctx, expiryMsg) | ||
| } | ||
|
|
||
| return nil, nil | ||
| } |
Copilot
AI
Dec 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This entire status-checking logic block (lines 72-132) is duplicated from auth_login.go lines 305-363. The code is nearly identical except for the verifyLoggedIn method signature. This violates the DRY principle mentioned in the PR instructions.
Consider extracting the common status-checking logic into a shared helper function that both auth_login.go (--check-status flag) and auth_status.go can use. This would:
- Reduce maintenance burden when the logic needs to change
- Ensure consistency between both commands
- Make the codebase easier to maintain
The helper function could accept the necessary parameters (formatter, writer, console, authManager, token, err) and handle the status display logic.
| func (a *authStatusAction) Run(ctx context.Context) (*actions.ActionResult, error) { | ||
| scopes := a.authManager.LoginScopes() | ||
|
|
||
| // In check status mode, we always print the final status to stdout. | ||
| // We print any non-setup related errors to stderr. | ||
| // We always return a zero exit code. | ||
| token, err := a.verifyLoggedIn(ctx, scopes) | ||
| var loginExpiryError *auth.ReLoginRequiredError | ||
| if err != nil && | ||
| !errors.Is(err, auth.ErrNoCurrentUser) && | ||
| !errors.As(err, &loginExpiryError) { | ||
| fmt.Fprintln(a.console.Handles().Stderr, err.Error()) | ||
| } | ||
|
|
||
| res := contracts.LoginResult{} | ||
| if err != nil { | ||
| res.Status = contracts.LoginStatusUnauthenticated | ||
| } else { | ||
| res.Status = contracts.LoginStatusSuccess | ||
| res.ExpiresOn = &token.ExpiresOn | ||
| } | ||
|
|
||
| if a.formatter.Kind() != output.NoneFormat { | ||
| return nil, a.formatter.Format(res, a.writer, nil) | ||
| } else { | ||
| var msg string | ||
| switch res.Status { | ||
| case contracts.LoginStatusSuccess: | ||
| msg = "Logged in to Azure" | ||
| case contracts.LoginStatusUnauthenticated: | ||
| msg = "Not logged in, run `azd auth login` to login to Azure" | ||
| default: | ||
| panic("Unhandled login status") | ||
| } | ||
|
|
||
| // get user account information | ||
| details, err := a.authManager.LogInDetails(ctx) | ||
|
|
||
| // error getting user account or not logged in | ||
| if err != nil { | ||
| log.Printf("error: getting signed in account: %v", err) | ||
| fmt.Fprintln(a.console.Handles().Stdout, msg) | ||
| return nil, nil | ||
| } | ||
|
|
||
| // only print the message if the user is logged in | ||
| a.console.MessageUxItem(ctx, &ux.LoggedIn{ | ||
| LoggedInAs: details.Account, | ||
| LoginType: ux.LoginType(details.LoginType), | ||
| }) | ||
|
|
||
| // Display token expiration information | ||
| if res.ExpiresOn != nil { | ||
| expiryMsg := fmt.Sprintf( | ||
| "\nCredential expires on: %s", | ||
| res.ExpiresOn.Format("2006-01-02 15:04:05 MST")) | ||
| a.console.Message(ctx, expiryMsg) | ||
| } | ||
|
|
||
| return nil, nil | ||
| } | ||
| } | ||
|
|
||
| // Verifies that the user has credentials stored, | ||
| // and that the credentials stored is accepted by the identity server (can be exchanged for access token). | ||
| func (a *authStatusAction) verifyLoggedIn(ctx context.Context, scopes []string) (*azcore.AccessToken, error) { | ||
| cred, err := a.authManager.CredentialForCurrentUser(ctx, nil) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| // Ensure credential is valid, and can be exchanged for an access token | ||
| token, err := cred.GetToken(ctx, policy.TokenRequestOptions{ | ||
| Scopes: scopes, | ||
| }) | ||
|
|
||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return &token, nil | ||
| } |
Copilot
AI
Dec 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new auth_status command lacks unit tests. Similar commands in the same directory have comprehensive test coverage. For example, auth_token_test.go has 367 lines of tests covering various scenarios including success cases, error cases, and different input combinations.
At minimum, tests should cover:
- Authenticated user scenario (status success with expiration)
- Unauthenticated user scenario (status unauthenticated)
- JSON output format validation
- Text output format validation
- Error scenarios (e.g., ReLoginRequiredError, ErrNoCurrentUser)
| // In check status mode, we always print the final status to stdout. | ||
| // We print any non-setup related errors to stderr. | ||
| // We always return a zero exit code. |
Copilot
AI
Dec 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment "In check status mode, we always print the final status to stdout" appears to be copied from auth_login.go where it makes sense in the context of the --check-status flag. However, for the dedicated auth_status command, this comment is slightly misleading since the command is always in "status mode" - there's no mode switching.
Consider updating the comment to better reflect that this is the primary behavior of the status command, for example: "The status command always prints the final status to stdout and returns a zero exit code. Any non-setup related errors are printed to stderr."

Users had to discover
azd auth login --check-statusto check authentication status, which is unintuitive compared to CLIs likeghthat useauth statussubcommands.Changes
azd auth statuschecks authentication status and displays user information--output jsonfor structured outputsuccessorunauthenticatedwith expiration timeazd auth login --check-statuscontinues to work unchangedazd auth statusUsage
Implementation
Created
auth_status.gowith dedicated command registration in the auth command group. The command checks the current user's authentication status using default login scopes, without allowing tenant or scope overrides (since azd stores only one current user credential at a time). Both text and JSON output formats now include credential expiration information. Updatedazd auth login --check-statusto display the same credential expiration information for consistency.Original prompt
azd auth status#2898💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.