Academy → Practical GuidesOfficial documentation · Arabic guidance

Desktop Native Sign-In (RFC 8252)

تسجيل الدخول الآمن من تطبيق سطح المكتب

Intermediate5 min readLesson 282 questions✓ 2026-08-18
Before you read

What this page is, and what it holds.

This page covers Desktop Native Sign-In (RFC 8252). About 5 minutes to read. Open the channel to yourself first with an allowlist. An open channel means anyone can message your agent.

6sections
1code examples
1tables
0commands
816source words
The official one-line description

How the Hermes Desktop app signs in to a gated gateway using your system browser and PKCE — no embedded webview, no session cookies

What you will be able to do

Outcomes taken from this page, not a template.

  • Understand what بوابة المراسلة is and when you need it.
  • Read the table and take only the row that applies to you.
  • Know the common mistake before you hit it.
Page map

Jump to the part you need.

  1. 01Why native sign-in
  2. 02How it works
  3. 03Capability detection & fallback
  4. 04Token lifecycle
  5. 05For gateway operators
  6. 06See also
The full official page

Nothing summarised away.

The documentation body below is reproduced from the official source so commands and identifiers stay exact. Each section carries a short note describing what it contains.

When the Hermes Desktop app connects to a gated gateway (a hosted or self-hosted dashboard that sits behind an OAuth provider), it can sign in two ways:

  1. Native sign-in (RFC 8252) — the app opens your real system browser, you approve in the browser you already trust, and the app receives tokens it stores in your OS keychain. No embedded webview, no browser session cookies. This is the default whenever the gateway supports it.
  2. Embedded sign-in (legacy fallback) — the app opens a small in-app browser window and captures the gateway's session cookie. Used automatically when the gateway is an older build that doesn't advertise native sign-in.

You don't choose between these — the app detects what the gateway supports and picks the best one. This page explains what happens and why.

Why native sign-in

Explains the idea itself. Read it slowly; the later sections build on it.

Embedding a browser inside a native app for OAuth has well-known downsides: the login page can't see your existing browser session (so you re-type credentials and re-do MFA), password managers and passkeys often don't work, and the app relies on reading a session cookie out of a private webview. RFC 8252 ("OAuth 2.0 for Native Apps") is the industry best practice that avoids all of that: **do the authorization in the system browser and hand the app its own tokens.**

For Hermes specifically, native sign-in means:

  • No embedded webview. The authorization happens in Safari / Chrome / Firefox / Edge — whatever you use — with your logins, extensions, and passkeys intact.
  • No session cookies. The app holds an OAuth access token (short-lived) and refresh token, encrypted at rest via your OS keychain (Electron safeStorage). REST calls and WebSocket tickets are authenticated with an Authorization: Bearer header, not a cookie jar.

How it works

Explains the idea itself. Read it slowly; the later sections build on it.

Text10 lines
Desktop app                Gateway (/auth/native/*)          Nous Portal (IDP)
   │ 1. open loopback 127.0.0.1:<random port>
   │ 2. system browser ─►  /auth/native/authorize
   │    (PKCE challenge)    (starts the normal PKCE login) ─► /oauth/authorize
   │                        ◄──── code ──── /auth/callback ◄──┘
   │                        3. mint one-time gateway code
   │ ◄─ 302 127.0.0.1/cb?code=… ─┘
   │ 4. POST /auth/native/token (code + PKCE verifier)
   │ ◄─ 5. { access_token, refresh_token, expires_at } ───────┘
   │ 6. store in OS keychain; use Bearer for REST + WS tickets

The gateway brokers the flow: it is the authorization server *to the desktop app and an OAuth client to the upstream identity provider* (Nous Portal). This is required because the upstream client_id and permitted redirect URIs are bound to the gateway's own origin — a desktop app can't be a direct client of the Portal. The desktop still gets the full RFC 8252 experience: its own PKCE pair, its own loopback redirect, and tokens it owns.

PKCE (RFC 7636) protects the loopback hop: the one-time gateway code is useless without the code verifier, which never leaves the app. The code is single-use and short-lived.

Capability detection & fallback

Explains the idea itself. Read it slowly; the later sections build on it.

The desktop reads the gateway's public /api/status endpoint, which advertises an auth_flows array:

auth_flows valueMeaning
["cookie", "native_pkce"]Gateway supports native sign-in → the app uses it
["cookie"]Gateway supports only the legacy flow → the app uses the embedded webview
(field absent)Older gateway → the app uses the embedded webview

If native sign-in is advertised but fails for a local reason — e.g. a security tool blocks the loopback listener, or you close the browser tab — the app falls back to the embedded flow automatically so you can still sign in.

Token lifecycle

Explains the idea itself. Read it slowly; the later sections build on it.

  • Access token: short-lived (minutes). Sent as Authorization: Bearer on every REST call and when minting a WebSocket ticket.
  • Refresh token: longer-lived, rotating. When the access token is near expiry the app calls /auth/native/refresh to rotate both tokens, then updates the keychain.
  • Terminal expiry: if the refresh token is dead (expired / revoked / reuse-detected), the app clears its stored tokens and prompts a fresh sign-in.
  • Sign out: clears both the native tokens (keychain) and any legacy session cookie for that gateway.

For gateway operators

Explains the idea itself. Read it slowly; the later sections build on it.

Native sign-in is available automatically on any gated gateway with an interactive session provider registered. No configuration is required — the /auth/native/* routes and the auth_flows advertisement are part of the dashboard-auth subsystem. OAuth providers (e.g. the bundled Nous provider) broker the upstream IDP redirect; password providers (e.g. the bundled basic-auth plugin) land the system browser on the gateway's /login credential form instead — which is what lets OS password managers (macOS Passwords, etc.) autofill the form, something no embedded desktop webview can offer. Token-only credentials (e.g. drain) are not interactive sign-ins and do not advertise native_pkce.

The relevant endpoints (all public, pre-auth bootstrap, same as the existing /auth/* OAuth routes):

  • GET /auth/native/authorize — starts the brokered PKCE login
  • POST /auth/native/token — exchanges the loopback code + verifier for tokens
  • POST /auth/native/refresh — rotates tokens from the app's refresh token

See also

Explains the idea itself. Read it slowly; the later sections build on it.

Knowledge check

2 questions answered by this page alone.

Every option is a real identifier from the Hermes documentation. The wrong ones are real too, just from other pages.

1. In this lesson's table, what is the “Meaning” for “(field absent)”?
2. Which of these headings does not appear in this lesson?