Configuração¶
A precedência de configuração é: flag de CLI → variável de ambiente → arquivo .env → default compilado. Uma variável já exportada no ambiente ganha do arquivo, sempre. Em produção, use variáveis de ambiente.
Onde o arquivo é procurado¶
O CLI lê um arquivo de ambiente. O primeiro candidato que existir vence, e nada é mesclado:
| Ordem | Candidato | Observação |
|---|---|---|
| 1 | o arquivo indicado por CA_CLI_ENV_FILE |
Escape hatch explícito, por invocação. Se a variável estiver definida e o arquivo não puder ser lido, o CLI falha — nunca cai em silêncio para o próximo candidato. |
| 2 | <raiz do repo>/.env |
O caminho de sempre, ao lado de bin/, independentemente do diretório de onde você invoca o CLI. Pulado dentro de um PHAR: ali ele resolveria para um phar://…/.env que ninguém pode criar. |
| 3 | ~/.config/conta-azul-cli/.env |
O arquivo do usuário, no mesmo diretório em que já moram tokens.json e o log. É o que torna um ca global utilizável. |
Mesclar candidatos tornaria ca config set ambíguo — gravou em qual arquivo? — e transformaria um arquivo esquecido num override parcial silencioso. A regra cabe numa frase de propósito, e ca config path imprime a decisão inteira, com o motivo de cada candidato ter vencido ou sido descartado:
getcwd()/.envnão é candidato, e isso é deliberado. Se o diretório de trabalho entrasse na busca, rodar ocade dentro de qualquer projeto alheio que tenha um.envfaria o CLI absorver as variáveis daquele projeto — credenciais de terceiros, em silêncio, sem nada na saída indicando de onde vieram.CA_CLI_ENV_FILEcobre a mesma necessidade de forma explícita, por invocação, e aparece emca config path.
Configurando uma instalação global¶
Com o ca instalado como binário (Instalação), não há repositório por perto e o candidato 3 é o que vale. Os comandos ca config funcionam mesmo sem credencial nenhuma — são o caminho para sair desse estado:
ca config init # cria ~/.config/conta-azul-cli/.env
ca config set CA_CLIENT_ID <id>
ca config set CA_CLIENT_SECRET <secret>
ca config show # confere o resultado
O arquivo nasce 0600, dentro de um diretório 0700 — em Unix. No Windows, essa garantia não existe; veja Permissões dos arquivos.
ca config set valida a chave contra a lista de variáveis conhecidas: um nome digitado errado é recusado na hora, em vez de virar uma linha no arquivo que nunca faz efeito.
init e set não têm o mesmo alvo. ca config init grava sempre em ~/.config/conta-azul-cli/.env, mesmo que outro candidato esteja valendo — é a razão de ele existir. Já ca config set grava no arquivo em vigor, seja ele qual for. Num clone que tenha .env na raiz, init cria um segundo arquivo que só passa a valer quando o primeiro sair do caminho; ca config path mostra isso.
ca config show lista todas as variáveis com o valor efetivo e a origem de cada uma — ambiente, arquivo ou default. A saída nunca contém segredo: CA_CLIENT_SECRET e CA_BOOTSTRAP_REFRESH_TOKEN aparecem só como (definido) ou (ausente), sem máscara parcial e sem opção para revelar. É o que torna essa saída segura para colar numa issue.
Os quatro comandos, com o que cada um responde: Configuração na referência.
Configurando um clone¶
Num clone, o candidato 2 vence. Copie .env.example para .env e preencha as credenciais:
Variáveis¶
| Variável | Obrigatória | Default |
|---|---|---|
CA_CLIENT_ID |
sim | — |
CA_CLIENT_SECRET |
sim | — |
CA_REDIRECT_URI |
não | https://conta-azul-cli.ddev.site:9876/callback |
CA_SCOPE |
não | omitido da requisição |
CA_CALLBACK_CERT |
não | — |
CA_CALLBACK_KEY |
não | — |
CA_API_BASE_URL |
não | https://api-v2.contaazul.com |
CA_AUTH_BASE_URL |
não | https://auth.contaazul.com |
CA_AUTHORIZE_URL |
não | {CA_AUTH_BASE_URL}/oauth2/authorize |
CA_TOKEN_URL |
não | {CA_AUTH_BASE_URL}/oauth2/token |
CA_CALLBACK_TIMEOUT |
não | 300 (segundos) |
CA_CLI_TOKEN_PATH |
não | ~/.config/conta-azul-cli/tokens.json |
CA_BOOTSTRAP_REFRESH_TOKEN |
não | — |
CA_CLI_ENV_FILE |
não | — (veja abaixo) |
CA_CLI_ENV_FILE é a única da lista que só funciona no ambiente, nunca dentro de um arquivo: ela escolhe o arquivo, então defini-la lá dentro jamais poderia fazer efeito. Por isso ca config set a recusa, e é ca config path que mostra seu valor.
.env e tokens.json nunca devem ser versionados.
Permissões dos arquivos¶
O CLI grava arquivos que carregam credencial:
| Arquivo | O que guarda |
|---|---|
~/.config/conta-azul-cli/.env |
CA_CLIENT_SECRET — e o CA_BOOTSTRAP_REFRESH_TOKEN, se você o definir ali |
~/.config/conta-azul-cli/tokens.json |
O access token e o refresh token do OAuth, a credencial de longa duração |
~/.config/conta-azul-cli/certs/ |
A CA e a chave privada do certificado TLS do callback, gerados por ca auth login |
Em todos esses caminhos o CLI cria o diretório com 0700 e o arquivo com 0600, e reaplica a permissão a cada escrita, não só na criação. Em Unix isso significa o que promete: nenhum outro usuário da máquina lê esses arquivos.
No Windows essa garantia não existe. O
chmoddo PHP naquela plataforma só liga e desliga o atributo de somente-leitura — ele não escreve bits de modo POSIX, porque o sistema de arquivos não os tem. O código chamachmodem todas as plataformas e está correto; o que não existe no Windows é o efeito. Quem protege os arquivos ali são as ACLs do próprio perfil do usuário (C:\Users\<você>), que por padrão já barram os demais usuários locais.Numa máquina Windows de um usuário só, isso costuma ser suficiente. O que não é verdade é a garantia: num perfil com ACL afrouxada, numa pasta sincronizada para a nuvem ou num diretório compartilhado, não há um
0600segurando a ponta. Se for o seu caso, restrinja o diretório à mão (icacls) ou mantenha as credenciais em variáveis de ambiente, fora de arquivo.A suíte de testes se comporta do mesmo jeito: em Windows, os casos que verificam bits de permissão são pulados explicitamente, em vez de afirmar algo que a plataforma não sustenta.
Uma ressalva sobre o caminho de clone: cp .env.example .env cria o arquivo com o que o seu umask mandar — tipicamente 0644, legível por qualquer usuário da máquina. Só ca config init e ca config set aplicam 0600. Num clone em máquina compartilhada, vale um chmod 600 .env depois de copiar.
Sobre CA_SCOPE¶
Valores aceitos dependem do app registrado. O scope do app de produção é:
O valor precisa de aspas: contém espaços, e o Dotenv rejeita valores não citados com espaço.
Nem todo scope serve: financeiro é recusado com invalid_scope. Se CA_SCOPE ficar indefinida, o parâmetro é omitido da requisição e o provedor aplica os escopos configurados no painel do app — também um caminho válido. Ao receber invalid_scope no login, o primeiro lugar a olhar é o valor no .env.
CA_AUTHORIZE_URL e CA_TOKEN_URL andam em par¶
Um authorization code só pode ser resgatado no servidor que o emitiu. Os dois endpoints têm que pertencer ao mesmo servidor de autorização. Os defaults já satisfazem isso e servem tanto produção quanto sandbox:
CA_AUTHORIZE_URL = https://auth.contaazul.com/oauth2/authorize
CA_TOKEN_URL = https://auth.contaazul.com/oauth2/token
Na prática, só mexa nessas variáveis se a Conta Azul mudar os endpoints — e mexa nas duas.
Não aponte
CA_AUTHORIZE_URLparahttps://login.contaazul.com/#/oauth/authorize. Aquela tela funciona, exibe o nome do app e devolve umcodeno callback — mas é a SPA de login, e ela emite o code através deapi-v2.contaazul.com/oauth/authorize, um emissor diferente. O/oauth2/tokendo Cognito não reconhece esse code, e a troca falha cominvalid_grantlogo depois de um login aparentemente bem-sucedido. Já caímos nessa: o sintoma não aponta para a causa, porque a parte visível do fluxo se comporta como se estivesse certa.
Callback OAuth com HTTPS¶
O provedor da Conta Azul recusa redirect_uri em http://localhost: exige HTTPS e um domínio real. O default compilado já é esse valor:
ca auth login emite sozinho o certificado TLS em ~/.config/conta-azul-cli/certs/ e instala a CA no trust store do usuário (no macOS, o login keychain — pode pedir a senha da conta uma vez). Não depende de um checkout, de .certs/ na raiz do repositório, nem de mkcert. É o que torna brew install + ca auth login suficiente numa máquina nova.
Não altere esse domínio. O nome sugere uma dependência de DDEV que não existe: o projeto não usa DDEV, e
*.ddev.siteé apenas um wildcard DNS público apontando para127.0.0.1. A escolha é imposta pelo provedor — já tentamos trocar por um nome mais neutro e não funcionou. Ao registrar a aplicação comconta-azul-cli.localtest.me, que tem exatamente a mesma propriedade de DNS, o portal da Conta Azul respondeu erro interno de servidor e recusou o cadastro; comddev.siteaceitou. O critério de validação de domínio deles não é documentado, então vale o valor que funciona.
Registre exatamente esse redirect_uri no painel do app na Conta Azul.
CA_CALLBACK_CERT e CA_CALLBACK_KEY continuam valendo como override: se os dois arquivos existirem, o CLI usa-os e não mexe no trust store. Caminhos copiados de um checkout antigo que não existem nesta máquina são ignorados, e o CLI cai no par gerado. Sem as duas variáveis, o servidor de callback abre um socket TLS com o certificado gerado; um CA_REDIRECT_URI em http:// (não o default) cai no modo http:// simples.