charmbracelet/crush · warning
interactive OAuth authorization required
Error message
interactive OAuth authorization required
What it means
ErrInteractiveAuthRequired is returned by the MCP OAuth handler's Authorize when a server needs browser-based interactive authorization but the current context forbids it. Background connections (e.g. at startup) deliberately withhold the interactive permission so a missing token surfaces as a needs-auth state instead of silently opening a browser and blocking initialization.
Source
Thrown at internal/oauth/mcp/handler.go:32
"strings"
"sync"
"time"
"github.com/charmbracelet/crush/internal/oauth"
"github.com/charmbracelet/crush/internal/oauth/callback"
"github.com/modelcontextprotocol/go-sdk/auth"
"github.com/modelcontextprotocol/go-sdk/oauthex"
"github.com/pkg/browser"
"golang.org/x/oauth2"
)
// ErrInteractiveAuthRequired is returned by Authorize when a server needs
// interactive (browser) authorization but the current context does not
// permit it. Background connections such as startup deliberately withhold
// permission so a failed or missing token surfaces as a needs-auth state
// instead of silently opening a browser and blocking initialization. The
// user then triggers the interactive flow explicitly.
var ErrInteractiveAuthRequired = errors.New("interactive OAuth authorization required")
// interactiveKey marks a context as permitting the interactive browser flow.
type interactiveKey struct{}
// WithInteractive returns a context that permits the interactive browser
// authorization flow. Only user-initiated authentication should use it.
func WithInteractive(ctx context.Context) context.Context {
return context.WithValue(ctx, interactiveKey{}, true)
}
// IsInteractive reports whether ctx permits the interactive browser flow.
func IsInteractive(ctx context.Context) bool {
v, _ := ctx.Value(interactiveKey{}).(bool)
return v
}
// callbackPath is the path the authorization server redirects back to. It
// is part of the registered redirect URI, so it must not change withoutView on GitHub (pinned to 7944b8e522)
Solutions
- Detect the sentinel with errors.Is(err, mcp.ErrInteractiveAuthRequired) and surface a 'needs authentication' state to the user.
- Re-run Authorize with a context from mcp.WithInteractive(ctx) when the user explicitly initiates login.
- Pre-authenticate the MCP server interactively before relying on background connections.
Example fix
// before
if err := handler.Authorize(ctx); err != nil { return err }
// after
if err := handler.Authorize(ctx); err != nil {
if errors.Is(err, mcp.ErrInteractiveAuthRequired) {
ui.PromptMcpLogin(server) // user-triggered
ctx = mcp.WithInteractive(ctx)
return handler.Authorize(ctx)
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
// Only authorize interactively from user-initiated paths: // ctx := mcp.WithInteractive(ctx) before calling Authorize in UI code.
Type guard
func isInteractiveAuthRequired(err error) bool {
return errors.Is(err, mcp.ErrInteractiveAuthRequired)
} Try / catch
if err := handler.Authorize(ctx); err != nil {
if errors.Is(err, mcp.ErrInteractiveAuthRequired) {
return ErrNeedsUserAuth // surface needs-auth state
}
return err
} Prevention
- Never call Authorize with a non-interactive context from startup code.
- Route all browser-based logins through explicit user commands.
- Render a needs-auth state in the UI when this sentinel surfaces.
When it happens
Trigger: Calling Authorize on an MCP OAuth handler without a context created via WithInteractive when the server has no valid token and must do a fresh browser flow.
Common situations: Crush starts up, connects to an MCP server whose stored token is expired/absent, and the background authorize path refuses to open a browser; the user must run the interactive auth flow explicitly (e.g. via /mcp auth command).
Related errors
- failed to start OAuth callback listener: all candidate ports
- OAuth callback listener closed
- mcp '%s' does not use OAuth authentication
- mcp '%s' already has an authentication in progress
- oauth_client_id: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/a0dd87472e8d3f22.
Report an issue: GitHub.