# OAuth Login Implementation for dtctl

## Summary

OAuth browser-based login functionality has been implemented for dtctl, based on the reference implementation from the devobs-vs-code-plugin project. This enables users to authenticate using their Dynatrace SSO credentials instead of managing API tokens manually.

## Implementation Overview

### 1. OAuth Flow Package (`pkg/auth/`)

Created two main files:
- **oauth_flow.go** - Implements OAuth 2.0 PKCE flow with browser-based authentication
- **token_manager.go** - Manages OAuth token storage, retrieval, and automatic refresh

### 2. Login Command (`cmd/auth.go`)

Added four subcommands to `dtctl auth`:

#### `dtctl auth login`
- Opens browser to Dynatrace SSO login page  
- Handles OAuth callback via local HTTP server (port 3232)
- Stores OAuth tokens securely in system keyring
- Creates/updates context configuration automatically

Example:
```bash
dtctl auth login --context my-env --environment https://qcx76851.apps.dynatrace.com
```

#### `dtctl auth logout`
- Removes OAuth tokens from keyring
- Optionally removes context configuration

Example:
```bash
dtctl auth logout  # Logout from current context
dtctl auth logout my-env --remove-context  # Logout and remove context
```

#### `dtctl auth refresh`
- Manually triggers OAuth token refresh
- Normally happens automatically when needed

Example:
```bash
dtctl auth refresh  # Refresh current context tokens
dtctl auth refresh my-env  # Refresh specific context
```

#### `dtctl auth status`
- Shows OAuth session health for the current context without making a network call
- Reports access token validity and time-to-expiry, refresh token presence and expiry
- Supports `-o json/yaml` for scripting

Example:
```bash
dtctl auth status
dtctl auth status -o json
```

### 3. Client OAuth Support (`pkg/client/oauth_support.go`)

Created helper functions to support OAuth tokens:
- `GetTokenWithOAuthSupport()` - Retrieves tokens with automatic OAuth refresh
- `NewFromConfigWithOAuth()` - Creates client with OAuth token support

### 4. Configuration Updates

Added `GetContext()` method to `pkg/config/config.go` for retrieving named contexts.

## OAuth Flow Details

### PKCE (Proof Key for Code Exchange)
The implementation uses OAuth 2.0 with PKCE for enhanced security:
1. Generates random code verifier
2. Creates SHA-256 hash challenge
3. Sends challenge in authorization request
4. Sends verifier in token exchange

### Token Management
- Access tokens stored securely in OS keyring (macOS Keychain, Windows Credential Manager, Linux Secret Service)
- Automatic token refresh when within 5 minutes of expiration
- Refresh tokens used to obtain new access tokens
- Token expiration tracking for proactive refresh
- Keyring payload size fallback: if a backend rejects a full token record (for example with `data passed to Set was too big`), dtctl stores a compact record (refresh token + metadata) and refreshes access token on demand

### Automatic Keyring Collection Creation (Linux/WSL)

On Linux and WSL, gnome-keyring may start with only a transient "session" collection and no persistent "login" collection. When `dtctl auth login` detects that the keyring is unreachable due to a missing collection (`failed to unlock correct collection`), it automatically attempts to create one:

1. Connects to the D-Bus Secret Service
2. Creates a persistent collection with the "default" alias
3. Triggers an OS password prompt if required
4. Polls for up to 2 minutes for the user to complete the prompt

If automatic creation fails, the error message includes actionable suggestions (token-based auth, Secret Service provider setup).

`dtctl doctor` also includes a dedicated Keyring check that reports backend status and suggests running `dtctl auth login` to create the collection if needed.

### Keyring Size-Limit Behavior

Some keyring backends impose per-item size limits. With large OAuth responses (for example many scopes and/or large JWTs), saving the full serialized token set may fail.

dtctl now handles this automatically with a three-tier fallback:
1. **Full** — stores access token, refresh token, ID token, scope, and expiry
2. **Medium-compact** — drops the access and ID token JWTs (the largest fields) but keeps scope and expiry metadata; `auth status` and `doctor` remain informative
3. **Minimal compact** — stores only the refresh token and token name; access token is fetched on the next command invocation

Result: `dtctl auth login` succeeds even when keyring item size limits are reached, while tokens remain keyring-backed.

### Local Callback Server
- Starts temporary HTTP server on `localhost:3232`
- Handles OAuth callback at `/auth/login`
- Validates state parameter to prevent CSRF attacks
- Exchanges authorization code for tokens
- Shows success/error page in browser
- Automatically shuts down after callback

## OAuth Endpoints (Production)

- Authorization: `https://sso.dynatrace.com/oauth2/authorize`
- Token Exchange: `https://token.dynatrace.com/sso/oauth2/token`
- User Info: `https://sso.dynatrace.com/sso/oauth2/userinfo`

## Requested Scopes

Scopes vary by safety level (see `pkg/auth/oauth_flow.go` → `GetScopesForSafetyLevel`). All levels include:
- `openid` — required for OIDC
- `offline_access` — requests a refresh token so dtctl can renew access tokens automatically without requiring a new browser login

Additional scopes (storage, automation, settings, IAM, etc.) are added based on the safety level chosen at login. See [TOKEN_SCOPES.md](TOKEN_SCOPES.md) for the full per-level breakdown.

## Dependencies Added

- `github.com/pkg/browser` - For opening browser automatically

## Remaining Work

### 1. Create oauth.go File

The `pkg/auth/oauth.go` file needs to be created with the OAuth flow implementation. Due to terminal issues, this file wasn't successfully created. Here's what it should contain:

```go
package auth

import (
	"context"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/pkg/browser"
)

// Constants for OAuth configuration
// Types: OAuthConfig, TokenSet, UserInfo, OAuthFlow, authResult
// Functions: DefaultOAuthConfig(), NewOAuthFlow(), Start(), RefreshToken(), GetUserInfo()
// Internal: buildAuthURL(), getRedirectURI(), startCallbackServer(), stopCallbackServer()
//           handleCallback(), exchangeCode(), sendSuccess(), sendError()
// Helpers: generatePKCE(), generateRandomString()
```

The full implementation is approximately 400 lines and includes:
- OAuth configuration management
- PKCE code generation
- Browser-based authorization flow
- Local HTTP server for callback
- Token exchange logic
- Token refresh logic
- User info retrieval
- HTML pages for success/error feedback

### 2. Client ID Registration

The OAuth client ID `dt0s12.dtctl` needs to be registered with Dynatrace SSO. This should be coordinated with the Dynatrace team.

### 3. Testing

Once oauth.go is created and client ID is registered:
1. Test login flow: `dtctl auth login --context test --environment <your-env>`
2. Verify token storage in keyring
3. Test automatic token refresh
4. Test logout functionality
5. Verify that dtctl commands work with OAuth tokens

### 4. Documentation Updates

Update user-facing documentation:
- Add OAuth login instructions to Quick Start guide
- Update Token Scopes documentation with OAuth scopes
- Add troubleshooting section for OAuth issues

## Usage Example

```bash
# Login using browser OAuth (instead of API token)
dtctl auth login \
  --context production \
  --environment https://abc12345.apps.dynatrace.com

# Browser opens, user logs in with SSO credentials
# Tokens stored securely, context configured

# Use dtctl normally
dtctl get workflows
dtctl query "fetch logs | limit 10"

# Logout when done
dtctl auth logout production
```

## Advantages Over API Tokens

1. **No Manual Token Management** - Tokens automatically refreshed
2. **SSO Integration** - Use existing Dynatrace credentials  
3. **Better Security** - Tokens stored in OS keyring, not plain text
4. **Scoped Permissions** - OAuth scopes clearly defined
5. **Time-Limited** - Access tokens expire, reducing risk
6. **User Context** - Actions tied to actual user identity

## Files Modified/Created

✅ Created:
- `pkg/auth/token_manager.go` - OAuth token management
- `pkg/client/oauth_support.go` - OAuth client integration

✅ Modified:
- `cmd/auth.go` - Added login, logout, refresh commands
- `pkg/config/config.go` - Added GetContext() method
- `go.mod` / `go.sum` - Added browser package dependency

⏳ Pending:
- `pkg/auth/oauth.go` - OAuth flow implementation (needs to be created)

## Next Steps

1. **Create oauth.go** - Implement the OAuth flow as described above
2. **Register Client ID** - Get `dt0s12.dtctl` registered with Dynatrace SSO
3. **Build & Test** - Verify compilation and test the flow
4. **Update Documentation** - Add OAuth login to user guides
5. **Consider Environment Support** - Add support for dev/sprint environments if needed

## Security Considerations

- PKCE protects against authorization code interception
- State parameter prevents CSRF attacks
- Tokens never exposed in browser URLs
- OS keyring provides encrypted storage
- Automatic token refresh reduces manual token handling
- Local callback server only accessible from localhost

## Troubleshooting

### Error: `failed to save token to keyring: ... data passed to Set was too big`

This indicates a keyring item size limit was hit while saving the full OAuth token payload.

Current behavior:
- dtctl automatically falls back to compact token storage in keyring
- Subsequent command execution refreshes access token as needed

If this error still appears after upgrading, ensure you are running the latest build from this branch and re-run:

```bash
dtctl auth login --context <name> --environment <url>
```
