Skip to content
Closed
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
12 changes: 8 additions & 4 deletions cmd/auth_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ func executeAuthLoginCommand(cmd *cobra.Command, args []string) error {
// Provider-level authentication (e.g., for SSO auto-provisioning).
whoami, err = authManager.AuthenticateProvider(ctx, providerName)
if err != nil {
return fmt.Errorf("%w: provider=%s: %w", errUtils.ErrAuthenticationFailed, providerName, err)
// Return error directly - it already has ErrorBuilder context with hints.
return err
}
} else {
// Try identity-level authentication first.
Expand All @@ -82,7 +83,8 @@ func executeAuthLoginCommand(cmd *cobra.Command, args []string) error {
}
whoami, err = authManager.AuthenticateProvider(ctx, providerName)
if err != nil {
return fmt.Errorf("%w: provider=%s: %w", errUtils.ErrAuthenticationFailed, providerName, err)
// Return error directly - it already has ErrorBuilder context with hints.
return err
}
} else if err != nil {
return err
Expand Down Expand Up @@ -118,14 +120,16 @@ func authenticateIdentity(ctx context.Context, cmd *cobra.Command, authManager a
errors.Is(err, errUtils.ErrNoDefaultIdentity) {
return nil, true, nil
}
return nil, false, fmt.Errorf(errUtils.ErrWrapFormat, errUtils.ErrDefaultIdentity, err)
// Return error directly - it already has ErrorBuilder context with hints.
return nil, false, err
}
}

// Perform identity authentication.
whoami, err := authManager.Authenticate(ctx, identityName)
if err != nil {
return nil, false, fmt.Errorf("%w: identity=%s: %w", errUtils.ErrAuthenticationFailed, identityName, err)
// Return error directly - it already has ErrorBuilder context with hints.
return nil, false, err
}

return whoami, false, nil
Expand Down
3 changes: 2 additions & 1 deletion cmd/terraform/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,8 @@ func handleInteractiveIdentitySelection(info *schema.ConfigAndStacksInfo) {
// Note: We bypass error formatting as user abort is not an error condition.
errUtils.Exit(errUtils.ExitCodeSIGINT)
}
errUtils.CheckErrorPrintAndExit(fmt.Errorf(errWrapFormat, errUtils.ErrDefaultIdentity, err), "", "")
// Print error directly - it already has ErrorBuilder context with hints.
errUtils.CheckErrorPrintAndExit(err, "", "")
}

info.Identity = selectedIdentity
Expand Down
268 changes: 268 additions & 0 deletions docs/prd/auth-error-messaging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
# PRD: Improved Auth Error Messaging

## Overview

This PRD defines requirements for improving error messaging in `atmos auth` to provide better developer experience when authentication fails. Currently, auth errors lack context about why authentication failed, making troubleshooting difficult.

## Problem Statement

When authentication fails, users receive minimal error messages like:

```text
Error: authentication failed: failed to authenticate via credential chain
for identity "plat-dev/terraform": authentication failed: identity=plat-
dev/terraform step=1: authentication failed
```

This error provides no visibility into:
- The identity being authenticated
- The current profile (or lack thereof)
- Actionable steps to resolve the issue

## Goals

1. Provide rich, contextual error messages for all auth-related failures
2. Use the standard ErrorBuilder pattern consistently across auth code
3. Include profile info and actionable hints
4. Cover authentication failures, credential cache issues, and configuration validation errors

## Non-Goals

- Changing authentication logic or flow
- Adding new authentication providers
- Modifying the credential storage system

## Scope

This PRD covers error improvements for three categories:

### 1. Authentication Failures
- Provider authentication failures (AWS SSO, GitHub OIDC, etc.)
- Identity authentication failures (assume-role, permission-set)
- Credential chain failures (multi-step authentication)

### 2. Credential Cache Issues
- Missing credentials (`ErrNoCredentialsFound`)
- Expired credentials (`ErrExpiredCredentials`)
- Invalid credentials
- Credential store initialization failures

### 3. Configuration Validation Errors
- Invalid provider configuration
- Invalid identity configuration
- Missing required fields
- Circular dependencies in identity chains
- Identity/provider not found

## Requirements

### R1: Error Context Requirements

All auth errors MUST include the following context using the existing ErrorBuilder `.WithContext()` API:

| Context | Description | Example |
|---------|-------------|---------|
| `profile` | Active profile(s) or "(not set)" | `devops` |
| `provider` | Provider name | `aws-sso` |
| `identity` | Target identity name | `plat-dev/terraform` |
| `expiration` | Credential expiration time (when applicable) | `2024-01-15T10:30:00Z` |

### R2: Profile Status Display

All auth errors MUST include current profile status in the context table.

If not set:
```text
| profile | (not set) |
```

Multiple profiles should be comma-separated:
```text
| profile | ci, developer |
```

### R3: Actionable Hints

Each error type MUST include appropriate hints:

| Error Type | Required Hints |
|------------|----------------|
| Auth failure | "Run `atmos auth --help` for troubleshooting" |
| Expired credentials | "Run `atmos auth login` to refresh credentials" |
| Missing credentials | "Run `atmos auth login` to authenticate" |
| SSO session expired | "Run `atmos auth login --provider <name>` to re-authenticate" |
| Identity not found | "Run `atmos list identities` to see available identities" |
| Provider not found | "Run `atmos list providers` to see available providers" |
| No profile set | "Set ATMOS_PROFILE or use --profile flag" |
| Circular dependency | "Check identity chain configuration for cycles" |

### R4: ErrorBuilder Migration

All auth errors MUST use the ErrorBuilder pattern:

```go
return errUtils.Build(errUtils.ErrAuthenticationFailed).
WithCause(underlyingErr).
WithExplanation("Failed to authenticate identity").
WithHint("Run `atmos auth --help` for troubleshooting").
WithContext("profile", formatProfile(profilesFromArg)).
WithContext("provider", providerName).
WithContext("identity", identityName).
Err()
```

### R5: Error Categories and Sentinels

Use appropriate sentinel errors for each category:

**Authentication Failures:**
- `ErrAuthenticationFailed` - General auth failure
- `ErrPostAuthenticationHookFailed` - Post-auth hook failure

**Credential Issues:**
- `ErrNoCredentialsFound` - Missing credentials
- `ErrExpiredCredentials` - Expired/invalid credentials
- `ErrInitializingCredentialStore` - Store init failure

**Configuration Errors:**
- `ErrInvalidIdentityConfig` - Invalid identity config
- `ErrInvalidProviderConfig` - Invalid provider config
- `ErrIdentityNotFound` - Identity not in config
- `ErrProviderNotFound` - Provider not in config
- `ErrCircularDependency` - Circular chain dependency
- `ErrNoDefaultIdentity` - No default identity configured

**SSO-Specific:**
- `ErrSSOSessionExpired` - SSO session expired
- `ErrSSODeviceAuthFailed` - Device auth failed
- `ErrSSOTokenCreationFailed` - Token creation failed

## Example Error Output

### Example 1: Authentication Failed

```markdown
# Authentication Error

**Error:** authentication failed

## Explanation

Failed to authenticate via credential chain for identity "plat-dev/terraform".

## Hints

💡 Run `atmos auth --help` for troubleshooting
💡 Check that the GitHub OIDC provider is correctly configured

## Context

| Key | Value |
|-----|-------|
| profile | devops |
| provider | github-oidc |
| identity | plat-dev/terraform |
```

### Example 2: Credentials Expired (No Profile)

```markdown
# Authentication Error

**Error:** credentials for identity are expired or invalid

## Explanation

Cached credentials for identity "core-auto/terraform" have expired.

## Hints

💡 Run `atmos auth login` to refresh credentials
💡 Set ATMOS_PROFILE or use --profile flag to select a profile

## Context

| Key | Value |
|-----|-------|
| profile | (not set) |
| provider | aws-sso |
| identity | core-auto/terraform |
| expiration | 2024-01-15T10:30:00Z |
```

### Example 3: Identity Not Found in Profile

```markdown
# Authentication Error

**Error:** identity not found

## Explanation

Identity "plat-sandbox/terraform" not found in the current configuration.

## Hints

💡 Run `atmos list identities` to see available identities
💡 Check that the identity is defined in your auth configuration
💡 Current profile may not include this identity

## Context

| Key | Value |
|-----|-------|
| profile | github-plan |
| provider | (not set) |
| identity | plat-sandbox/terraform |
```

## Implementation Notes

### Helper Functions

Create helper functions for consistent formatting:

```go
// FormatProfile formats profile information for error display.
func FormatProfile(profiles []string) string {
if len(profiles) == 0 {
return "(not set)"
}
return strings.Join(profiles, ", ")
}
```

### Files to Modify

| File | Changes |
|------|---------|
| `pkg/auth/manager.go` | Migrate all error returns to ErrorBuilder pattern |
| `pkg/auth/manager_helpers.go` | Add profile context to errors |
| `pkg/auth/credentials/store.go` | Improve credential store errors |
| `pkg/auth/validation/validator.go` | Improve validation error messages |
| `pkg/auth/identities/aws/*.go` | Add identity-specific error context |
| `pkg/auth/providers/aws/*.go` | Add provider-specific error context |
| `pkg/auth/errors.go` (new) | Helper functions for error formatting |

### Testing Requirements

1. Unit tests for each error type with expected context
2. Test that `errors.Is()` works correctly with wrapped errors
3. Test profile formatting (set, not set, multiple)

## Success Criteria

1. All auth errors use ErrorBuilder pattern consistently
2. Every auth error includes identity, provider, and profile context
3. Every error includes at least one actionable hint
4. Users can understand why authentication failed from the error message alone
5. All existing tests pass with updated error format
6. New tests cover all error scenarios

## References

- [ErrorBuilder Documentation](../errors.md)
- [Auth Configuration](../auth/README.md)
- [Atmos Profiles PRD](./atmos-profiles.md)
- [Auth Default Settings PRD](./auth-default-settings.md)
- Linear Issue: DEV-3809
Loading
Loading