Files
ccs/src/codex-auth/codex-account-identity.ts
T
Tam Nhu Tran 358b703d98 feat(codex-auth): add profile registry + storage foundation
Adds the storage substrate for ccsx auth profile isolation.
Each Codex profile gets its own CODEX_HOME dir under
~/.ccs/codex-instances/<name>/ with isolated auth.json and
history.jsonl; config.toml is shared via symlink to ~/.codex/config.toml
so two terminals can run two Codex accounts simultaneously without
duplicating user config.

- CodexProfileRegistry (YAML, atomic write tmp.<pid>.<rand> + rename,
  orphan cleanup, full CRUD + default pointer)
- decode-id-token: pure base64 JWT decoder for OpenAI id_token,
  reads nested https://api.openai.com/auth claims (chatgpt_plan_type,
  chatgpt_account_id) and dual-path email
- ensureSharedConfigSymlink: self-healing, idempotent, overwrites
  stale entries with stderr warning
- 45 unit tests, all green

Foundation only — no CLI, no runtime injection, no dashboard.
Subsequent commits wire those in.
2026-05-17 14:44:07 -04:00

37 lines
1.1 KiB
TypeScript

import * as fs from 'fs';
import { createLogger } from '../services/logging';
import { decodeIdToken } from './decode-id-token';
import type { CodexAccountIdentity } from './types';
const logger = createLogger('codex-auth:identity');
interface AuthJson {
tokens?: {
id_token?: string;
};
}
/**
* Read auth.json from disk and extract display-safe identity fields.
* Returns {} on any error (missing file, bad JSON, missing token, decode failure).
* Never throws.
*/
export function decodeAccountIdentity(authJsonPath: string): CodexAccountIdentity {
try {
const raw = fs.readFileSync(authJsonPath, 'utf8');
const parsed = JSON.parse(raw) as AuthJson;
const idToken = parsed?.tokens?.id_token;
if (typeof idToken !== 'string' || idToken.length === 0) {
return {};
}
return decodeIdToken(idToken);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
logger.warn(
'codex-auth.identity.decode-failed',
`Failed to decode account identity from ${authJsonPath}: ${msg}`
);
return {};
}
}