Documentation Index Fetch the complete documentation index at: https://mintlify.com/ndycode/codex-multi-auth/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Codex Multi-Auth implements a multi-account OAuth system that allows you to authenticate and manage multiple OpenAI accounts simultaneously. This enables seamless account rotation, load distribution, and quota management across your team’s accounts.
OAuth Flow Architecture
PKCE (Proof Key for Code Exchange)
The plugin uses PKCE (RFC 7636) for secure OAuth authentication without client secrets:
PKCE Implementation
The PKCE flow is implemented in lib/auth/auth.ts:220-243:
export async function createAuthorizationFlow (
options ?: AuthorizationFlowOptions
) : Promise < AuthorizationFlow > {
const pkce = await generatePKCE (); // S256 challenge
const state = createState (); // Random nonce
const url = new URL ( AUTHORIZE_URL );
url . searchParams . set ( 'code_challenge' , pkce . challenge );
url . searchParams . set ( 'code_challenge_method' , 'S256' );
url . searchParams . set ( 'state' , state );
// Force fresh login when adding multiple accounts
if ( options ?. forceNewLogin ) {
url . searchParams . set ( 'prompt' , 'login' );
}
return { pkce , state , url: url . toString () };
}
Key security features:
S256 hashing of code verifier prevents interception attacks
State parameter prevents CSRF attacks
Local callback server (127.0.0.1:1455) keeps tokens on your machine
No client secret required or stored
Token Management
Token Structure
Each authenticated account stores:
Account Storage
Example Storage
interface ManagedAccount {
index : number ;
accountId ?: string ; // Extracted from JWT
email ?: string ; // Extracted from JWT
refreshToken : string ; // Long-lived refresh token
access ?: string ; // Short-lived access token
expires ?: number ; // Access token expiry (ms)
enabled ?: boolean ; // Account enabled state
addedAt : number ; // First added timestamp
lastUsed : number ; // Last request timestamp
rateLimitResetTimes : Record < string , number >;
coolingDownUntil ?: number ;
}
JWT Decoding
Account identity is extracted from JWT tokens (lib/auth/auth.ts:139-154):
export function decodeJWT ( token : string ) : JWTPayload | null {
try {
const parts = token . split ( '.' );
if ( parts . length !== 3 ) return null ;
const payload = parts [ 1 ];
const normalized = payload . replace ( /-/ g , '+' ). replace ( /_/ g , '/' );
const padded = normalized . padEnd (
normalized . length + (( 4 - ( normalized . length % 4 )) % 4 ),
'='
);
const decoded = Buffer . from ( padded , 'base64' ). toString ( 'utf-8' );
return JSON . parse ( decoded );
} catch {
return null ;
}
}
Extracted fields include:
sub → accountId
email → email
exp → token expiry validation
Token Refresh
Automatic Refresh
Access tokens are automatically refreshed before expiry using the refresh queue to prevent race conditions:
export async function refreshAccessToken (
refreshToken : string
) : Promise < TokenResult > {
const response = await fetch ( TOKEN_URL , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/x-www-form-urlencoded' },
body: new URLSearchParams ({
grant_type: 'refresh_token' ,
refresh_token: refreshToken ,
client_id: CLIENT_ID ,
}),
});
if ( ! response . ok ) {
return {
type: 'failed' ,
reason: 'http_error' ,
statusCode: response . status
};
}
const json = await response . json ();
return {
type: 'success' ,
access: json . access_token ,
refresh: json . refresh_token ?? refreshToken ,
expires: Date . now () + json . expires_in * 1000 ,
};
}
Refresh Guardian
The Proactive Refresh Guardian (lib/proactive-refresh.ts) refreshes tokens before they expire:
Refreshes when < 5 minutes remaining
Uses refresh lease to prevent concurrent refreshes
Falls back to on-demand refresh if proactive refresh fails
Multi-Account Management
Adding Accounts
Add multiple accounts using:
# Add first account
codex auth login
# Add additional accounts (forces fresh login)
codex auth login --force-new-login
The --force-new-login flag sets prompt=login to prevent browser session reuse.
Account Deduplication
Accounts are deduplicated by:
Refresh token (exact match)
Account ID (from JWT)
Email (case-insensitive, normalized)
function normalizeEmailKey ( email : string | undefined ) : string | null {
if ( ! email ) return null ;
return email . trim (). toLowerCase ();
}
Storage Locations
Project-Scoped
Global Fallback
~/.codex/multi-auth/projects/<project-key>/openai-codex-accounts.json
Automatically detected by walking up from current directory to find:
.git directory
package.json
Other project markers
~/.codex/multi-auth/openai-codex-accounts.json
Used when no project root is detected.
Security Considerations
Tokens are stored in plain JSON files. Ensure proper file permissions:
Unix/Linux/macOS: chmod 600 (owner read/write only)
Windows: ACL restricts to current user
Token Redaction
Sensitive parameters are automatically redacted in logs:
const OAUTH_SENSITIVE_QUERY_PARAMS = [
'state' ,
'code' ,
'code_challenge' ,
'code_verifier' ,
];
export function redactOAuthUrlForLog ( rawUrl : string ) : string {
const parsed = new URL ( rawUrl );
for ( const key of OAUTH_SENSITIVE_QUERY_PARAMS ) {
if ( parsed . searchParams . has ( key )) {
parsed . searchParams . set ( key , '<redacted>' );
}
}
return parsed . toString ();
}
OAuth Configuration
The plugin uses these OAuth constants (lib/auth/auth.ts:7-12):
export const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann" ;
export const AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize" ;
export const TOKEN_URL = "https://auth.openai.com/oauth/token" ;
export const REDIRECT_URI = "http://127.0.0.1:1455/auth/callback" ;
export const SCOPE = "openid profile email offline_access" ;
Scope breakdown:
openid - OpenID Connect authentication
profile - User profile information
email - User email address
offline_access - Refresh token grant
Account Rotation Learn how accounts are selected and rotated based on health scores
Session Affinity Understand how sessions stick to specific accounts
Quota Management See how quotas are tracked and managed per account
Commands Reference View all available CLI commands