Authentication Inventory & Migration Readiness: Multi-Account Infrastructure Audit
Over the past session, we completed a comprehensive audit of authentication across JADA's distributed infrastructure: local development on Mac, the Lightsail agent runner, and AWS Lambda chatbots. This post documents the inventory, architectural decisions, and readiness checklist for the planned account migration.
What Was Done
We catalogued three distinct authentication contexts, each with different credential types, lifecycles, and risk profiles. The result is a detailed reference document at /Users/cb/icloud-repos/shared/references/environments.md that serves as the canonical source of truth for credential sourcing, rotation intervals, and account assignments.
- Mac development environment: Migrating from iOS-billed subscription (metered API key) to web-billed subscription (interactive OAuth in system Keychain)
- Lightsail jada-agent: Validated existing CLAUDE_CODE_OAUTH_TOKEN and confirmed 1-year validity window under the legacy iOS-billed plan
- Lambda chatbots: Confirmed Console API key usage (unaffected by subscription tier changes) across four production functions
Technical Details: Three Auth Contexts
Context 1: macOS Interactive Development
The Mac uses OAuth stored in the macOS Keychain under the item named Claude Code-credentials. This is fetched automatically by Claude Code desktop when invoked in interactive mode. The credential includes read/write scopes for projects, file operations, and tool execution. No API key is stored in shell configuration files or environment variables.
# NO API key in interactive shell — uses Keychain OAuth
$ env | grep -i anthropic
# (empty)
# Token refresh happens transparently via Keychain + system auth
$ security find-generic-password -ga "Claude Code-credentials"
# (returns encrypted credential stored in Keychain)
The new web-billed account will also use subscription OAuth in the same Keychain item, maintaining the same interaction pattern. The tier upgrade (from lowest to high-plan) affects only rate limits and feature availability, not auth flow.
Context 2: Lightsail jada-agent (24/7 Agent Runner)
The Lightsail box at 34.239.233.28 runs persistent ticket-automation tasks under the plan-billed Claude Proxy. Authentication is a 1-year CLAUDE_CODE_OAUTH_TOKEN stored in /home/ubuntu/ticket-runner/.env, minted from the old iOS-billed account. This token:
- Expires: ~12 months from mint date (recorded in the reference doc)
- Scope: sufficient for project/file/tool access needed by ticket-runner
- Lifecycle: survives the iOS account downgrade to lowest plan (Lightsail-only use), expires ~April 2027
- No rotation required during this period; migration path documented for renewal
The token is injected into the environment at agent startup via LaunchAgent or direct process invocation. The reference doc includes a read-only SSH checklist to confirm the token is present and matches expected format:
# SSH validation (read-only check, no modifications)
ssh ubuntu@34.239.233.28 "grep CLAUDE_CODE_OAUTH_TOKEN /home/ubuntu/ticket-runner/.env | wc -c"
# Confirms token is present; length should be ~200 chars for valid JWT structure
ssh ubuntu@34.239.233.28 "cat /home/ubuntu/ticket-runner/.env | head -5"
# Verify no API key bleeding into environment variables
Context 3: Lambda Chatbots
Four production Lambda functions use a shared Console API key for Claude model invocations:
dc-chat-api— DragonCorp chat endpointshipyard-bot— Slack integrationshipcaptaincrew— Crew management chatbottenant-portal-*— Tenant self-service (multiple functions)
The API key is injected via AWS Secrets Manager (or environment variable at function deploy time) and is completely decoupled from subscription tier. The Console API key:
- Persists across account downgrades (Console is usage-metered, not subscription-gated)
- Requires no changes during the Mac account migration
- Is protected by IAM policies restricting Lambda execution role access
Infrastructure & File Layout
The audit produced or updated the following reference documents:
| Path | Purpose | Owner |
|---|---|---|
/Users/cb/icloud-repos/shared/references/environments.md |
Canonical auth inventory + credential sourcing for all three contexts | Local (Mac) |
~/icloud-jada-ops/ |
Working files & credential references (iCloud sync, not git) | Local + jada-agent |
/home/ubuntu/ticket-runner/.env |
1-year OAUTH token + runtime config (Lightsail) | Lightsail only |
| AWS Secrets Manager | Console API key + other service credentials (Lambdas) | AWS account |
Key Decisions & Rationale
Why three separate auth contexts?
Each environment has different runtime requirements and failure domains. The Mac is interactive and user-facing; Lightsail runs headless 24/7; Lambdas are ephemeral and often run in parallel. Mixing credentials (e.g., storing the Lightsail token on Mac, or using Keychain from Lambda) would create hard-to-debug cross-environment issues and increase blast radius if any credential leaks.
Why OAuth token for Lightsail instead of API key?
The ticket-runner agent uses the plan-billed Claude Proxy, which is token-authenticated. OAuth tokens also have narrower scopes (project/file/tool access only) compared to Console API keys, which can be used for any API endpoint. This reduces risk if the token is accidentally logged or committed.
Why keep the old iOS-billed account until April 2027?
The 1-year Lightsail token expires April 2027. Keeping the old account open on the lowest plan costs minimal overhead (~$20/mo) and avoids forcing a token refresh mid-cycle. The account is locked against interactive use (no Keychain credential), so it can only serve as a token issuer. New development work will use the high-tier web-billed account on the Mac.
What's Next
Pre-migration validation:
- Verify the 1-year OAUTH token on Lightsail is readable and not corrupted
- Confirm Lightsail can reach Claude endpoints with the stored token (health check script)
- Audit Lambda environment variables to ensure no API keys are being overwritten by recent deployments
- Test the new Mac Keychain credential with a dummy project operation (create/read file)
Migration sequence:
- Create new web-billed account (pending)
- Authenticate to new account on Mac via Claude Code desktop; credential auto-stores in Keychain
- Verify jada-ops/ directory remains accessible (iCloud sync, auth-independent)
- Downgrade old iOS account to lowest tier; confirm Lightsail token still works
- Update reference doc with final auth state and migration completion date
No Lambdas or Lightsail configurations require changes. The ticket-runner will continue using the old account's token; Lambdas will continue using Console API key. Both are unaffected by the Mac account tier shift.
```