Um cliente precisava automatizar a gestão de assinaturas eletrônicas: criar e administrar usuários, disparar envelopes para assinatura e consultar o status — tudo a partir de um sistema interno, sem ninguém clicando em telas. Esse “sem ninguém clicando” é a parte importante: define como a aplicação se autentica.
Por que JWT Grant (e não o fluxo com login)
O DocuSign oferece alguns fluxos OAuth. O mais comum, Authorization Code Grant, exige que um humano abra o navegador e autorize o acesso. Serve para apps onde o próprio usuário final loga.
No nosso caso era uma integração servidor-a-servidor: um backend agindo em nome de um usuário, sem interface de login. Para isso existe o JWT Grant — a aplicação assina um token JWT com uma chave privada RSA e o troca por um access token, impersonando um usuário previamente autorizado.
O fluxo, no papel, é curto:
- Você cria uma Integration Key (o client id) no painel do DocuSign.
- Gera um par de chaves RSA; a pública vai no painel, a privada fica no servidor.
- O backend monta um JWT, assina com a privada e pede o access token, informando qual usuário quer impersonar.
- Uma única vez, um admin precisa dar consent ao escopo
impersonation.
A documentação termina mais ou menos aqui. A realidade tem mais seis capítulos.
1. ActiveOnly não é um status válido
Ao listar usuários, é intuitivo filtrar pelos ativos com algo como
status=ActiveOnly. A API aceita a chamada e devolve erro — porque o valor
correto é simplesmente Active. Pequeno, mas custa uma sessão de debug
achando que o problema é de permissão.
2. O container não conseguia ler a chave privada
Rodando a aplicação em container, a chave privada estava montada com permissão
600 e dono root — o reflexo de segurança correto. Só que o processo dentro do
container roda com um UID não-root (no nosso caso, 10001), que não é dono
do arquivo e portanto não consegue lê-lo.
O ajuste: dar a posse do arquivo ao UID do processo e manter a permissão
restrita — chown 10001:10001 + chmod 400. Continua protegido, e agora quem
precisa, lê.
3. Redirect URI é obrigatório — mesmo sem redirecionamento
JWT Grant não usa redirecionamento de navegador. Mesmo assim, o painel do DocuSign exige um Redirect URI cadastrado na aplicação. Sem ele, o fluxo de consent quebra. Cadastre uma URL qualquer válida e siga em frente.
4. Configurações de homologação NÃO migram para produção
Esse é o que mais dói. Toda a integração foi construída e testada no ambiente de
demonstração (account-d.docusign.com). Quando o DocuSign promove sua aplicação
para produção (account.docusign.com), o código da aplicação migra — mas as
configurações (Redirect URI, chave pública RSA, tipo de integração) não.
Resultado: você jura que está tudo configurado, porque configurou — só que em demo. Em produção, a aplicação chega “pelada”. É preciso reconfigurar tudo manualmente no painel de produção depois do go-live.
5. no_valid_keys_or_signatures quase nunca é sobre a assinatura
Em produção, batemos no erro invalid_grant: no_valid_keys_or_signatures. O nome
sugere problema na chave ou na assinatura do JWT — e você vai perder tempo
conferindo a RSA.
Na prática, esse erro aparece quando falta a chave pública cadastrada OU
falta o consent no ambiente de produção (lembra do capítulo 4?). Não confunda
com consent_required, que é o erro “limpo” de consent pendente. O
no_valid_keys_or_signatures é o sintoma indireto da configuração que não migrou.
6. Deletar um usuário não o apaga
Por fim, um detalhe de modelagem: um DELETE em um usuário não remove o
registro — ele passa para o status Closed. O e-mail daquele usuário fica
“reservado”, o que significa que recriar alguém com o mesmo e-mail tem
comportamento próprio. Útil saber antes de assumir que “deletar” zera tudo.
O que fica de lição
Integração de API raramente falha na “lógica” — ela falha nos detalhes de ambiente, permissão e provisionamento que a documentação trata como óbvios. O maior buraco aqui foi o demo → produção: tudo funcionava, e ainda assim nada funcionava no dia da virada, porque metade da configuração mora num lugar que não viaja junto com o código.
Quando montamos uma integração para um cliente, é justamente esse trecho — a passagem para produção e os modos de falha silenciosos — que tratamos com mais cuidado. É onde o “funciona na minha máquina” cobra o preço.