The atmos auth logout command provides secure, comprehensive cleanup of locally cached authentication credentials and session data. It removes credentials from both the system keyring and provider-specific file storage (e.g., AWS credential files), ensuring a clean logout experience while maintaining security best practices.
- No Logout Mechanism: Users cannot remove cached credentials without manually deleting files and keyring entries
- Security Concerns: Stale credentials may remain in the keyring and on disk after authentication expires
- Developer Experience: No clear way to switch between identities or clear authentication state
- Compliance Requirements: Organizations need audit trails showing when users logged out of systems
- Session Management: Browser sessions remain active even after local credential cleanup
- Credential Cleanup: 100% removal of all cached credentials for logged-out identities
- Security: Zero false positives (never delete credentials for identities not specified)
- User Experience: Clear, informative output showing what was removed
- Error Resilience: Best-effort cleanup continues even if individual steps fail
- Description: Remove credentials for a specific identity
- Acceptance Criteria:
- Accept identity name as argument:
atmos auth logout <identity> - Build complete authentication chain for the identity
- Remove keyring entries for all identities in the chain
- Remove provider-specific files (AWS:
~/.aws/atmos/<provider>/) - Display list of removed identities
- Handle missing credentials gracefully (treat as already logged out)
- Accept identity name as argument:
- Priority: P0 (Must Have)
- Description: Remove all credentials for a specific provider
- Acceptance Criteria:
- Support
--provider <name>flag - Remove all credentials associated with the provider
- Clean up provider-specific file storage
- Display confirmation of removed provider data
- Support AWS as initial provider implementation
- Support
- Priority: P0 (Must Have)
- Description: Prompt user when no identity/provider specified
- Acceptance Criteria:
- List all available identities from configuration
- Use Charmbracelet Huh for styled selection
- Allow "All identities" option
- Apply Atmos theme to prompts
- Exit gracefully on Ctrl+C
- Priority: P0 (Must Have)
- Description: Remove all credential storage locations
- Acceptance Criteria:
- Delete entries from system keyring using
go-keyring - Remove AWS credential files:
<base_path>/<provider>/credentials - Remove AWS config files:
<base_path>/<provider>/config - Support configurable base path via
spec.files.base_path(default:~/.aws/atmos) - Remove empty provider directories after cleanup
- Use native Go file operations (
os.RemoveAll, not shell commands) - Continue cleanup even if individual steps fail
- Delete entries from system keyring using
- Priority: P0 (Must Have)
- Description: Inform users about logout scope and limitations
- Acceptance Criteria:
- Display which identities were logged out
- Show file paths that were removed
- Clarify that browser sessions are NOT affected
- Provide summary of cleanup actions
- Use Charmbracelet styling for output
- Priority: P0 (Must Have)
- Description: Best-effort cleanup continues despite errors
- Acceptance Criteria:
- Continue cleanup if keyring deletion fails
- Continue cleanup if file deletion fails
- Collect and report all errors at end
- Exit with error code only if zero cleanup succeeded
- Log detailed error information for debugging
- Priority: P0 (Must Have)
- Never delete unrelated credentials
- Validate identity/provider names before deletion
- Log all deletion operations for audit trail
- Ensure proper permissions on remaining files
- Logout operation completes in <1 second for single identity
- Minimal memory overhead (no credential loading into memory)
- Efficient file system operations (batch deletions where possible)
- Works on macOS, Linux, and Windows
- Uses Go's standard library for file operations
- Leverages
go-keyringfor cross-platform keyring access - Handles platform-specific path separators correctly
- Unit tests for each logout component
- Integration tests for full logout flow
- Mock keyring for testing without system dependencies
- Mock file system for testing file cleanup
# Logout from specific identity
atmos auth logout <identity>
# Logout from specific provider
atmos auth logout --provider <provider-name>
# Interactive prompt (no arguments)
atmos auth logout
# Help
atmos auth logout --helpWhen run without arguments:
? Choose what to logout from:
❯ Identity: dev-admin
Identity: prod-admin
Identity: dev-readonly
Provider: aws-sso (removes all identities)
All identities (complete logout)
$ atmos auth logout dev-admin
Logging out from identity: dev-admin
Building authentication chain...
✓ Chain: aws-sso → dev-org-admin → dev-admin
Removing credentials...
✓ Keyring: aws-sso
✓ Keyring: dev-org-admin
✓ Keyring: dev-admin
✓ Files: ~/.aws/atmos/aws-sso/
Successfully logged out from 3 identities
⚠️ Note: This only removes local credentials. Your browser session
may still be active. Visit your identity provider to end your
browser session.$ atmos auth logout --provider aws-sso
Logging out from provider: aws-sso
Removing all credentials for provider...
✓ Keyring: aws-sso
✓ Keyring: dev-org-admin (via aws-sso)
✓ Keyring: dev-admin (via aws-sso)
✓ Keyring: prod-admin (via aws-sso)
✓ Files: ~/.aws/atmos/aws-sso/
Successfully logged out from 4 identities
⚠️ Note: This only removes local credentials.$ atmos auth logout dev-admin
Logging out from identity: dev-admin
Building authentication chain...
✓ Chain: aws-sso → dev-admin
Removing credentials...
✓ Keyring: aws-sso
✗ Keyring: dev-admin (not found - already logged out)
✓ Files: ~/.aws/atmos/aws-sso/
Logged out with warnings (2/3 successful)
Errors encountered:
• dev-admin: credential not found in keyring$ atmos auth logout dev-admin
Identity 'dev-admin' is already logged out.
No credentials found in keyring or file storage.$ atmos auth logout nonexistent
Error: identity "nonexistent" not found in configuration
Available identities:
• dev-admin
• prod-admin
• dev-readonly
Run 'atmos auth logout' without arguments for interactive selection.$ atmos auth logout --provider nonexistent
Error: provider "nonexistent" not found in configuration
Available providers:
• aws-sso
• github-oidc
Run 'atmos auth logout' without arguments for interactive selection.AWS providers support configurable file storage paths via spec.files.base_path:
# atmos.yaml
auth:
providers:
aws-sso:
kind: aws/iam-identity-center
start_url: https://example.awsapps.com/start
region: us-east-1
spec:
files:
base_path: ~/.custom/aws/credentials # Optional, defaults to ~/.aws/atmosConfiguration Precedence:
spec.files.base_pathin provider configuration- Default:
~/.aws/atmos
Validation:
- Path must not be empty or whitespace-only
- Path must not contain null bytes, carriage returns, or newlines
- Tilde (
~) expansion is supported viago-homedir - Validation occurs during
atmos auth validate
Use Cases:
- Custom Directories: Store credentials in non-standard locations
- Container Environments: Use volume mounts at custom paths
- Multi-User Systems: Isolate credentials per user/project
// pkg/auth/types/interfaces.go
type Provider interface {
// ... existing methods
// Logout removes provider-specific credential storage.
// Returns error only if cleanup fails for critical resources.
Logout(ctx context.Context) error
}// pkg/auth/types/interfaces.go
type Identity interface {
// ... existing methods
// Logout removes identity-specific credential storage.
// Receives file manager for provider-specific cleanup.
Logout(ctx context.Context) error
}// pkg/auth/types/interfaces.go
type AuthManager interface {
// ... existing methods
// Logout removes credentials for the specified identity and its chain.
Logout(ctx context.Context, identityName string) error
// LogoutProvider removes all credentials for the specified provider.
LogoutProvider(ctx context.Context, providerName string) error
// LogoutAll removes all credentials for all identities.
LogoutAll(ctx context.Context) error
}File: pkg/auth/manager.go
// Logout removes credentials for a specific identity and its authentication chain.
func (m *manager) Logout(ctx context.Context, identityName string) error {
// 1. Validate identity exists in configuration
// 2. Build authentication chain
// 3. Delete keyring entries for each chain step (best-effort)
// 4. Call provider-specific cleanup
// 5. Collect and report errors
// 6. Return aggregated error if all steps failed
}
// LogoutProvider removes all credentials for a provider.
func (m *manager) LogoutProvider(ctx context.Context, providerName string) error {
// 1. Find all identities using this provider
// 2. Call Logout for each identity
// 3. Clean up provider-specific storage
// 4. Return aggregated errors
}
// LogoutAll removes all cached credentials.
func (m *manager) LogoutAll(ctx context.Context) error {
// 1. Iterate all identities in configuration
// 2. Call Logout for each
// 3. Return aggregated errors
}File: pkg/auth/providers/aws/sso.go, pkg/auth/providers/aws/saml.go
func (p *SSOProvider) Logout(ctx context.Context) error {
fileManager, err := NewAWSFileManager()
if err != nil {
return err
}
return fileManager.Cleanup(p.name)
}File: pkg/auth/identities/aws/permission_set.go, pkg/auth/identities/aws/assume_role.go
func (i *PermissionSetIdentity) Logout(ctx context.Context) error {
// AWS identities rely on provider cleanup
// No additional cleanup needed at identity level
return nil
}File: pkg/auth/cloud/aws/files.go
// Cleanup removes all files for a provider (already exists).
func (m *AWSFileManager) Cleanup(providerName string) error {
providerDir := filepath.Join(m.baseDir, providerName)
if err := os.RemoveAll(providerDir); err != nil {
if os.IsNotExist(err) {
// Already removed - not an error
return nil
}
return ErrCleanupAWSFiles
}
return nil
}
// CleanupAll removes entire ~/.aws/atmos directory.
func (m *AWSFileManager) CleanupAll() error {
if err := os.RemoveAll(m.baseDir); err != nil {
if os.IsNotExist(err) {
return nil
}
return ErrCleanupAWSFiles
}
return nil
}File: cmd/auth_logout.go
var authLogoutCmd = &cobra.Command{
Use: "logout [identity]",
Short: "Remove locally cached credentials and session data",
Long: `Removes cached credentials from the system keyring and local credential files.`,
RunE: executeAuthLogoutCommand,
}
func executeAuthLogoutCommand(cmd *cobra.Command, args []string) error {
// 1. Load atmos config
// 2. Create auth manager
// 3. Determine what to logout (identity, provider, or prompt)
// 4. Perform logout
// 5. Display results with Charmbracelet styling
// 6. Show browser session warning
}
func init() {
authLogoutCmd.Flags().String("provider", "", "Logout from specific provider")
authCmd.AddCommand(authLogoutCmd)
}Following Atmos error handling conventions:
// errors/errors.go - Add new error sentinels
var (
ErrLogoutFailed = errors.New("logout failed")
ErrPartialLogout = errors.New("partial logout")
)
// Usage in logout code
func (m *manager) Logout(ctx context.Context, identityName string) error {
var errs []error
// Collect errors but continue
if err := m.credentialStore.Delete(identityName); err != nil {
errs = append(errs, fmt.Errorf("%w: keyring deletion failed: %w",
ErrLogoutFailed, err))
}
// More cleanup steps...
if len(errs) > 0 {
return errors.Join(errs...)
}
return nil
}Use structured logging without affecting execution:
log.Debug("Starting logout", "identity", identityName)
log.Debug("Authentication chain built", "chain", chain)
log.Debug("Removing keyring entry", "alias", alias)
if err != nil {
log.Debug("Keyring deletion failed", "alias", alias, "error", err)
}
log.Info("Logout completed", "identity", identityName, "removed", count)// Automatic via RootCmd.ExecuteC()
// No additional telemetry code needed
// Captures: command path, error state (boolean only)Test File: pkg/auth/manager_logout_test.go
func TestManager_Logout_SingleIdentity(t *testing.T)
func TestManager_Logout_ChainedIdentity(t *testing.T)
func TestManager_Logout_MissingCredentials(t *testing.T)
func TestManager_Logout_PartialFailure(t *testing.T)
func TestManager_LogoutProvider(t *testing.T)
func TestManager_LogoutAll(t *testing.T)Test File: pkg/auth/cloud/aws/files_logout_test.go
func TestAWSFileManager_Cleanup(t *testing.T)
func TestAWSFileManager_CleanupAll(t *testing.T)
func TestAWSFileManager_CleanupNonExistent(t *testing.T)Test File: cmd/auth_logout_test.go
func TestAuthLogoutCmd_WithIdentity(t *testing.T)
func TestAuthLogoutCmd_WithProvider(t *testing.T)
func TestAuthLogoutCmd_InvalidIdentity(t *testing.T)
func TestAuthLogoutCmd_AlreadyLoggedOut(t *testing.T)Test File: tests/auth_logout_integration_test.go
func TestAuthLogout_EndToEnd(t *testing.T) {
// 1. Setup: Login with test identity
// 2. Verify credentials exist
// 3. Logout
// 4. Verify credentials removed
// 5. Verify files removed
}
func TestAuthLogout_MultipleIdentities(t *testing.T) {
// Test logging out from multiple identities
}Use existing precondition patterns:
func TestAuthLogout_AWS(t *testing.T) {
if testing.Short() {
t.Skipf("Skipping test requiring AWS profile setup")
}
// Test AWS-specific logout
}File: website/docs/cli/commands/auth/logout.mdx
- Command syntax and examples
- Flag descriptions
- Interactive mode explanation
- Security considerations
- Browser session clarification
File: website/blog/2025-10-17-auth-logout-feature.md
- Feature announcement
- Usage examples
- Security best practices
- Migration guide (if needed)
File: pkg/auth/docs/UserGuide.md
- Add logout section
- Update authentication workflow diagrams
- Add troubleshooting for logout issues
- Validate identity/provider names exist in configuration before deletion
- Never accept arbitrary paths from user input
- Use authentication chain to determine what to delete
- Log all logout operations with identity names
- Log file paths being removed
- Log keyring keys being deleted
- Enable compliance auditing
Display prominently after logout:
⚠️ Important: This command only removes locally cached credentials.
Your browser session with the identity provider (AWS SSO, Okta, etc.)
may still be active. To completely end your session:
1. Visit your identity provider's website
2. Sign out from the browser session
3. Close all browser windows
Local credentials have been securely removed.
- Ensure proper file permissions on parent directories after cleanup
- Don't leave world-readable directories
- Remove empty provider directories
- Extend Provider/Identity interfaces with Logout methods
- Implement AuthManager logout methods
- Implement AWS provider/identity logout
- Add file cleanup to AWSFileManager
- Create CLI command structure
- Add interactive prompts with Charmbracelet Huh
- Implement styled output with Charmbracelet lipgloss
- Add progress indicators for multi-step cleanup
- Add browser session warning message
- Write unit tests for all components
- Write integration tests
- Test on macOS, Linux, Windows
- Test with various identity chain configurations
- Write PRD (this document)
- Create CLI documentation
- Write blog post
- Update user guide
- Build website and verify
- Create pull request
- Code review
- CI/CD validation
- Merge to main
- Release notes
Keep provider credentials but remove identity:
atmos auth logout dev-admin --keep-providerRequire confirmation for destructive operations:
atmos auth logout --all --confirmAutomatically remove expired credentials:
atmos auth cleanup-expiredExtend logout to Azure, GCP, GitHub:
// Azure Entra ID logout
func (p *AzureProvider) Logout(ctx context.Context) error
// GCP OIDC logout
func (p *GCPProvider) Logout(ctx context.Context) errorDecision: Use interactive option only for initial release. Add --all flag in v2 if requested.
Rationale: Interactive mode is safer and prevents accidental complete logout.
Decision: No. Best-effort is default behavior. Always continue cleanup and report errors.
Rationale: Consistent with Atmos philosophy of informative error reporting.
Decision: Yes, add in initial release.
Rationale: Allows users to preview what would be deleted. Consistent with atmos vendor pull --dry-run.
Decision: Exit 0 if any cleanup succeeded, exit 1 if zero cleanup succeeded.
Rationale: Best-effort approach means partial success is still success.
- ✅ Remove credentials for specific identity
- ✅ Remove credentials for specific provider
- ✅ Interactive mode for selection
- ✅ Remove keyring entries
- ✅ Remove AWS credential files
- ✅ Best-effort error handling
- ✅ Clear user output
- ✅ Browser session warning
- ✅ Unit tests (80%+ coverage)
- ✅ Integration tests
- ✅ CLI documentation
- ✅ Blog post
- ⭕ Dry-run mode
- ⭕ Progress indicators
- ⭕ Colored output with theme
- ⭕ Command completion for identity names
- ⭕
--allflag for complete logout - ⭕ Confirmation prompts for destructive operations
- ⭕ JSON output format
- ⭕ Automated cleanup of expired credentials