Claude Code at Work: Solving the Enterprise Authentication Problem
How I built claude-switch to seamlessly switch Claude Code between personal and enterprise accounts, syncing plugins, MCP servers, and npm registries
I spend most of my day inside Claude Code. It has become my pair programmer, documentation writer, and thinking partner. But like many developers working at large companies, I hit a friction point early on: I have a personal Claude subscription that I use for side projects, and my employer provides enterprise access through an internal AI gateway. Switching between them was painful.
This post explains the architecture of Claude Code's configuration system, and how I built a workflow to switch between accounts seamlessly. If you use Claude Code at work and at home, this might save you hours of frustration.
The Problem: Two Worlds, One Tool
Claude Code stores its configuration in a hidden .claude directory in your home folder. This single directory holds everything: your authentication tokens, settings, plugins, conversation history, and more. The assumption baked into this design is that you are one person with one account.
But enterprise users live in two worlds:
- Personal: Direct Anthropic API access via OAuth, using your Claude Pro/Max subscription
- Work: Access through corporate gateways (Portkey, AWS Bedrock, internal proxies) with SSO authentication
When I wanted to switch from personal coding on a weekend to work on Monday, I had to manually juggle configuration files, clear cached tokens, and pray nothing broke. There had to be a better way.
Understanding Claude Code's Architecture
Before explaining the solution, let me walk you through how Claude Code actually stores its state. This is useful for anyone trying to debug authentication issues or customize their setup.
~/.claude/
|
|-- .credentials.json # OAuth tokens for personal account
|-- settings.json # User preferences and API helpers
|-- gateway-helper-config.json # Enterprise gateway configuration
|
|-- /tokens/ # Enterprise SSO tokens (encrypted)
| |-- jwt-*.enc # JWT tokens for each SSO provider
|
|-- /plugins/ # Installed plugins
| |-- config.json # Plugin registry
| |-- /repos/ # Plugin source code
|
|-- /projects/ # Per-project state and memory
|-- /logs/ # Gateway and session logs
|-- /todos/ # Task lists from sessions
|-- history.jsonl # Command history
The Key Files
.credentials.json - This is where personal OAuth tokens live. When you authenticate with claude login, the access token, refresh token, expiration time, and subscription type get stored here:
{
"claudeAiOauth": {
"accessToken": "sk-ant-oat01-...",
"refreshToken": "sk-ant-ort01-...",
"expiresAt": 1762386054209,
"scopes": ["user:inference", "user:profile"],
"subscriptionType": "max"
}
}
settings.json - This controls Claude Code's behavior. The critical field for enterprise users is apiKeyHelper, which points to a script that provides authentication tokens dynamically:
{
"apiKeyHelper": "node \"path/to/jwt-token-helper.js\"",
"statusLine": {
"type": "command",
"command": "..."
}
}
/tokens/jwt-*.enc - Enterprise SSO tokens are stored encrypted. On macOS they go into Keychain, on Windows into Credential Manager, and on Linux/WSL they use AES-256-GCM encrypted files. This is important: your enterprise credentials never sit in plain text.
The Solution: claude-switch
The solution to the dual-account problem is claude-switch - a shell script I wrote that handles the complete context switch between personal and corporate profiles. It does more than just swap authentication; it manages the entire development environment.
Here is what claude-switch handles:
- Claude authentication - Swaps
settings.jsonandgateway-helper-config.jsonbetween profiles - Plugin and MCP server sync - Keeps your extensions consistent across both profiles
- NPM registry - Switches between corporate Artifactory and public npmjs.org
- Token management - Backs up and restores encrypted SSO tokens for each profile
The Profile Structure
claude-switch stores profile configurations in a dedicated directory:
~/.claude/profiles/
|-- personal-settings.json # Personal Claude settings
|-- corporate-settings.json # Corporate Claude settings
|-- corporate-gateway-config.json # Gateway configuration
|-- tokens-personal/ # Backed up personal tokens
|-- tokens-corporate/ # Backed up corporate tokens
|-- npmrc-backup-personal # Personal npm config
|-- npmrc-backup-corporate # Corporate npm config
Automatic Plugin Sync
One of the most useful features is automatic plugin and MCP server synchronization. When you install a new plugin or configure an MCP server in one profile, claude-switch merges it into both profiles on the next switch.
The sync uses a simple Python script embedded in the shell script:
# Merge enabledPlugins (union of both)
personal_plugins = personal.get('enabledPlugins', {})
corporate_plugins = corporate.get('enabledPlugins', {})
merged_plugins = {**personal_plugins, **corporate_plugins}
# Merge mcpServers (union of both)
personal_mcp = personal.get('mcpServers', {})
corporate_mcp = corporate.get('mcpServers', {})
merged_mcp = {**personal_mcp, **corporate_mcp}
This means I never have to manually configure the same plugin twice. Install it once, switch profiles, and it is already there.
NPM Registry Switching
This was the feature I did not expect to need but now cannot live without. Many enterprises use private npm registries (Artifactory, Nexus, etc.) for internal packages and security scanning. When I switch to corporate mode, claude-switch also switches my npm registry:
# Corporate mode
npm config set registry "https://artifacts.example.com/artifactory/api/npm/npm-all/"
# Personal mode
npm config delete registry # Falls back to public npmjs.org
This prevents the common problem of accidentally publishing to the wrong registry or failing to install packages because you are pointing at the wrong source.
The Switch Flow
My workflow is now a single command:
Switching to Corporate
$ claude-switch corporate
Switching to CORPORATE Profile
----------------------------------------
[1/4] Backing up current configuration...
Backed up personal tokens
[2/4] Syncing plugins and MCP servers...
Synced enabledPlugins across profiles
Synced mcpServers across profiles
[3/4] Switching Claude authentication...
Loaded corporate settings
Configured corporate gateway
[4/4] Switching NPM registry...
NPM registry: Corporate Artifactory
----------------------------------------
CORPORATE Profile Active
----------------------------------------
Claude Code:
Gateway: https://live.ai.example.com
Auth: Corporate SSO (gateway-helper)
Billing: Corporate account
NPM:
Registry: Corporate Artifactory
Next: Run claude to start
Switching to Personal
$ claude-switch personal
Switching to PERSONAL Profile
----------------------------------------
[1/4] Backing up current configuration...
Backed up corporate tokens
[2/4] Syncing plugins and MCP servers...
Synced enabledPlugins across profiles
Synced mcpServers across profiles
[3/4] Switching Claude authentication...
Loaded personal settings
Removed corporate gateway config
[4/4] Switching NPM registry...
NPM registry: Public npmjs.org
----------------------------------------
PERSONAL Profile Active
----------------------------------------
Claude Code:
Auth: Direct Anthropic authentication
Billing: Your personal Claude subscription
NPM:
Registry: Public npmjs.org
Checking Current Status
Running claude-switch without arguments shows the current state:
$ claude-switch
Current Profile Status
----------------------------------------
Claude Profile: CORPORATE
Gateway: portkey
URL: https://live.ai.example.com
Auth: Corporate SSO
NPM Registry: CORPORATE
Registry: Corporate Artifactory
----------------------------------------
Usage: claude-switch [corporate|personal]
corporate Switch to corporate gateway + Artifactory
personal Switch to personal Anthropic account + public npm
The beauty is that both profiles can coexist. The script does not touch .credentials.json when switching, and personal Claude does not touch gateway-helper-config.json. They are completely isolated.
Token Storage Security
A common concern with SSO workflows is: where do my credentials actually live?
The gateway helper uses platform-native secure storage:
| Platform | Storage Method |
|---|---|
| macOS | Keychain Access |
| Windows | Windows Credential Manager |
| Linux/WSL | Encrypted files (~/.claude/tokens/) |
For Linux and WSL, tokens are encrypted with AES-256-GCM using a user-specific derived key. No external dependencies like libsecret are required. This was a deliberate design choice: we wanted it to work on minimal server environments and corporate-locked machines.
Troubleshooting Common Issues
After using this setup for months, here are the issues I have hit and how to fix them:
"Authentication failed" after it was working
SSO tokens expire. Usually the gateway helper auto-refreshes, but if something goes wrong:
# Clear cached tokens (Linux/WSL)
rm -rf ~/.claude/tokens/
# Switch back to corporate to re-authenticate
claude-switch corporate
Claude Code works but uses the wrong account
Check which profile is active:
claude-switch
This shows exactly which profile is loaded and which npm registry is configured.
Plugins missing after switching
If plugins are not syncing, ensure Python3 is installed. The sync script requires it:
# Check if Python3 is available
python3 --version
# If not installed on Ubuntu/Debian
sudo apt install python3
NPM installing from wrong registry
After switching profiles, verify your npm registry:
npm config get registry
If it shows the wrong registry, run claude-switch again to reset it.
Why This Matters
The broader point here is about developer experience in the age of AI tooling. As AI coding assistants become essential infrastructure, the friction of authentication and configuration will determine adoption.
Enterprise security teams rightfully want control over how AI tools access corporate resources. But if the developer experience is too painful, people will find workarounds - personal accounts on corporate machines, copy-pasting code into web interfaces, or just avoiding AI tools altogether.
claude-switch shows there is a middle path: keep enterprise security intact while making the developer experience seamless. Authentication tokens are managed automatically, plugins stay in sync, and even the npm registry follows along. Switching contexts is a single command that takes two seconds.
Conclusion
If you are using Claude Code at an enterprise and struggling with authentication, here is my advice:
- Understand the file structure - Know where Claude Code stores state so you can debug issues
- Build a profile switcher - Do not manually swap config files; automate it with a script like
claude-switch - Sync your extensions - Plugins and MCP servers should follow you across profiles automatically
- Do not forget npm - If your enterprise uses a private registry, include that in your switching logic
The goal is to make the AI tool disappear into your workflow. You should not be thinking about authentication or configuration; you should be thinking about the code you are writing. A few hours spent setting up proper infrastructure pays dividends every single day.
Get the Code
The full claude-switch script is open source and available on GitHub:
github.com/darshshah981/claude-profile-manager
Quick install:
curl -o ~/.local/bin/claude-switch https://raw.githubusercontent.com/darshshah981/claude-profile-manager/main/claude-switch
chmod +x ~/.local/bin/claude-switch
claude-switch init
The script is configurable - edit ~/.claude/profiles/config.sh to customize profile names, gateway URLs, npm registries, and which features to enable. The patterns here are portable across different AI coding assistants; it is really about wrapping any CLI tool with proper enterprise profile management.
More soon.