Programação Por Equipe DevBras

Capa do artigo: Network Error no oidc-client: como achar a causa real em cinco minutos

Network Error no oidc-client: como achar a causa real em cinco minutos

O oidc-client diz Network Error, mas a causa costuma ser CORS, certificado, mixed content ou endereço errado. Veja como ler o painel de rede e corrigir no lugar certo.

O SPA em Angular abre, você clica em Entrar e o console mostra Network Error at XMLHttpRequest.s.onerror (oidc-client.min.js). Alguém sugere atualizar a biblioteca, outro sugere trocar de navegador. Duas horas depois, o erro continua igual. A mensagem é genérica porque o navegador esconde do JavaScript o motivo da falha. O motivo está escrito, com todas as letras, na aba Network e no console, uma linha acima.

A resposta curta: Network Error no oidc-client significa que uma requisição XHR da biblioteca para o provedor de identidade terminou sem resposta legível, com status 0. As causas mais comuns são CORS não liberado para a origem do SPA, certificado HTTPS não confiável no provedor, página HTTPS chamando endereço HTTP e authority apontando para o lugar errado. Abra a requisição vermelha, leia o motivo e corrija na configuração do provedor, não na biblioteca.

Por que o erro chega tão vago

A biblioteca faz várias chamadas XHR por conta própria: baixa o documento de descoberta em /.well-known/openid-configuration, as chaves públicas do endpoint jwks, troca o código pelo token no endpoint de token e, se configurado, consulta o userinfo. Quando qualquer uma falha antes de haver uma resposta que o JavaScript possa ler, o navegador dispara onerror com status 0 e nenhum detalhe. Isso é proposital: se uma página pudesse saber por que a chamada a outro domínio falhou, ela poderia sondar redes internas.

Então a biblioteca não tem como dizer mais do que Network Error. Quem sabe o motivo é o navegador, e ele mostra isso nas ferramentas de desenvolvedor, não no objeto de erro. Atualizar a biblioteca não muda essa regra, e é por isso que raramente resolve.

Como ler o painel de rede, passo a passo

O cenário de exemplo: SPA Angular em http://localhost:4200, provedor IdentityServer em https://localhost:5001, API em https://localhost:5002.

  1. Abra as ferramentas de desenvolvedor, aba Network, marque Preserve log e reproduza o login.
  2. Filtre por Fetch/XHR e encontre a requisição em vermelho.
  3. Anote o domínio e o caminho dela. É o documento de descoberta, o jwks, o token ou o userinfo?
  4. Veja a coluna Status. Valores como (failed), CORS error ou um código net::ERR_... já dizem a família do problema.
  5. Vá ao console e leia a mensagem completa que o navegador escreveu junto da falha.
  6. Reproduza a mesma chamada fora do navegador com curl para separar problema de rede de problema de política do navegador.

As quatro mensagens que resolvem quase tudo

CORS. O console mostra algo como:

Access to XMLHttpRequest at 'https://localhost:5001/.well-known/openid-configuration'
from origin 'http://localhost:4200' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

O provedor respondeu, mas não autorizou a origem do SPA a ler a resposta. Aqui o CORS é de fato o problema, porque o oidc-client chama o provedor por XHR. No IdentityServer, a origem é liberada por cliente.

Certificado. A requisição aparece com net::ERR_CERT_AUTHORITY_INVALID. O provedor em desenvolvimento usa um certificado em que o navegador não confia. Ao abrir a URL numa aba, você veria o aviso de conexão não segura; via XHR, não há aviso, só falha.

Mixed content. O console diz que a página foi carregada por HTTPS e tentou um XMLHttpRequest para um endereço HTTP, e que a requisição foi bloqueada. Acontece quando o SPA já está em HTTPS e o authority ou algum endpoint do documento de descoberta ainda aponta para HTTP, comum quando o provedor roda atrás de proxy e não sabe que o acesso externo é HTTPS.

Endereço errado ou serviço fora. net::ERR_CONNECTION_REFUSED ou net::ERR_NAME_NOT_RESOLVED. O authority tem porta errada, o provedor não subiu ou o nome não resolve na máquina de quem testa.

Como corrigir cada causa no lugar certo

Liberar a origem no IdentityServer

new Client
{
    ClientId = "angular-spa",
    AllowedGrantTypes = GrantTypes.Code,
    RequirePkce = true,
    RequireClientSecret = false,
    RedirectUris = { "http://localhost:4200/auth-callback" },
    PostLogoutRedirectUris = { "http://localhost:4200/" },
    AllowedCorsOrigins = { "http://localhost:4200" },
    AllowedScopes = { "openid", "profile", "api1" }
}

A origem é esquema, host e porta, sem barra no final e sem caminho. http://localhost:4200/ com barra não casa com a origem que o navegador envia. Em produção, entra a origem pública do SPA, e só ela. Liberar qualquer origem para fazer o erro sumir troca um problema visível por um invisível; o post CORS não é a trava do seu servidor explica o que o CORS protege e o que não protege.

Conferir de fora do navegador

curl -i -H "Origin: http://localhost:4200" https://localhost:5001/.well-known/openid-configuration

O curl não aplica CORS, mas mostra os cabeçalhos. Se a resposta vier 200 e sem Access-Control-Allow-Origin: http://localhost:4200, a configuração do cliente não foi aplicada ou a origem está escrita diferente. Se o curl reclamar do certificado, o problema é o certificado, não o CORS. Não use a opção que desliga a verificação do curl como solução; ela só esconde a causa.

Leia também o JSON da descoberta. Todos os endpoints listados ali (token_endpoint, jwks_uri, userinfo_endpoint) precisam estar no mesmo esquema e host que o navegador alcança. Se aparecer http:// ou um nome interno de contêiner, o provedor está montando URLs a partir do que ele enxerga atrás do proxy, e é preciso configurar o encaminhamento dos cabeçalhos do proxy.

Certificado de desenvolvimento confiável

Com ASP.NET Core em Windows ou macOS, dotnet dev-certs https --trust instala e confia no certificado de desenvolvimento. Feche e reabra o navegador depois. Em produção, use um certificado de autoridade pública, como os do Let's Encrypt. Nunca desligue a verificação de certificado no cliente para avançar; o post certificado autoassinado serve no laboratório mostra onde ele cabe.

Quando atualizar a biblioteca faz sentido

O pacote oidc-client original não é mais mantido, e a comunidade continuou o trabalho no oidc-client-ts. Migrar é uma boa ideia, mas como tarefa separada, com testes, depois de entender o erro atual. Trocar a biblioteca para tentar sumir com um bloqueio de CORS só adiciona uma segunda variável ao problema.

Erros comuns

  • Atualizar a biblioteca como primeiro passo. O bloqueio é do navegador e continua igual na versão nova, agora com mudanças de API para depurar junto.
  • Liberar CORS na API quando o bloqueio é no provedor. A configuração vai para o projeto errado e o erro não muda, porque a requisição que falha é para outro domínio.
  • Escrever a origem com barra ou caminho. O valor nunca casa com o cabeçalho Origin e a liberação parece não funcionar.
  • Desligar a verificação de certificado. O erro some em desenvolvimento e a mesma configuração vaza para produção, aceitando qualquer servidor.
  • Ignorar o documento de descoberta. Endpoints com HTTP ou nome interno causam mixed content ou falha de resolução que parecem aleatórios.
  • Colar o token no ticket enquanto depura. A credencial passa a circular em ferramentas que não deveriam tê-la.

Checklist

  • Você sabe qual requisição falhou: descoberta, jwks, token ou userinfo.
  • Você leu a mensagem completa do console ao lado da falha.
  • A origem exata do SPA está liberada no cliente do provedor, sem barra final.
  • O curl com cabeçalho Origin mostra o Access-Control-Allow-Origin esperado.
  • O certificado do provedor é confiável no navegador de quem testa.
  • Todos os endpoints do documento de descoberta usam HTTPS e o host público.
  • Nenhum token aparece em log, print ou ticket do diagnóstico.

Abra agora a aba Network e reproduza o erro: para qual domínio vai a requisição vermelha, e qual motivo o navegador escreveu no console?

Avalie este artigo

Referência: https://pretagteam.com/question/network-error-at-xmlhttprequestsonerror-oidcclientminjs3-with-angular-7-and-aspnet-core-22