Pular para o conteúdo principal

Documentação oficial desta página · v0.20.6

Login Nativo no Desktop (RFC 8252)

Quando o aplicativo Hermes Desktop se conecta a um gateway protegido (um painel hospedado ou auto-hospedado que fica atrás de um provedor OAuth), ele pode fazer login de duas formas:

  1. Login nativo (RFC 8252) — o aplicativo abre o seu navegador de sistema de verdade, você aprova no navegador em que já confia, e o aplicativo recebe tokens que guarda como arquivos de acesso exclusivo do dono no diretório de dados do usuário (opcionalmente criptografados com o chaveiro do seu sistema operacional — Settings → Gateway). Sem webview embutida, sem cookies de sessão de navegador. É o padrão sempre que o gateway tem suporte.
  2. Login embutido (alternativa legada) — o aplicativo abre uma pequena janela de navegador interna e captura o cookie de sessão do gateway. Usado automaticamente quando o gateway é uma versão mais antiga que não anuncia o login nativo.

Você não escolhe entre os dois — o aplicativo detecta o que o gateway suporta e escolhe o melhor. Esta página explica o que acontece e por quê.

Por que login nativo​

Embutir um navegador dentro de um aplicativo nativo para OAuth tem desvantagens conhecidas: a página de login não enxerga a sua sessão de navegador existente (então você redigita credenciais e refaz o MFA), gerenciadores de senha e passkeys muitas vezes não funcionam, e o aplicativo depende de ler um cookie de sessão de dentro de uma webview privada. A RFC 8252 ("OAuth 2.0 for Native Apps") é a boa prática do setor que evita tudo isso: faça a autorização no navegador do sistema e entregue ao aplicativo os tokens dele.

No caso específico do Hermes, login nativo significa:

  • Sem webview embutida. A autorização acontece no Safari / Chrome / Firefox / Edge — o que você usar — com seus logins, extensões e passkeys intactos.
  • Sem cookies de sessão. O aplicativo guarda um access token OAuth (de vida curta) e um refresh token, armazenados como arquivos de acesso exclusivo do dono — criptografados em repouso pelo chaveiro do seu sistema operacional (safeStorage do Electron) quando a chave opcional de chaveiro em Settings → Gateway está ligada. As chamadas REST e os tíquetes de WebSocket são autenticados com um cabeçalho Authorization: Bearer, não com um pote de cookies.

Como funciona​

Aplicativo desktop Gateway (/auth/native/*) Nous Portal (IDP)
│ 1. abre loopback 127.0.0.1:<porta aleatória>
│ 2. navegador do sistema ─► /auth/native/authorize
│ (desafio PKCE) (inicia o login PKCE normal) ─► /oauth/authorize
│ ◄──── code ──── /auth/callback ◄──┘
│ 3. emite código de gateway de uso único
│ ◄─ 302 127.0.0.1/cb?code=… ─┘
│ 4. POST /auth/native/token (code + verifier PKCE)
│ ◄─ 5. { access_token, refresh_token, expires_at } ───────┘
│ 6. guarda no cofre local de tokens; usa Bearer para REST + tíquetes WS

O gateway intermedeia o fluxo: ele é o servidor de autorização para o aplicativo desktop e um cliente OAuth para o provedor de identidade upstream (Nous Portal). Isso é necessário porque o client_id upstream e as URIs de redirecionamento permitidas estão vinculados à origem do próprio gateway — um aplicativo desktop não pode ser cliente direto do Portal. Mesmo assim, o desktop tem a experiência completa da RFC 8252: o par PKCE dele, o redirecionamento de loopback dele e tokens que pertencem a ele.

PKCE (RFC 7636) protege o salto de loopback: o código de uso único do gateway é inútil sem o code verifier, que nunca sai do aplicativo. O código é de uso único e de vida curta.

Detecção de capacidade e alternativa​

O desktop lê o endpoint público /api/status do gateway, que anuncia um array auth_flows:

Valor de auth_flowsSignificado
["cookie", "native_pkce"]O gateway suporta login nativo → o aplicativo usa esse fluxo
["cookie"]O gateway suporta só o fluxo legado → o aplicativo usa a webview embutida
(campo ausente)Gateway antigo → o aplicativo usa a webview embutida

Se o login nativo é anunciado mas falha por um motivo local — por exemplo, uma ferramenta de segurança bloqueia o listener de loopback, ou você fecha a aba do navegador — o aplicativo cai automaticamente no fluxo embutido para que você ainda consiga entrar.

Ciclo de vida dos tokens​

  • Access token: de vida curta (minutos). Enviado como Authorization: Bearer em toda chamada REST e ao emitir um tíquete de WebSocket.
  • Refresh token: de vida mais longa, rotativo. Quando o access token está perto de expirar, o aplicativo chama /auth/native/refresh para rotacionar os dois tokens e então atualiza seu cofre de tokens.
  • Expiração terminal: se o refresh token está morto (expirado / revogado / reuso detectado), o aplicativo limpa os tokens armazenados e pede um novo login.
  • Sair: limpa tanto os tokens nativos armazenados quanto qualquer cookie de sessão legado daquele gateway.

Para operadores de gateway​

O login nativo fica disponível automaticamente em qualquer gateway protegido que tenha um provedor de sessão interativa registrado. Nenhuma configuração é necessária — as rotas /auth/native/* e o anúncio de auth_flows fazem parte do subsistema de autenticação do painel. Provedores OAuth (por exemplo, o provedor Nous embutido) intermedeiam o redirecionamento ao IDP upstream; provedores de senha (por exemplo, o plugin basic-auth embutido) levam o navegador do sistema ao formulário de credenciais /login do gateway — e é isso que permite aos gerenciadores de senha do sistema operacional (macOS Passwords, etc.) preencher o formulário automaticamente, algo que nenhuma webview embutida de desktop consegue oferecer. Credenciais somente de token (por exemplo, drain) não são logins interativos e não anunciam native_pkce.

Os endpoints relevantes (todos públicos, de bootstrap pré-autenticação, iguais às rotas OAuth /auth/* já existentes):

  • GET /auth/native/authorize — inicia o login PKCE intermediado
  • POST /auth/native/token — troca o código de loopback + verifier por tokens
  • POST /auth/native/refresh — rotaciona os tokens a partir do refresh token do aplicativo

Veja também​