OAuth auf einem Remote-Server abschließen: SSH-Tunnel, eingefügte Callbacks und Device Codes

Du installierst Hermes auf einer Cloud-VM oder auf einer Dev-Box hinter einem Bastion Host, und jetzt willst du Spotify im Spiel haben – oder einen entfernten MCP-Server wie Linear, Sentry oder Atlassian. Du führst das Kommando aus, Hermes gibt eine Authorize-URL aus, du öffnest sie im Browser deines Laptops und klickst auf Allow. Der Browser landet dann auf einer 127.0.0.1-Adresse und zeigt nichts außer „This site can’t be reached“. Zurück auf dem Server wartet Hermes noch immer still auf einen Callback, der nie ankommt.
Das ist keine Fehlkonfiguration. Es ist eine physische Diskrepanz darin, wo der OAuth-Handshake stattfindet: Das 127.0.0.1 in der Redirect-URI bedeutet „die Maschine, auf der dein Browser läuft“, während der Listener auf dem Remote-Host gebunden ist. Unten stehen die drei Wege, die funktionieren – plus die Provider, die nie einen Tunnel gebraucht haben.
Warum es auf einem Remote-Host bricht
Eine Minute Theorie, weil sie den Fix offensichtlich macht. Hermes nutzt zwei Arten von OAuth-Login:
- Loopback-Redirect. Hermes startet einen winzigen HTTP-Listener auf
127.0.0.1auf der lokalen Maschine. Wenn du genehmigst, leitet der Autorisierungsserver deinen Browser aufhttp://127.0.0.1:port/callbackum, und dieser kleine Listener schnappt sich den Code. So arbeiten Spotify und die meisten OAuth-geschützten entfernten MCP-Server. - Device Code / Paste-the-Code. Ganz ohne Callback-URI. Der Auth-Server gibt dir einen kurzen Code und eine Verifizierungs-URL; du genehmigst in irgendeinem Browser, und Hermes pollt, bis das Token auftaucht.
Beide laufen reibungslos, wenn Hermes und dein Browser dieselbe Maschine teilen. Der erste bricht sonst: Der Browser deines Laptops trifft das 127.0.0.1 des Laptops, während der Listener auf dem 127.0.0.1 des Servers sitzt. Verschiedene Maschinen, gleich aussehende Adresse.
Warum also nicht einfach den Listener an 0.0.0.0 binden oder den öffentlichen Hostnamen des Servers einsetzen? Weil Auth-Server die Redirect-URI gegen eine feste Allowlist validieren. Spotify und die meisten MCP-Autorisierungsserver verlangen die Loopback-Form http://127.0.0.1:port/callback; bindest du woanders oder wählst einen anderen Port, wird die Anfrage als redirect_uri mismatch abgelehnt. Der Fix besteht nicht darin, den Listener zu verschieben – sondern diesen Loopback-Port auf deinen Laptop zu tragen, und genau das tut ein lokaler SSH-Forward.
Weg eins: Ein lokaler SSH-Forward (Spotify als Beispiel)
Öffne ein zweites Terminal auf deinem Laptop und widme es dem Tunnel:
# Lokales Terminal: Laptop:43827 auf remote-host:43827 weiterleiten
ssh -N -L 43827:127.0.0.1:43827 user@remote-host
-N bedeutet „öffne keine Remote-Shell, halte nur diesen Forward offen“. Lass dieses Terminal laufen, bis der Login abgeschlossen ist.
Dann führe in einer separaten SSH-Sitzung das Auth-Kommando aus:
ssh user@remote-host
hermes auth spotify --no-browser
--no-browser überspringt den Auto-Open-Schritt (auf dem Server gibt es keinen Browser). Hermes gibt eine Authorize-URL aus und – entscheidend – den Port, den es tatsächlich gebunden hat:
Waiting for callback on http://127.0.0.1:43827/callback
Füge die Authorize-URL in einen Browser auf deinem Laptop ein und genehmige. Der Auth-Server leitet auf 127.0.0.1:43827/callback um – diesmal ist diese Adresse dein Laptop, sie trifft deinen Tunnel, die Anfrage wird an den entfernten Listener weitergeleitet, und das Terminal meldet Erfolg. Danach kannst du den Tunnel abbauen.
Woher kommt der Port? Aus der Zeile Waiting for callback on .... Spotify nutzt standardmäßig 43827, aber wenn der Port belegt ist, erhöht Hermes ihn eventuell automatisch – lies die Zahl immer aus der Ausgabe ab, statt sie aus einem Blogbeitrag zu kopieren.
Über einen Jump Host nutzt du SSH’s eingebautes ProxyJump, damit der Loopback-Port nie auf der Bastion landet:
ssh -N -L 43827:127.0.0.1:43827 -J jump-user@jump-host user@final-host
Auf älteren OpenSSH-Versionen ohne -J lautet die lange Form:
ssh -N \
-o "ProxyCommand=ssh -W %h:%p jump-user@jump-host" \
-L 43827:127.0.0.1:43827 \
user@final-host
Drei Fallen, die man vorher kennen sollte. Mosh-Roaming trägt keine -L-Forwards; wenn du Hermes also über mosh in tmux laufen lässt, öffne eine separate einfache SSH-Sitzung nur für den Tunnel – diese Verbindung muss durch den Flow hindurch am Leben bleiben, während deine interaktive Sitzung weiterarbeitet. Wenn du ssh -o ControlMaster=auto nutzt, teilen Forwards die Lebensdauer der Master-Verbindung; kommt der Tunnel nicht hoch, beende den Master mit ssh -O exit user@remote-host und versuch es erneut.
Weg zwei: Die Redirect-URL zurückeinfügen (MCP-Server)
Entfernte MCP-Server nutzen denselben Loopback-Flow, aber auf einem interaktiven Terminal bietet Hermes eine Abkürzung, die keinen Tunnel braucht: Füge die Callback-URL an der Eingabeaufforderung wieder ein.
Nachdem du im Browser auf Allow geklickt hast, leitet die Seite auf eine 127.0.0.1-Adresse um und lädt nicht – das ist erwartet. Kopiere die vollständige URL aus der Adressleiste des Browsers und füge sie in die Hermes-Eingabeaufforderung ein:
MCP OAuth: authorization required.
Open this URL in your browser:
https://mcp.linear.app/authorize?response_type=code&...
Or paste the redirect URL here (or the ?code=...&state=... portion) and press Enter:
> https://mcp.linear.app/callback?code=abc123&state=xyz
Got authorization code from paste — completing flow.
Es reicht auch, nur den Query-String ?code=...&state=... einzufügen. Dieser Weg braucht null SSH-Konfiguration und gilt für jeden MCP-Server mit auth: oauth.
Den Tunnel aus Weg eins brauchst du nur, wenn der Flow unbeaufsichtigt abgeschlossen werden muss – eine geskriptete Re-Auth, bei der niemand interaktiv einfügen kann.
Eine Besonderheit auf der Desktop-Seite: Im Skills → MCP-Panel der Desktop-App empfängt die native App den Callback auf deinem Rechner und leitet ihn an die ausgewählte Verbindung und das ausgewählte Profile weiter, sodass weder SSH-Tunnel noch dashboard.public_url im Spiel sind und die Tokens beim besitzenden Backend-Profile bleiben. Das MCP-Tab zu verlassen oder seinen Scope zu ändern bricht eine ausstehende Anmeldung ab.
Weg drei: Device Code und Paste-the-Code (ganz ohne Tunnel)
Nutzt der Provider einen Device-Code-Flow, muss sich an deinem Netzwerk nichts ändern – du genehmigst einmal in einem Browser, und Hermes pollt. Kurzreferenz für „brauche ich einen Tunnel“:
| Provider | Loopback-Port | Tunnel nötig |
|---|---|---|
| Spotify | standardmäßig 43827 | Ja, wenn Hermes remote läuft |
| MCP-Server mit dem Auth-Modus oauth | pro Server automatisch gewählt | Ja, oder Redirect-URL zurückeinfügen |
| xai-oauth (Grok SuperGrok) | n/a | Nein, Device Code |
| anthropic (Claude Pro/Max) | n/a | Nein, Code einfügen |
| openai-codex (ChatGPT Plus/Pro) | n/a | Nein, Device Code |
| minimax, nous-portal | n/a | Nein, Device Code |
| openrouter | nur lokal | Nein: über SSH wechselt Hermes in einen headless Flow und bittet dich, den im Browser angezeigten Code einzufügen |
OpenRouter ist der jüngste dieser Fälle. hermes auth add openrouter --type oauth führt OpenRouters Browser-PKCE-Flow aus und münzt bei Erfolg einen API key in den Credential Pool (seine Quelle wird als manual:openrouter_pkce festgehalten) – kein Copy-Paste eines Keys von einer Webseite. Lokal nutzt es einen bind-first Loopback-Listener auf einem vom OS vergebenen Port, was das probe-then-rebind-Rennen umgeht, indem es einen Port benennt, den es bereits besitzt. Für Remote-Sitzungen erkennt es die SSH-Umgebung und wechselt in OpenRouters dokumentierten headless Mode: kein callback_url, der Code wird auf dem Bildschirm angezeigt, und du fügst ihn ein. Lässt du --type weg, verhält es sich weiterhin als API-Key-Login, der ältere Workflow hermes auth add openrouter --api-key ... bleibt also unverändert.
Vier Fehler, die dir tatsächlich passieren werden
- Konfiguration in einer laufenden Sitzung bearbeiten und dann versuchen, sich anzumelden: 30 Sekunden, dann gibt es auf. Wenn du
config.yamlaus einer laufenden Hermes-Sitzung heraus einen OAuth-MCP-Server hinzufügst, lädt die CLI MCP-Verbindungen mit einem 30-Sekunden-Timeout automatisch neu. Das ist weit entfernt von genug für einen interaktiven OAuth-Flow. Führhermes mcp login <server>stattdessen in einem frischen Terminal aus – es hat keine solche Obergrenze und wartet die vollen fünf Minuten auf dein Einfügen. - Tokens landen im falschen
~/.hermes. Credentials werden unter dem Benutzer geschrieben, der das Kommando ausgeführt hat. Läuft dein Gateway oder systemd-Service unter einem anderen Konto (etwarootoder einem dediziertenhermes-Benutzer), authentifiziere dich als dieses Konto, sonst liegen die Tokens in deinem Home-Verzeichnis und der Service sieht sie nicht.sudo -u hermes -ioder ein Äquivalent. bind [127.0.0.1]:43827: Address already in use. Irgendetwas auf deinem Laptop hält den Port bereits – ein veralteter Tunnel oder ein lokaler Hermes-Listener. Finde und beende es mitlsof -iTCP:43827 -sTCP:LISTENund versuch den Forward dann erneut.- Authorization timed out waiting for the local callback. Die Umleitung hat den entfernten Listener nie erreicht. Bestätige, dass das Tunnel-Terminal noch lebt (eine
ssh -N-Sitzung gibt nichts aus, schau also auf das Terminal selbst), stell sicher, dass der Port zur neuesten ZeileWaiting for callback on ...passt, starte den Tunnel neu und führ das Auth-Kommando erneut aus.
Ein Sicherheitshinweis, der es wert ist, wiederholt zu werden: OAuth-Tokens sind langlebige Credentials, es zählt also, wo sie landen und wer sie lesen kann. Zur umgebenden Maschinerie sieh dir Credential Pools und Browser-Autofill und Keychain-gestützte Secret-Verschlüsselung an. Ist der Server, den du anbindest, von Drittanbietern, lies den Sicherheitsleitfaden zum MCP-Katalog und die Übersicht über den offiziellen Remote-MCP-Katalog, bevor du ihn an ein Gateway hängst.
Die Kurzfassung
Stell eine Frage: Nutzt dieser Provider einen Callback oder einen Code?
- Callback-basiert (Spotify, OAuth-MCP-Server): Auf einem interaktiven Terminal fügst du die Redirect-URL einfach wieder ein – am einfachsten. Für Automatisierung leite den Loopback-Port mit
ssh -N -Lweiter, nimm den Port aus der Ausgabe von Hermes selbst und achte auf mosh, tmux und ControlMaster. - Code-basiert (xai-oauth, openai-codex, anthropic, minimax, nous-portal und OpenRouter über SSH): Ändere nichts. Öffne den Link, gib den Code ein, drück Enter.
Ein leicht vergessener Folgeschritt: Starte nach dem Login jedes lang laufende Gateway oder jeden Service neu, damit es das Credential in seinem eigenen Prozess aufnimmt. Und wenn du die Maschine von Grund auf einrichtest, deckt der Installationsleitfaden den ganzen Weg ab.