Skip to content

About

Switch accounts in the Claude Code CLI without /logout, reopening the browser, authorizing again, and so on. You save each account as a profile once, and from then on you alternate between them with a single command.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

7 Commits

Folders and files

Repository files navigation

claude-switch

🇧🇷 Português (abaixo) · 🇺🇸 English

Trocar de conta no Claude Code CLI sem precisar de /logout, reabrir o navegador, autorizar de novo, etc. Você salva cada conta como um profile uma vez, e a partir daí alterna entre elas com um único comando.

Por que existe

O fluxo nativo pra trocar de conta é:

  1. Digitar /logout dentro do Claude.
  2. Sair, rodar claude de novo.
  3. Esperar abrir o navegador.
  4. Fazer login na conta nova.
  5. Autorizar o OAuth.
  6. Repetir tudo se quiser voltar pra primeira conta.

Cansativo se você troca várias vezes por dia (ex.: conta pessoal vs. conta da empresa). O claude-switch faz isso em uma linha, sem browser, porque ele só rotaciona os tokens já válidos que o Claude Code guarda.

Como funciona por baixo

O Claude Code armazena o estado da conta em dois lugares:

O que Onde
Tokens OAuth (access + refresh) macOS Keychain — service Claude Code-credentials, account = $USER; Linux — ~/.claude/.credentials.json
Metadados da conta (oauthAccount, userID) ~/.claude.json

Um profile é só um JSON em ~/.claude/profiles/<nome>.json contendo um snapshot dos dois. O comando use restaura o snapshot — grava os tokens de volta no Keychain (macOS) ou em ~/.claude/.credentials.json (Linux) e substitui oauthAccount + userID em ~/.claude.json. O Claude Code refresca o access token sozinho se estiver vencido, então o navegador não precisa abrir de novo.

Por que o use sincroniza antes de trocar

O access token vale poucas horas, e o Claude Code rotaciona o refresh token a cada renovação: o token novo vai pro Keychain, o antigo deixa de valer. Um snapshot congelado envelhece — depois de algumas semanas o profile guarda um refresh token já consumido, e use acaba caindo no navegador.

Por isso, antes de sobrescrever as credenciais, o use re-salva os tokens da conta ativa no profile dela (match por accountUuid, com fallback pro e-mail). Cada troca deixa os dois profiles atualizados. Se você passar muito tempo sem alternar, rode claude-switch sync de vez em quando pra atualizar o profile ativo sem trocar de conta.

Os tokens continuam protegidos pelo Keychain do macOS (a senha da sua conta libera o acesso). No Linux, os tokens ficam no arquivo local ~/.claude/.credentials.json. Os profiles ficam em arquivos locais que você não deve versionar — eles contêm refresh tokens válidos.

Pré-requisitos

Obrigatórios (sem isso o script não roda)

Requisito Como verificar Como instalar / resolver
macOS ou Linux uname -s → Darwin ou Linux Windows não é suportado
bash command -v bash Já vem no macOS
security CLI (macOS) command -v security Já vem no macOS (parte do Security.framework)
jq jq --version brew install jq

Necessários pra ter o que gerenciar

Requisito Como verificar Como resolver
Claude Code CLI instalado claude --version npm i -g @anthropic-ai/claude-code
~/.claude.json criado ls ~/.claude.json Rode claude uma vez; o arquivo é criado na inicialização
Pelo menos uma conta logada Conseguir abrir claude sem cair no login Rode claude e complete o OAuth no navegador

Verificação automática

Use o comando doctor — checa tudo de uma vez e mostra exatamente o que falta:

claude-switch doctor

Saída esperada quando tudo está OK:

  [ok] macOS (26.5)
  [ok] bash
  [ok] security CLI
  [ok] jq (jq-1.7.1-apple)
  [ok] claude CLI (2.1.142)
  [ok] /Users/<seu_usuario>/.claude.json
  [ok] credenciais no Keychain (conta ativa: voce@exemplo.com)
  [ok] profiles salvos: 2 (em /Users/<seu_usuario>/.claude/profiles)
  [ok] ANTHROPIC_API_KEY não definida (OAuth no comando)

tudo ok pra rodar.

No Linux, a linha de credenciais aponta para ~/.claude/.credentials.json em vez do Keychain.

Sobre o check da ANTHROPIC_API_KEY: essa variável tem precedência sobre as credenciais OAuth em ambos os sistemas. Se ela estiver exportada no seu shell, o Claude Code autentica por ela e ignora o Keychain (macOS) ou o ~/.claude/.credentials.json (Linux) — ou seja, claude-switch use <nome> grava o profile corretamente mas não muda a conta que o Claude Code usa de fato. O doctor marca isso como [aviso] porque é um modo de falha silencioso. Se você precisa da key para scripts/SDK, carregue-a sob demanda (função de shell ou direnv) em vez de exportá-la globalmente.

Se aparecer [falta] em algum item obrigatório, o doctor sai com código de saída 1. Itens marcados [aviso] não bloqueiam o script em si, mas indicam coisas que você vai precisar antes de usar save (ex.: não estar logado em nenhuma conta).

O install.sh roda essas mesmas verificações antes de instalar.

Instalação

cd ~/Developer/claude-switch
./install.sh                  # auto-detecta o shell
./install.sh --shell=fish     # força fish (recomendado pra quem usa fish)
./install.sh --shell=zsh      # força zsh
./install.sh --shell=bash     # força bash

Importante para usuários de fish: o macOS guarda como "shell de login" o /bin/bash por padrão, mesmo se você abre o terminal direto no fish. Auto-detecção pode errar nesse caso — use --shell=fish explicitamente.

Importante para usuários Linux: ao final da instalação, o script recarrega o shell automaticamente quando possível para disponibilizar claude-switch no terminal atual.

O instalador:

  1. Roda todas as verificações de pré-requisitos (mesma coisa que claude-switch doctor).
  2. Copia o script para ~/.claude/bin/claude-switch (deixa executável).
  3. Cria ~/.claude/profiles/ se não existir.
  4. Adiciona ~/.claude/bin ao seu PATH:
    • fish: fish_add_path -U ~/.claude/bin (universal, persiste entre sessões).
    • zsh: adiciona uma linha ao ~/.zshrc (idempotente — só adiciona se não existir).
    • bash: adiciona ao ~/.bash_profile (se existir) ou ~/.bashrc.
  5. Mostra como recarregar o PATH.

Se preferir instalar à mão, é só copiar claude-switch pra qualquer lugar no PATH e dar chmod +x.

Uso

Primeira vez (registro de cada conta)

Esse passo só acontece uma vez por conta. Depois você nunca mais vê o navegador (até o refresh token expirar, o que demora bastante).

# 1) Você já está logado em uma conta (ex.: pessoal). Salve como profile:
claude-switch save pessoal

# 2) Saia da conta atual e logue na conta nova:
claude-switch logout
claude               # abre o navegador, faz login na outra conta

# 3) Confirme que pegou a conta certa e salve como profile:
claude-switch current
claude-switch save trabalho

Deslogue do claude.ai antes do passo 2. Se o navegador ainda estiver autenticado na conta anterior, o OAuth reautoriza aquela sessão sem perguntar nada e você acaba salvando a mesma conta duas vezes. Faça logout em https://claude.ai (ou use uma janela anônima / outro perfil do navegador) antes de rodar claude. O claude-switch current no passo 3 confirma qual conta veio de fato.

Uso recorrente (o que você vai fazer de fato)

claude-switch use pessoal      # ativa a conta pessoal
claude-switch use trabalho     # ativa a conta de trabalho
claude-switch sync             # atualiza o profile da conta ativa com os tokens de agora
claude-switch list             # lista profiles ('*' marca o ativo) + validade dos tokens
claude-switch current          # mostra qual conta está logada agora

O list mostra o estado dos tokens de cada profile:

* pessoal              voce@exemplo.com                 válido
  trabalho             voce@empresa.com                 renovável
  cliente-x            voce@cliente.com                 EXPIRADO
Estado Significado
válido access token ainda vale — use é instantâneo
renovável access token venceu, mas o refresh token renova sem navegador
EXPIRADO refresh token também venceu — use vai cair no navegador; refaça o save depois de logar
formato antigo profile salvo antes do campo refreshTokenExpiresAt existir; pode estar vencido — refaça o save

Depois de use, é só rodar claude normalmente — já vai estar na conta certa.

Outros comandos

claude-switch logout           # remove os tokens do Keychain/arquivo local (profiles ficam)
claude-switch rm <nome>        # apaga um profile salvo
claude-switch help             # mostra a ajuda

Referência rápida dos comandos

Comando O que faz
claude-switch save <nome> Salva a conta atualmente logada como profile <nome>
claude-switch use <nome> Ativa o profile <nome> (sem browser); sincroniza o profile da conta ativa antes
claude-switch sync Atualiza o profile da conta ativa com os tokens atuais (sem trocar de conta)
claude-switch list (ou ls) Lista todos os profiles, o e-mail e a validade dos tokens de cada
claude-switch current Mostra qual conta está ativa agora
claude-switch logout Limpa os tokens do Keychain/arquivo local (não apaga profiles)
claude-switch rm <nome> Apaga o profile <nome> do disco
claude-switch doctor Verifica pré-requisitos e estado do ambiente
claude-switch help Mostra a ajuda

Cenários comuns

Trocar de conta no meio do dia:

claude-switch use trabalho
claude

Atualizar um profile (porque o token foi renovado e você quer salvar o estado novo):

# basta dar save de novo com o mesmo nome — sobrescreve.
claude-switch save trabalho

Logar em uma terceira conta:

# deslogue de claude.ai no navegador antes, senão o OAuth reusa a conta atual
claude-switch logout
claude              # navegador abre, loga na conta nova
claude-switch current       # confirme que veio a conta certa
claude-switch save cliente-x

Recuperar um profile com token expirado:

claude-switch list          # confirma qual está EXPIRADO
# deslogue de claude.ai no navegador
claude-switch logout
claude                      # login na conta daquele profile
claude-switch current       # confirme a conta
claude-switch save trabalho # sobrescreve o profile com tokens vivos

Ver se você está na conta certa antes de mandar uma pergunta cara:

claude-switch current

Cuidados

  • Não versione ~/.claude/profiles/. Os arquivos ali dentro contêm refreshToken válidos — quem tiver o arquivo loga como você. O .gitignore deste repositório já bloqueia, mas se você mover os profiles pra outro lugar, lembre disso.
  • No Linux, não versione ~/.claude/.credentials.json. Esse arquivo também contém tokens válidos.
  • Backup: se você quiser passar uma conta pra outra máquina sua, copie o JSON do profile via canal seguro (AirDrop, scp). Não cole em chat/email.
  • Refresh token expira: o refresh token vale ~30 dias e é rotacionado a cada renovação. O use mantém o profile ativo fresco automaticamente, mas um profile que ficou meses parado vence — list e doctor marcam isso. Nesse caso use ainda restaura o estado, o claude pede login pelo navegador, e aí você roda claude-switch save <nome> pra recuperar o profile.
  • Conta atual não salva: se você der use em um profile sem ter salvado a conta atualmente ativa, o script avisa antes — você pode cancelar com Ctrl-C e dar save primeiro.

Desinstalação

cd ~/Developer/claude-switch
./uninstall.sh

Isso remove só o binário em ~/.claude/bin/claude-switch. Os profiles em ~/.claude/profiles/ ficam (apague à mão se quiser). A linha de PATH adicionada ao seu shell rc também fica — remova manualmente se quiser.

Estrutura do projeto

~/Developer/claude-switch/
├── claude-switch          # o script em si
├── README.md              # este documento
├── install.sh             # instalador
├── uninstall.sh           # desinstalador
└── .gitignore             # garante que profiles não vazem se você versionar

Troubleshooting

jq não encontrado → brew install jq.

sem credenciais ativas no Keychain ou sem credenciais ativas em ~/.claude/.credentials.json ao dar save → você não está logado. Rode claude e faça login primeiro.

~/.claude.json não encontrado → você nunca rodou claude nessa máquina. Rode uma vez pra ele inicializar.

use ativou o profile mas o Claude continua na conta antiga → certifique-se de que o processo claude não estava aberto (ele só relê as credenciais ao iniciar). Saia e rode de novo.

use funciona, mas o Claude pede login no navegador toda vez → o profile guarda um refresh token vencido ou já consumido. Rode claude-switch list (ou doctor) pra confirmar: profiles marcados EXPIRADO ou formato antigo precisam de um save novo depois do login. A partir daí o use mantém os tokens frescos sozinho.

use só imprimiu o aviso e não abriu o navegador → é o comportamento esperado. O use apenas grava as credenciais; quem abre o navegador é o claude no próximo start (ou o /login dentro de uma sessão aberta).

Fiz login pra recuperar um profile, mas caí na conta errada → o navegador ainda estava autenticado na conta anterior e o OAuth reautorizou aquela sessão sem perguntar. Deslogue em https://claude.ai (ou use uma janela anônima) e repita. Use claude-switch current pra conferir antes do save — comparar o e-mail é mais confiável que assumir qual conta o navegador escolheu.

Quero rodar comandos diferentes em sessões diferentes ao mesmo tempo (sem mexer no estado global) → não dá com este script (o Claude Code lê de um único lugar). Pra esse caso, melhor usar perfis separados de macOS ou containers.


claude-switch (English)

Switch accounts in the Claude Code CLI without /logout, reopening the browser, authorizing again, and so on. You save each account as a profile once, and from then on you alternate between them with a single command.

Why it exists

The native account-switching flow is:

  1. Type /logout inside Claude.
  2. Quit, run claude again.
  3. Wait for the browser to open.
  4. Log into the new account.
  5. Authorize OAuth.
  6. Repeat everything if you want to go back to the first account.

Tiring if you switch several times a day (e.g. personal account vs. company account). claude-switch does it in one line, with no browser, because it just rotates the already valid tokens that Claude Code stores.

How it works under the hood

Claude Code stores the account state in two places:

What Where
OAuth tokens (access + refresh) macOS Keychain — service Claude Code-credentials, account = $USER; Linux — ~/.claude/.credentials.json
Account metadata (oauthAccount, userID) ~/.claude.json

A profile is just a JSON file at ~/.claude/profiles/<name>.json holding a snapshot of both. The use command restores the snapshot — it writes the tokens back to the Keychain (macOS) or to ~/.claude/.credentials.json (Linux) and replaces oauthAccount + userID in ~/.claude.json. Claude Code refreshes the access token on its own if it has expired, so the browser doesn't have to open again.

Why use syncs before switching

The access token is valid for a few hours, and Claude Code rotates the refresh token on every renewal: the new token goes to the Keychain, the old one stops working. A frozen snapshot ages — after a few weeks the profile holds an already-consumed refresh token, and use ends up falling back to the browser.

That's why, before overwriting the credentials, use re-saves the active account's tokens into its own profile (matched by accountUuid, falling back to the email). Every switch leaves both profiles up to date. If you go a long time without alternating, run claude-switch sync once in a while to refresh the active profile without switching accounts.

The tokens remain protected by the macOS Keychain (your account password unlocks access). On Linux, the tokens live in the local file ~/.claude/.credentials.json. Profiles live in local files that you should not commit — they contain valid refresh tokens.

Requirements

Mandatory (the script won't run without them)

Requirement How to check How to install / fix
macOS or Linux uname -s → Darwin or Linux Windows is not supported
bash command -v bash Ships with macOS
security CLI (macOS) command -v security Ships with macOS (part of Security.framework)
jq jq --version brew install jq

Needed so there's something to manage

Requirement How to check How to fix
Claude Code CLI installed claude --version npm i -g @anthropic-ai/claude-code
~/.claude.json created ls ~/.claude.json Run claude once; the file is created at startup
At least one logged-in account Being able to open claude without hitting the login flow Run claude and complete the OAuth in the browser

Automatic check

Use the doctor command — it checks everything at once and shows exactly what's missing:

claude-switch doctor

Expected output when everything is OK:

  [ok] macOS (26.5)
  [ok] bash
  [ok] security CLI
  [ok] jq (jq-1.7.1-apple)
  [ok] claude CLI (2.1.142)
  [ok] /Users/<your_user>/.claude.json
  [ok] credentials in Keychain (active account: you@example.com)
  [ok] saved profiles: 2 (in /Users/<your_user>/.claude/profiles)
  [ok] ANTHROPIC_API_KEY not set (OAuth in use)

all good to go.

On Linux, the credentials line points to ~/.claude/.credentials.json instead of the Keychain.

About the ANTHROPIC_API_KEY check: this variable takes precedence over the OAuth credentials on both systems. If it's exported in your shell, Claude Code authenticates with it and ignores the Keychain (macOS) or ~/.claude/.credentials.json (Linux) — meaning claude-switch use <name> writes the profile correctly but doesn't change the account Claude Code actually uses. doctor flags this as a warning because it's a silent failure mode. If you need the key for scripts/SDK, load it on demand (a shell function or direnv) instead of exporting it globally.

If any mandatory item shows up as missing, doctor exits with status code 1. Items marked as warnings don't block the script itself, but they point to things you'll need before using save (e.g. not being logged into any account).

install.sh runs these same checks before installing.

Installation

cd ~/Developer/claude-switch
./install.sh                  # auto-detects the shell
./install.sh --shell=fish     # forces fish (recommended for fish users)
./install.sh --shell=zsh      # forces zsh
./install.sh --shell=bash     # forces bash

Important for fish users: macOS keeps /bin/bash as the "login shell" by default, even if you open the terminal straight into fish. Auto-detection can get it wrong in that case — pass --shell=fish explicitly.

Important for Linux users: at the end of the installation, the script reloads the shell automatically when possible so claude-switch becomes available in the current terminal.

The installer:

  1. Runs all the prerequisite checks (same thing as claude-switch doctor).
  2. Copies the script to ~/.claude/bin/claude-switch (making it executable).
  3. Creates ~/.claude/profiles/ if it doesn't exist.
  4. Adds ~/.claude/bin to your PATH:
    • fish: fish_add_path -U ~/.claude/bin (universal, persists across sessions).
    • zsh: adds a line to ~/.zshrc (idempotent — only adds it if not present).
    • bash: adds to ~/.bash_profile (if it exists) or ~/.bashrc.
  5. Shows how to reload your PATH.

If you'd rather install by hand, just copy claude-switch anywhere on your PATH and chmod +x it.

Usage

First time (registering each account)

This step happens only once per account. After that you never see the browser again (until the refresh token expires, which takes a while).

# 1) You're already logged into one account (e.g. personal). Save it as a profile:
claude-switch save personal

# 2) Log out of the current account and log into the new one:
claude-switch logout
claude               # opens the browser, log into the other account

# 3) Confirm you got the right account and save it as a profile:
claude-switch current
claude-switch save work

Log out of claude.ai before step 2. If the browser is still authenticated with the previous account, OAuth re-authorizes that session without asking anything and you end up saving the same account twice. Log out at https://claude.ai (or use a private window / another browser profile) before running claude. claude-switch current in step 3 confirms which account actually came through.

Day-to-day usage (what you'll actually do)

claude-switch use personal     # activates the personal account
claude-switch use work         # activates the work account
claude-switch sync             # updates the active account's profile with the current tokens
claude-switch list             # lists profiles ('*' marks the active one) + token validity
claude-switch current          # shows which account is logged in right now

list shows each profile's token state:

* personal             you@example.com                  valid
  work                 you@company.com                  renewable
  client-x             you@client.com                   EXPIRED
State Meaning
valid access token still good — use is instant
renewable access token expired, but the refresh token renews it without a browser
EXPIRED the refresh token expired too — use will fall back to the browser; redo the save after logging in
old format profile saved before the refreshTokenExpiresAt field existed; it may be expired — redo the save

After use, just run claude as usual — it'll already be on the right account.

Other commands

claude-switch logout           # removes the tokens from the Keychain/local file (profiles stay)
claude-switch rm <name>        # deletes a saved profile
claude-switch help             # shows the help

Command quick reference

Command What it does
claude-switch save <name> Saves the currently logged-in account as profile <name>
claude-switch use <name> Activates profile <name> (no browser); syncs the active account's profile first
claude-switch sync Updates the active account's profile with the current tokens (without switching accounts)
claude-switch list (or ls) Lists all profiles, plus each one's email and token validity
claude-switch current Shows which account is active right now
claude-switch logout Clears the tokens from the Keychain/local file (doesn't delete profiles)
claude-switch rm <name> Deletes profile <name> from disk
claude-switch doctor Checks prerequisites and the state of the environment
claude-switch help Shows the help

Common scenarios

Switching accounts mid-day:

claude-switch use work
claude

Updating a profile (because the token was renewed and you want to save the new state):

# just save again with the same name — it overwrites.
claude-switch save work

Logging into a third account:

# log out of claude.ai in the browser first, otherwise OAuth reuses the current account
claude-switch logout
claude              # browser opens, log into the new account
claude-switch current       # confirm the right account came through
claude-switch save client-x

Recovering a profile with an expired token:

claude-switch list          # confirm which one is EXPIRED
# log out of claude.ai in the browser
claude-switch logout
claude                      # log into that profile's account
claude-switch current       # confirm the account
claude-switch save work     # overwrite the profile with live tokens

Checking whether you're on the right account before sending an expensive prompt:

claude-switch current

Caveats

  • Don't commit ~/.claude/profiles/. The files in there contain valid refreshTokens — whoever has the file logs in as you. This repository's .gitignore already blocks it, but if you move the profiles somewhere else, keep that in mind.
  • On Linux, don't commit ~/.claude/.credentials.json. That file also contains valid tokens.
  • Backup: if you want to move an account to another machine of yours, copy the profile JSON over a secure channel (AirDrop, scp). Don't paste it into chat/email.
  • Refresh tokens expire: the refresh token lasts ~30 days and is rotated on every renewal. use keeps the active profile fresh automatically, but a profile that sat idle for months will expire — list and doctor flag that. In that case use still restores the state, claude asks for a browser login, and then you run claude-switch save <name> to recover the profile.
  • Current account not saved: if you use a profile without having saved the currently active account, the script warns you first — you can cancel with Ctrl-C and save it first.

Uninstalling

cd ~/Developer/claude-switch
./uninstall.sh

This removes only the binary at ~/.claude/bin/claude-switch. The profiles in ~/.claude/profiles/ stay (delete them by hand if you want). The PATH line added to your shell rc also stays — remove it manually if you want.

Project structure

~/Developer/claude-switch/
├── claude-switch          # the script itself
├── README.md              # this document
├── install.sh             # installer
├── uninstall.sh           # uninstaller
└── .gitignore             # makes sure profiles don't leak if you commit

Troubleshooting

jq not found → brew install jq.

no active credentials in Keychain or no active credentials in ~/.claude/.credentials.json when running save → you're not logged in. Run claude and log in first.

~/.claude.json not found → you've never run claude on this machine. Run it once so it initializes.

use activated the profile but Claude is still on the old account → make sure the claude process wasn't running (it only re-reads the credentials at startup). Quit and run it again.

use works, but Claude asks for a browser login every time → the profile holds an expired or already-consumed refresh token. Run claude-switch list (or doctor) to confirm: profiles marked EXPIRED or old format need a fresh save after logging in. From then on use keeps the tokens fresh on its own.

use only printed the warning and didn't open the browser → that's the expected behavior. use only writes the credentials; the browser is opened by claude on its next start (or by /login inside an open session).

I logged in to recover a profile, but ended up on the wrong account → the browser was still authenticated with the previous account and OAuth re-authorized that session without asking. Log out at https://claude.ai (or use a private window) and try again. Use claude-switch current to check before the save — comparing the email is more reliable than assuming which account the browser picked.

I want to run different commands in different sessions at the same time (without touching the global state) → not possible with this script (Claude Code reads from a single place). For that case, separate macOS profiles or containers are a better fit.

About

Switch accounts in the Claude Code CLI without /logout, reopening the browser, authorizing again, and so on. You save each account as a profile once, and from then on you alternate between them with a single command.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Contributors

Languages