[{"data":1,"prerenderedAt":350},["ShallowReactive",2],{"header-blog-translations-/de/blog":3,"blog-list-de":4},null,[5],{"id":6,"title":7,"author":8,"body":9,"date":336,"description":337,"extension":338,"image":3,"meta":339,"navigation":340,"path":341,"seo":342,"stem":343,"tags":344,"translationKey":348,"__hash__":349},"blog_de/blog/de/wie-aus-einem-login-modul-ein-protokoll-wurde.md","Wie aus einem Login-Modul ein Protokoll wurde","Patrick Hofmann",{"type":10,"value":11,"toc":324},"minimark",[12,16,19,22,27,34,37,49,60,64,70,77,88,92,95,98,105,116,120,126,133,140,144,147,154,158,165,168,188,191,195,198,274,284,287,291,294,297,304,307,310,321],[13,14,15],"p",{},"Ich wollte ein Login-Modul bauen.",[13,17,18],{},"Das war im November. Ein Nuxt-Modul, mit dem Web-Apps WebAuthn-Passkeys statt Passwörter unterstützen können. Klein, fokussiert, eine Aufgabe. Ein Wochenende, dann fertig.",[13,20,21],{},"So war zumindest der Plan.",[23,24,26],"h2",{"id":25},"problem-1-wer-ist-der-identity-provider","Problem 1: Wer ist der Identity Provider?",[13,28,29,30],{},"Sobald man WebAuthn implementiert, stößt man auf eine unscheinbare Frage: ",[31,32,33],"strong",{},"Woher weiß ein Service Provider, an welchen Identity Provider er sich wenden soll?",[13,35,36],{},"Bei Auth0 oder Clerk ist die Antwort einfach: Du bist beim Anbieter registriert, der Anbieter ist hardcoded. Aber sobald du dezentral denkst, fehlt die Auflösung. Ein User gibt seine E-Mail-Adresse ein - und dann?",[13,38,39,40,43,44,48],{},"Die Antwort liegt seit 1983 herum: ",[31,41,42],{},"DNS",". Jede E-Mail-Adresse hat eine Domain. Jede Domain kann TXT-Records haben. Also habe ich DNS Discovery gebaut: Ein TXT-Record an ",[45,46,47],"code",{},"_ddisa.example.com"," verweist auf den zuständigen Identity Provider. Eine E-Mail-Adresse reicht, der Rest passiert über DNS.",[13,50,51,52,55,56,59],{},"Aus dem Login-Modul wurde ein zweites: ",[45,53,54],{},"@openape/core"," für die DNS-Resolution, ",[45,57,58],{},"@openape/auth"," für den eigentlichen WebAuthn-Flow.",[23,61,63],{"id":62},"problem-2-aber-wie-authentifiziert-sich-ein-agent","Problem 2: Aber wie authentifiziert sich ein Agent?",[13,65,66,67],{},"Etwa zur gleichen Zeit fingen meine eigenen Projekte an, AI Agents ernsthaft zu nutzen. Und bevor ich überhaupt über Berechtigungen nachdenken konnte, stand da eine viel grundlegendere Frage: ",[31,68,69],{},"Passkeys brauchen einen Finger. Agents haben keine Finger. Wie soll sich der überhaupt anmelden?",[13,71,72,73,76],{},"Also habe ich den Auth-Flow um einen zweiten Pfad erweitert: ",[31,74,75],{},"Ed25519 Challenge-Response, im Prinzip wie SSH-Keys."," Der Agent hat einen privaten Key, der IdP den Public Key, der IdP stellt eine Challenge, der Agent signiert. Dasselbe Pattern wie WebAuthn - nur ohne Browser und ohne Mensch in der Schleife.",[13,78,79,80,83,84,87],{},"Und damit passiert etwas Schönes: ",[31,81,82],{},"Auf Protokoll-Ebene verschwindet der Unterschied zwischen Mensch und Agent."," Beide haben eine Identität beim IdP. Beide authentifizieren sich nach demselben Schema. Beide können mit derselben CLI (",[45,85,86],{},"apes",") arbeiten. Der einzige Unterschied: Der Mensch hat einen Passkey am Laptop, der Agent einen Ed25519-Key im Filesystem.",[23,89,91],{"id":90},"problem-3-ok-angemeldet-was-darf-er-jetzt","Problem 3: OK angemeldet - was darf er jetzt?",[13,93,94],{},"Der Agent kann sich anmelden. Schön. Aber darf er jetzt einfach alles? Natürlich nicht. Ich will granulare Kontrolle - diese Mail lesen ja, jene löschen nein, diesen Code Review machen ja, direkt mergen nein.",[13,96,97],{},"OAuth wäre die naheliegende Antwort für Autorisierung. Aber OAuth ist für Menschen designed - Authorization Code Flow, Browser-Redirect, der ganze Tanz. Für einen Background-Agent fühlt sich das falsch an.",[13,99,100,101,104],{},"Also habe ich ",[31,102,103],{},"Grants"," gebaut. Ein Grant ist ein vorab genehmigtes JWT, das einem Agent erlaubt, eine bestimmte Aktion auszuführen. Granular, zeitlich begrenzt, jederzeit widerrufbar. Ich genehmige einmal mit meinem Passkey - der Agent kann dann ohne weitere Interaktion handeln, aber nur innerhalb der erteilten Berechtigung.",[13,106,107,108,111,112,115],{},"Aus zwei Packages wurden vier: ",[45,109,110],{},"@openape/grants"," kam dazu, dann ",[45,113,114],{},"@openape/proxy"," als HTTP-Gateway für Agents.",[23,117,119],{"id":118},"problem-4-wie-meldet-sich-ein-agent-in-meinem-namen-an","Problem 4: Wie meldet sich ein Agent in meinem Namen an?",[13,121,122,123],{},"Grants waren die Antwort auf \"der Agent darf genau diese eine Aktion\". Aber was, wenn ein Agent über längere Zeit wie ich an einem Service arbeiten soll? ",[31,124,125],{},"Nicht pro Call ein neues Grant, sondern eine Session - unter meiner Identität.",[13,127,128,129,132],{},"Das konnten Grants nicht. Ein Grant ist ein Ticket für einen einzelnen Call, keine Anmeldung. Also wurde daraus ein eigener Protokoll-Baustein: ",[31,130,131],{},"Delegation",". Ich autorisiere meinen Agent einmal, sich bei einem Service in meinem Namen anzumelden - und er läuft dann mit einer eigenen Session, als ich, aber mit einem eindeutigen Audit-Trail: \"Das war nicht Patrick selbst, das war Agent X im Auftrag von Patrick.\"",[13,134,135,136,139],{},"Technisch auf Basis von RFC 8693 (Token Exchange), mit dem ",[45,137,138],{},"act","-Claim aus OAuth 2.0. Standards wo möglich, eigene Erweiterungen wo nötig.",[23,141,143],{"id":142},"problem-5-wo-lebt-das-schlüsselmaterial","Problem 5: Wo lebt das Schlüsselmaterial?",[13,145,146],{},"Bis dahin lief alles im Browser oder im Server. Aber für eine Identity-Plattform reicht das nicht. Schlüssel müssen sicher auf dem Gerät des Users liegen, nicht in irgendeinem Server-Storage. Also kam eine Desktop-App - mit Tauri v2, Vue 3 im Frontend, Rust im Backend. Plus eine Rust-CLI für Power-User und Server-Setups.",[13,148,149,150,153],{},"Die Desktop-App hat auch noch eine andere Funktion bekommen: ",[31,151,152],{},"Sie orchestriert AI Agents als isolierte OS-User",". Jeder Agent läuft in seinem eigenen User-Account, mit eigenen Permissions, in einer eigenen Umgebung. Das ist nicht mehr \"Identity-Modul\" - das ist Infrastruktur für die nächste Generation von AI-gestützten Workflows.",[23,155,157],{"id":156},"problem-6-wie-schreibt-man-das-auf","Problem 6: Wie schreibt man das auf?",[13,159,160,161,164],{},"Irgendwann hatte ich 10 Packages, 2 Nuxt-Module, 6 Apps, eine Desktop-App, eine CLI, und keine Spezifikation. Ein Protokoll braucht aber eine Spezifikation - sonst ist es nur Code. Also habe ich angefangen, ",[31,162,163],{},"DDISA"," zu schreiben: DNS-Discoverable Identity & Service Authorization.",[13,166,167],{},"Drei Dokumente:",[169,170,171,178,183],"ul",{},[172,173,174,177],"li",{},[31,175,176],{},"Core",": DNS Discovery, OIDC-Erweiterungen, WebAuthn- und Ed25519-Auth-Flows, Token-Format",[172,179,180,182],{},[31,181,103],{},": Grant-basierte Authorization REST API, AuthZ-JWT, Polling-Modell",[172,184,185,187],{},[31,186,131],{},": Delegationsprotokoll auf Basis von RFC 8693",[13,189,190],{},"Plus JSON Schemas (Draft 2020-12) für alle Datenformate, plus vollständige HTTP-Beispiele für jeden Flow. Compliance-Levels für Implementierungen: Core, Core+Grants, Core+Grants+Delegation.",[23,192,194],{"id":193},"wo-das-heute-steht","Wo das heute steht",[13,196,197],{},"Heute, am 9. April 2026, sieht OpenApe so aus:",[199,200,201,214],"table",{},[202,203,204],"thead",{},[205,206,207,211],"tr",{},[208,209,210],"th",{},"Komponente",[208,212,213],{},"Beschreibung",[215,216,217,228,238,248,264],"tbody",{},[205,218,219,225],{},[220,221,222],"td",{},[31,223,224],{},"Protokoll",[220,226,227],{},"3 Specs (Core, Grants, Delegation), JSON Schemas, vollständige Beispiele",[205,229,230,235],{},[220,231,232],{},[31,233,234],{},"Monorepo",[220,236,237],{},"10 npm-Packages, 2 Nuxt-Module, 6 deployte Apps",[205,239,240,245],{},[220,241,242],{},[31,243,244],{},"Desktop App",[220,246,247],{},"Tauri v2, orchestriert AI Agents als isolierte OS-User",[205,249,250,255],{},[220,251,252],{},[31,253,254],{},"CLI",[220,256,257,259,260,263],{},[45,258,86],{}," für Grant-Management, ",[45,261,262],{},"ape-shell"," als grant-secured Shell",[205,265,266,271],{},[220,267,268],{},[31,269,270],{},"Free IdP",[220,272,273],{},"Hosted Identity Provider, kostenlos nutzbar",[13,275,276,277,279,280,283],{},"Heute Morgen habe ich ",[45,278,262],{}," committed - eine Shell-Replacement, die jeden Befehl durch das Grant-System schickt. ",[45,281,282],{},"ape-shell -c \"git status\""," requestet einen Grant, der für die Session gilt. Folgekommandos nutzen denselben Grant. Zero-Latency-Re-Execution mit menschlicher Kontrolle.",[13,285,286],{},"Im November wollte ich ein Login-Modul bauen.",[23,288,290],{"id":289},"was-ich-daraus-gelernt-habe","Was ich daraus gelernt habe",[13,292,293],{},"Die wichtigsten Projekte entstehen nicht am Whiteboard. Sie entstehen, wenn du ein konkretes Problem löst und dabei merkst, dass das Problem ein anderes Problem versteckt hat. Und das nächste. Und das übernächste.",[13,295,296],{},"Wenn ich im November einen \"Plan für ein dezentrales Identity-Protokoll\" gemacht hätte, hätte ich mich überfordert. Stattdessen habe ich ein Login-Modul gebaut. Das ging. Dann das nächste Stück. Auch das ging. Und so weiter, bis das Ergebnis größer war als der ursprüngliche Plan.",[13,298,299,300,303],{},"Der einzige Grund, warum es funktioniert hat: ",[31,301,302],{},"Jeder Schritt war für sich genommen klein und konkret."," Die Vision ist erst rückblickend entstanden. Sie war kein Startpunkt, sie war eine Folge.",[13,305,306],{},"Das ist vielleicht das, was an \"Building in Public\" wirklich wertvoll ist: nicht das öffentliche Zeigen, sondern das öffentliche Eingeständnis, dass du nicht von Anfang an wusstest, was du baust. Du hast es herausgefunden, indem du gebaut hast. Zumindest war es bei mir so.",[308,309],"hr",{},[13,311,312,313,320],{},"OpenApe ist Open Source. Die Protokoll-Spezifikation, der Code, die Apps - alles auf ",[314,315,319],"a",{"href":316,"rel":317},"https://github.com/openape-ai",[318],"nofollow","github.com/openape-ai",". Wenn du an dezentraler Identität, AI-Agent-Authorization oder einfach an interessanten Protokoll-Designs interessiert bist: schau rein, mach Issues auf, schreib mir.",[13,322,323],{},"Was war dein letztes Projekt, das dir entwachsen ist?",{"title":325,"searchDepth":326,"depth":326,"links":327},"",2,[328,329,330,331,332,333,334,335],{"id":25,"depth":326,"text":26},{"id":62,"depth":326,"text":63},{"id":90,"depth":326,"text":91},{"id":118,"depth":326,"text":119},{"id":142,"depth":326,"text":143},{"id":156,"depth":326,"text":157},{"id":193,"depth":326,"text":194},{"id":289,"depth":326,"text":290},"2026-04-09","Im November wollte ich ein Nuxt-Modul für WebAuthn-Passkeys bauen. Heute besteht OpenApe aus 10 npm-Packages, 2 Nuxt-Modulen, einem Protokoll und einer Desktop-App. Eine Geschichte über Probleme, die andere Probleme aufdecken.","md",{},true,"/blog/de/wie-aus-einem-login-modul-ein-protokoll-wurde",{"title":7,"description":337},"blog/de/wie-aus-einem-login-modul-ein-protokoll-wurde",[345,163,346,347],"OpenApe","Decentralized Identity","Building in Public","from-login-module-to-protocol","e-L4HiTOVa-ZZur_s9GeuS5yYBtuN1n-FSk5hAACRao",1775734220180]