Imported from reason-machines/codex-skills (
skills/codex-auth-helper-chrome-extension/SKILL.md). Install upstream withnpx skills add reason-machines/codex-skills --skill codex-auth-helper-chrome-extension. Copyright stays with the author.
Codex Auth Helper Chrome Extension
Skill by ara.so — Codex Skills collection.
Overview
Codex Auth Helper is a Chrome extension that securely exports your logged-in ChatGPT session credentials and generates a Codex-compliant auth.json configuration file. All processing happens 100% locally in the browser with no data sent to external servers.
Key Features:
- Automatic ChatGPT session detection
- Real-time token expiration countdown
- Synthetic JWT id_token generation for Codex authentication
- Local-only processing (no server uploads)
- Support for Free/Plus/Pro account types
Installation
Developer Mode Installation
- Clone or download the repository:
git clone https://github.com/zhishile/codex-auth-helper.git
cd codex-auth-helper
-
Open Chrome and navigate to
chrome://extensions/ -
Enable Developer mode (toggle in top-right corner)
-
Click Load unpacked (top-left)
-
Select the
extensionfolder from the cloned repository -
Pin the extension to your toolbar for easy access
Verification
After installation, you should see the Codex Auth Helper icon in your Chrome toolbar. The extension requires these permissions:
downloads- to save the generated auth.json filehttps://chatgpt.com/*- to read session credentials
Usage
Exporting auth.json
-
Login to ChatGPT: Navigate to https://chatgpt.com/ and ensure you're logged in
-
Open Extension: Click the Codex Auth Helper icon in your toolbar
-
Verify Session: The popup will automatically detect your session and display:
- Your profile avatar
- Email address
- Subscription tier (Free/Plus/Pro)
- Token expiration countdown
-
Generate Config: Click "生成并保存 auth.json" (Generate and Save auth.json)
-
Download: The file will automatically download to your default downloads folder
auth.json Structure
The generated file follows this format:
{
"user": "your-email@example.com",
"access_token": "eyJhbGc...",
"id_token": "synthetic-jwt-token",
"expires_at": 1234567890,
"account_type": "plus"
}
Fields:
user: Your ChatGPT account emailaccess_token: Session access token from cookiesid_token: Synthetically generated JWT for Codex authenticationexpires_at: Unix timestamp when the token expiresaccount_type:free,plus, orpro
Extension Architecture
File Structure
extension/
├── manifest.json # Extension configuration (Manifest V3)
├── popup.html # UI interface
├── popup.js # Frontend logic
├── background.js # Service worker for token processing
├── styles.css # Glassmorphism UI styling
└── icons/ # Extension icons
Key Components
manifest.json
{
"manifest_version": 3,
"name": "Codex 认证助手",
"version": "1.0.0",
"permissions": ["downloads"],
"host_permissions": ["https://chatgpt.com/*"],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html"
}
}
Session Detection (popup.js pattern)
// Check ChatGPT login status
async function checkAuthStatus() {
try {
const response = await fetch('https://chatgpt.com/api/auth/session');
const data = await response.json();
if (data.user) {
// User is logged in
displayUserInfo({
email: data.user.email,
avatar: data.user.image,
accountType: data.user.account_type || 'free'
});
} else {
// Show login prompt
showLoginButton();
}
} catch (error) {
console.error('Auth check failed:', error);
}
}
Token Extraction (background.js pattern)
// Extract tokens from cookies
chrome.cookies.getAll({
domain: '.chatgpt.com'
}, (cookies) => {
const accessToken = cookies.find(c => c.name === '__Secure-next-auth.session-token');
if (accessToken) {
// Generate synthetic JWT
const syntheticToken = generateSyntheticJWT(accessToken.value);
// Create auth.json structure
const authConfig = {
user: userEmail,
access_token: accessToken.value,
id_token: syntheticToken,
expires_at: Math.floor(accessToken.expirationDate),
account_type: accountType
};
// Trigger download
downloadAuthFile(authConfig);
}
});
Secure Local Download
function downloadAuthFile(authData) {
// Convert to JSON
const jsonString = JSON.stringify(authData, null, 2);
// Create data URL (no blob storage)
const dataUrl = 'data:application/json;charset=utf-8,' +
encodeURIComponent(jsonString);
// Trigger download
chrome.downloads.download({
url: dataUrl,
filename: 'auth.json',
saveAs: true
});
}
Configuration
Customizing Export Behavior
You can modify popup.js to customize the export behavior:
// Custom filename with timestamp
const timestamp = new Date().toISOString().split('T')[0];
const filename = `auth_${timestamp}.json`;
chrome.downloads.download({
url: dataUrl,
filename: filename,
saveAs: true // Set to false for automatic download
});
Token Refresh Handling
// Check token expiration
function checkTokenExpiry(expiresAt) {
const now = Math.floor(Date.now() / 1000);
const timeLeft = expiresAt - now;
if (timeLeft < 3600) {
// Less than 1 hour remaining
showExpiryWarning('Token expires soon! Please re-login.');
}
// Update countdown display
updateCountdown(timeLeft);
}
Integration with Codex
Using the Exported auth.json
After exporting, place auth.json in your Codex project directory:
# Typical Codex project structure
my-codex-project/
├── auth.json # Place exported file here
├── codex.config.js
└── src/
Environment Variable Alternative
For sensitive environments, convert auth.json to environment variables:
# .env
CODEX_USER=your-email@example.com
CODEX_ACCESS_TOKEN=eyJhbGc...
CODEX_ID_TOKEN=synthetic-jwt-token
CODEX_ACCOUNT_TYPE=plus
Then reference in your Codex configuration:
// codex.config.js
module.exports = {
auth: {
user: process.env.CODEX_USER,
access_token: process.env.CODEX_ACCESS_TOKEN,
id_token: process.env.CODEX_ID_TOKEN,
account_type: process.env.CODEX_ACCOUNT_TYPE
}
};
Troubleshooting
Extension Not Detecting Session
Problem: Popup shows "Please login" even when logged into ChatGPT
Solutions:
- Refresh the ChatGPT tab and reopen the extension
- Clear ChatGPT cookies and re-login
- Check if you're on the correct domain (
chatgpt.comnotchat.openai.com) - Verify extension has permission to access
https://chatgpt.com/*
// Debug session detection
chrome.cookies.getAll({domain: '.chatgpt.com'}, (cookies) => {
console.log('Found cookies:', cookies.map(c => c.name));
});
Token Expired Immediately
Problem: Generated auth.json shows token already expired
Solution: Re-login to ChatGPT to get fresh tokens:
// Check cookie expiration before export
if (cookie.expirationDate && cookie.expirationDate < Date.now() / 1000) {
alert('Session expired. Please re-login to ChatGPT.');
return;
}
Download Not Starting
Problem: "Generate and Save" button doesn't trigger download
Solutions:
- Check Chrome download permissions
- Verify
downloadspermission in manifest.json - Check browser console for errors:
chrome.downloads.download({
url: dataUrl,
filename: 'auth.json',
saveAs: true
}, (downloadId) => {
if (chrome.runtime.lastError) {
console.error('Download failed:', chrome.runtime.lastError);
} else {
console.log('Download started:', downloadId);
}
});
Permission Denied Errors
Problem: Extension can't read cookies or trigger downloads
Solution: Reinstall with correct permissions:
{
"permissions": ["downloads"],
"host_permissions": ["https://chatgpt.com/*"],
"optional_permissions": ["cookies"]
}
Security Best Practices
Safe Storage of auth.json
# Add to .gitignore
echo "auth.json" >> .gitignore
# Set restrictive permissions (Unix/Mac)
chmod 600 auth.json
Verify Extension Integrity
Before using, verify the extension only contains expected files:
# Check for unexpected network requests
grep -r "fetch\|XMLHttpRequest" extension/
grep -r "http" extension/ | grep -v "chatgpt.com"
Token Rotation
Implement automatic token refresh reminders:
// Set up expiry notification
function scheduleExpiryCheck(expiresAt) {
const checkTime = (expiresAt - Math.floor(Date.now() / 1000) - 3600) * 1000;
setTimeout(() => {
chrome.notifications.create({
type: 'basic',
iconUrl: 'icons/icon128.png',
title: 'Codex Auth Helper',
message: 'Your ChatGPT token will expire soon. Please export a new auth.json.'
});
}, checkTime);
}
Common Patterns
Batch Export for Multiple Accounts
// Export with account identifier
function exportWithIdentifier(email) {
const sanitizedEmail = email.replace('@', '_at_').replace('.', '_');
const filename = `auth_${sanitizedEmail}.json`;
chrome.downloads.download({
url: dataUrl,
filename: filename,
saveAs: false
});
}
Validation Before Export
function validateAuthData(authData) {
const required = ['user', 'access_token', 'id_token', 'expires_at'];
for (const field of required) {
if (!authData[field]) {
throw new Error(`Missing required field: ${field}`);
}
}
if (authData.expires_at < Date.now() / 1000) {
throw new Error('Token already expired');
}
return true;
}
Auto-Export on Login Detection
// Monitor for login events
chrome.webNavigation.onCompleted.addListener((details) => {
if (details.url.includes('chatgpt.com')) {
checkAuthStatus().then((isLoggedIn) => {
if (isLoggedIn) {
// Optionally auto-export
showNotification('ChatGPT session detected. Ready to export.');
}
});
}
});