Skip to content

Implement OIDC device flow authentication #54

@KofTwentyTwo

Description

@KofTwentyTwo

User Story

As a developer, I want to authenticate with qctl using my browser so I can securely access Voyage APIs without managing passwords in the CLI.

Design

Command Interface

# Start login flow
qctl auth login

# Login to specific provider
qctl auth login --provider voyage

# Check authentication status
qctl auth status

# Logout (clear tokens)
qctl auth logout

# Refresh token manually
qctl auth refresh

Device Flow Output

Logging in to Voyage...

Please visit: https://voyage.qrun.io/device
Enter code: ABCD-1234

Waiting for authorization... (press Ctrl+C to cancel)

[Browser opens automatically]

Authenticated as: james.maes@example.com
Organization: acme-corp
Token stored in: macOS Keychain

Login successful!

OIDC Configuration

# ~/.qctl/qctl.yaml
auth:
  provider: voyage
  providers:
    voyage:
      issuer: https://auth.qrun.io
      client_id: qctl-cli
      scopes:
        - openid
        - profile
        - qctl:read
        - qctl:write
      device_auth_endpoint: /oauth/device/code
      token_endpoint: /oauth/token

Token Storage

# Tokens stored in OS keychain with entries:
qctl:voyage:access_token
qctl:voyage:refresh_token
qctl:voyage:id_token
qctl:voyage:expires_at

Files to Create/Modify

File Action Purpose
qctl-core/src/main/java/io/qrun/qctl/core/auth/AuthCommand.java Create Auth command group
qctl-core/src/main/java/io/qrun/qctl/core/auth/LoginCommand.java Create Login subcommand
qctl-core/src/main/java/io/qrun/qctl/core/auth/LogoutCommand.java Create Logout subcommand
qctl-core/src/main/java/io/qrun/qctl/core/auth/StatusCommand.java Create Status subcommand
qctl-core/src/main/java/io/qrun/qctl/core/auth/DeviceFlow.java Create Device flow implementation
qctl-core/src/main/java/io/qrun/qctl/core/auth/TokenManager.java Create Token lifecycle
qctl-core/src/main/java/io/qrun/qctl/core/auth/OIDCClient.java Create OIDC HTTP client
qctl-core/src/main/java/io/qrun/qctl/core/auth/model/DeviceCode.java Create Device code response
qctl-core/src/main/java/io/qrun/qctl/core/auth/model/TokenResponse.java Create Token response

Implementation Tasks

  • Create AuthCommand with login, logout, status, refresh subcommands
  • Implement DeviceFlow with RFC 8628 compliance
  • Request device code from authorization server
  • Display user code and verification URI
  • Open browser automatically (with fallback)
  • Poll token endpoint with appropriate interval
  • Handle authorization_pending, slow_down, expired_token errors
  • Implement TokenManager for token storage/retrieval
  • Integrate with OS keychain (Add OS keychain integration #57)
  • Implement automatic token refresh before expiry
  • Add --provider flag for multi-provider support
  • Write unit tests for DeviceFlow
  • Write integration tests with mock OIDC server

Acceptance Criteria

  • qctl auth login starts device authorization flow
  • Displays verification URI and user code
  • Opens browser automatically
  • Polls for token with backoff
  • Stores tokens securely in keychain
  • qctl auth status shows current auth state
  • qctl auth logout clears stored tokens
  • Automatic token refresh works silently
  • Works with Voyage OIDC provider

Metadata

Metadata

Assignees

No one assigned

    Labels

    module:coreCore infrastructurestoryFeature story linked to epic

    Projects

    Status

    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions