Skip to content

feat: Claude /login subscription billing for claude_code (openlock-ndb)#67

Merged
vessux merged 24 commits into
mainfrom
feat/claude-subscription-billing-ndb
Jun 13, 2026
Merged

feat: Claude /login subscription billing for claude_code (openlock-ndb)#67
vessux merged 24 commits into
mainfrom
feat/claude-subscription-billing-ndb

Conversation

@vessux

@vessux vessux commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Status: steps 1–2 DONE, CI green ✅ — remaining gates require the maintainer

Done autonomously:

  1. Fork releasedfeat(cred_inject): add value_prefix to CredInjectHeader OpenShell#8 merged to fork main, tagged v0.6.5, openlock-release.yml published all binaries.
  2. OPENSHELL_FORK_TAG bumped v0.6.4v0.6.5 (4ba4e4c). CI now downloads the value_prefix-capable binary.
  3. CI fully greentest, Analyze, CodeQL, and both live-integration (docker + podman) pass against the v0.6.5 binary (live gateway+sandbox cred_inject exercised end-to-end).

Remaining (maintainer-only):

  • Real-account subscription-billing e2e — needs an interactive browser OAuth login to a real Claude subscription + real billing (cannot be automated). Checklist below.
  • Mergemain branch protection requires maintainer review/approval.

Summary

Replaces openlock's claude setup-token (API-billing) path with a host-side OAuth /login flow so a sandboxed Claude Code bills the user's Claude subscription, with the real token never entering the sandbox.

End-to-end flow:

  1. openlock login --provider anthropic runs a host-side OAuth PKCE paste-back flow (hosted callback platform.claude.com/oauth/code/callback, no localhost) → real access+refresh token pair.
  2. Credential record stores the raw access token in ANTHROPIC_BEARER_TOKEN + a refresh block.
  3. On sandbox start, ensure-provider imports a runtime claude-oauth profile and seeds the gateway once (never-clobber), wiring the gateway's native OAuth refresher.
  4. The sandbox gets a dummy OAT-shaped .credentials.json + CLAUDE_CONFIG_DIR → flips Claude Code into OAuth mode.
  5. Policy strips Authorization and re-injects Authorization: Bearer <raw token> via value_prefix: "Bearer " (fork v0.6.5).

Breaking / behavior changes (for release notes)

  • V1 credentials.json lossy-migrated: a legacy setup-token is dropped on migration → user re-runs openlock login.
  • opencode + anthropic no longer supported: errors actionably (use OpenRouter or the OpenCode Claude-auth plugin). Claude subscription is claude_code-only.

Remaining e2e checklist (maintainer, real account)

  • openlock login --provider anthropic → record has refresh; access token not logged
  • openshell provider refresh status shows oauth2_refresh_token, configured, token_url set
  • in-sandbox claude --debug → OAuth mode (not "Skipped: no usable OAuth"); completion succeeds
  • wire check: outbound carries anthropic-beta: ...oauth-2025-04-20...; bills sub base bucket (overage-status: rejected, unified-5h-status: allowed); exactly one Authorization header
  • dummy .credentials.json never leaves sandbox; real token never enters it
  • token-expiry/rotation: next request still succeeds (gateway refreshed; never-clobber on reattach)

Closes openlock-ndb (after merge). Fork: vessux/OpenShell#8 (merged, v0.6.5).

@vessux

vessux commented Jun 13, 2026

Copy link
Copy Markdown
Owner Author

⚠️ Direction change (2026-06-13) — login mechanism pivoting to token-import

Real-account e2e surfaced that reimplementing Claude Code's OAuth /login handshake is too fragile (3 failed attempts chasing the right authorize host + scope set; Anthropic changes these freely). Decision: drop the openlock-side OAuth handshake and import the token Claude Code itself obtains.

Proven this session: a controlled isolated Claude Code login (CLAUDE_CONFIG_DIR=<throwaway> → token lands in a namespaced keychain item, user's main session untouched) → harvest → prime openlock's provider. Result: anthropic stored=yes in_gateway=yes with a real subscription token. All downstream wiring in this PR staysvalue_prefix inject, sandboxFiles dummy creds, ensure-provider, gateway refresh. Only the acquisition changes.

Still to do (fresh session):

  • Rework anthropic loginInteractive → import-from-Claude-Code; drop anthropic-oauth.ts handshake.
  • Add openlock sandbox --no-attach (filed) — needed to script the in-sandbox e2e (sandbox currently force-attaches; backgrounding it wedges the session → relay open timed out).
  • Run the live e2e (OAuth-mode + completion + subscription-bucket billing + in-sandbox creds = dummy).

Added this session: OPENSHELL_FORK_TAG→v0.6.5 (4ba4e4c), OPENLOCK_OPENSHELL_BIN dev override (fa60c81), OAuth ground-truth constants (fd4e96f, will be superseded by import). Do not merge until the login rework + e2e land.

@vessux vessux merged commit dc4e5cc into main Jun 13, 2026
5 checks passed
@vessux vessux deleted the feat/claude-subscription-billing-ndb branch June 13, 2026 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant