The grm cli architecture This document outlines the architecture, design decisions, and implementation details for the grm CLI authentication flow.

Overview

The grm CLI (backend/go/cmd/cli/) aims to provide a single typed command to replace interactive shell scripts, enhancing developer experience. More importantly, it serves as an agent interface, allowing AI agents to authenticate once and use the stored API key for all subsequent operations without human intervention. The MVP scope includes three core commands:
  • grm auth login
  • grm auth logout
  • grm auth whoami

Problem Statement

The CLI must authenticate on behalf of developers and AI agents—including cases where no human is present after the initial login. Traditional authentication mechanisms fall short:
  • Username/password flags: Require typing credentials into the terminal, are incompatible with SSO/OAuth, and result in passwords stored at rest.
  • Session cookies: Browser-scoped and cannot be portably persisted across CLI invocations.
  • Short-lived access tokens: Require frequent re-authentication, breaking agent workflows where no human is present to approve the refresh.

Solution: OAuth 2.0 Device Flow with API Keys

To solve these issues, the grm CLI uses the OAuth 2.0 Device Authorization Grant (RFC 8628) combined with long-lived API keys.

The Flow

  1. Request Device Code: The CLI requests a device code (POST /api/auth/device/code).
  2. User Approval: The CLI opens the browser to the admin panel’s /device page. The user explicitly approves the request.
  3. Poll for Token: The CLI polls (POST /api/auth/device/token) until the user approves, receiving a short-lived access token.
  4. Exchange for API Key: The CLI immediately exchanges the access token for a long-lived API key (POST /api/auth/api-key/create).
  5. Persistence: Only the API key is persisted locally (to ~/.config/grm/config.json). The access token is discarded.
By storing an API key, every subsequent CLI invocation can authenticate using the x-api-key header with no expiry concerns. API keys can also be named and revoked independently per device.

Implementation Details

The implementation spans three main subsystems across the monorepo:

1. Bun Backend

The Bun backend leverages Better Auth with three required plugins:
  • deviceAuthorization: Enables the OAuth 2.0 Device Flow.
  • apiKey: Enables the generation of long-lived API keys.
  • bearer: Allows the CLI to authenticate the POST /api/auth/api-key/create request using Authorization: Bearer <access_token>.
ADR-0011: The bearer plugin is strictly required. Without it, Better Auth rejects the CLI’s createApiKey call with a 401 error since the CLI lacks a browser session cookie. Do not remove the bearer plugin as long as the CLI uses this flow.

2. SolidStart Admin Panel

A dedicated /device route serves as the user verification page.
  • Requires an active session (redirects unauthenticated users to sign in).
  • Shows the user code and explicit Approve and Deny buttons.
  • Security Rule: The page does not auto-approve on mount to prevent a stolen user_code link from silently authorizing a device.

3. Go CLI Core

The CLI uses a thin abstraction layer over Cobra (pkg/cli/builder.go) to reduce boilerplate and declarative define commands (CommandDef, GroupDef). Auth state is saved to ~/.config/grm/config.json with 0600 permissions (owner read/write only).

Per-Device Naming and Revocation

ADR-0012: API keys are named "grm-cli@<hostname>" (e.g., grm-cli@my-macbook).
A single developer may use the CLI from multiple machines. To prevent orphaned keys and avoid accidentally revoking another machine’s key, the CLI performs a best-effort revocation on re-login:
  1. Lists all API keys for the authenticated user.
  2. Filters for keys matching the current device’s hostname.
  3. Revokes only those matching keys before creating a fresh one.

Architectural Decision Records

Specs and Plans

  • docs/superpowers/plans/2026-05-13-grm-cli-auth.md
  • docs/superpowers/specs/2026-05-13-grm-cli-auth-design.md

Summary

The grm CLI auth architecture provides a robust, agent-friendly authentication mechanism without compromising security. By leveraging the OAuth 2.0 Device Flow to bootstrap a long-lived, per-device API key, it balances developer convenience with the automated needs of AI agents.