{"id":50794256,"url":"https://github.com/ftahirops/symbolon","last_synced_at":"2026-06-12T13:30:49.906Z","repository":{"id":363106085,"uuid":"1261975042","full_name":"ftahirops/symbolon","owner":"ftahirops","description":"Login authority you hold — an open auth protocol where an external Vault mints short-lived, single-use, signed Login Leases your app verifies offline, so one stolen credential is never enough.","archived":false,"fork":false,"pushed_at":"2026-06-07T12:21:54.000Z","size":1187,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-07T14:13:34.698Z","etag":null,"topics":["auth","authentication","ed25519","passwordless","protocol","security","zero-trust"],"latest_commit_sha":null,"homepage":"https://www.xgenstack.com/symbolon","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ftahirops.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-07T12:07:31.000Z","updated_at":"2026-06-07T12:21:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ftahirops/symbolon","commit_stats":null,"previous_names":["ftahirops/symbolon"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/ftahirops/symbolon","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ftahirops%2Fsymbolon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ftahirops%2Fsymbolon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ftahirops%2Fsymbolon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ftahirops%2Fsymbolon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ftahirops","download_url":"https://codeload.github.com/ftahirops/symbolon/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ftahirops%2Fsymbolon/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34247460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-12T02:00:06.859Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["auth","authentication","ed25519","passwordless","protocol","security","zero-trust"],"created_at":"2026-06-12T13:30:49.363Z","updated_at":"2026-06-12T13:30:49.901Z","avatar_url":"https://github.com/ftahirops.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# ⬡ Symbolon\n\n### _σύμβολον_ — the door is **closed by default**\n\n**An open authentication protocol where login authority lives in an external _Vault_, not in your app.**\nThe Vault mints short-lived, single-use, cryptographically signed **Login Leases** that your application verifies **offline** before opening a session.\n\n\u003cbr\u003e\n\n![status](https://img.shields.io/badge/status-draft%20v0.1-d9824a?style=for-the-badge)\n![wire](https://img.shields.io/badge/wire%20version-1-5fb8a8?style=for-the-badge)\n![crypto](https://img.shields.io/badge/crypto-Ed25519_%2B_JCS-e8c87a?style=for-the-badge)\n![verifier](https://img.shields.io/badge/verifier-under_500_LOC-c98a4f?style=for-the-badge)\n![license](https://img.shields.io/badge/license-TBD-lightgrey?style=for-the-badge)\n\n**[🔍 Live showcase →](https://www.xgenstack.com/symbolon)**  ·  **[📜 Read the spec →](./spec/symbolon-protocol-v0.1.md)**  ·  **[🛡 Threat model →](./spec/symbolon-threat-model-v0.1.md)**\n\n\u003c/div\u003e\n\n---\n\n\u003e _Greek **σύμβολον**: a clay token broken cleanly in two. Each party kept one half; matching the halves proved identity. The original one-time identity proof — and the etymological root of the word \"symbol.\"_\n\n## ⚡ The one claim worth making\n\n\u003e ### Symbolon doesn't make compromise _impossible_. It makes **single-point compromise insufficient.**\n\nPasswords, API keys, bearer tokens and session cookies all share one fatal shape: a **long-lived secret that grants standing access**. Steal it once and the door stays open — on any device, from anywhere, until someone notices. Symbolon inverts this. The door is closed by default, and the user **mints a lease per session** — one-time, time-boxed, device-bound, app-bound, action-bound.\n\n---\n\n## 🔄 How it works\n\n```text\n   🧑  SUBJECT  (the user)\n        │\n        │  ①  proves locally — biometric / PIN / passkey\n        ▼\n   🔐  VAULT  (issuer · hardware-backed)\n        │\n        │  ②  mints + signs the lease with its hardware key\n        │      and generates a fresh ephemeral keypair\n        ▼\n   🌐  USER-AGENT  (hostile carrier)\n        │\n        │  ③  carries the lease + ephemeral private key\n        ▼\n   🛡  VERIFIER  (your app)\n        │\n        │  ④  challenge  ⇄  signed nonce        (proof of possession)\n        │  ⑤  verify signature OFFLINE · enforce bindings · consume JTI\n        ▼\n   ✅  BOUNDED SESSION\n```\n\nTwo things **never** happen: no long-lived secret ever reaches your app, and the Verifier **never phones home** to a central authority — it checks the signature against the Vault's published public key, locally.\n\n---\n\n## ✨ Features\n\n| | Feature | What it means |\n|---|---|---|\n| 🔂 | **Single-use** | Each lease has a unique `jti`, consumed atomically on first use. Replays are rejected. |\n| ⏱️ | **Time-boxed** | `not_before` / `not_after` — a window measured in **minutes**, not days. |\n| 📱 | **Device-bound** | A lease is tied to one user-agent. Lifted to another device, it's dead. |\n| 🎯 | **App- \u0026 action-bound** | Usable only at one `app_id`, only for its `allowed_actions`. Writes need a new lease. |\n| 🌍 | **Geo-fenced** | Optional `geo_constraint` pins login to a country, ASN, or IP range. |\n| ✍️ | **Un-forgeable** | Ed25519 signature over the JCS (RFC 8785) canonical form. One changed byte fails. |\n| 📡 | **Offline-verifiable** | No callback to any server — verify against a cached public key. |\n| 🔒 | **Hardware-backed** | The Vault's signing key never leaves a Secure Enclave / TPM / HSM. |\n| 🙅 | **Fail-closed** | Unknown vault, bad sigalg, untrusted clock, or unavailable replay store all reject. |\n| 📓 | **Auditable** | Every mint is a hash-chained audit entry. |\n| 🚨 | **Revocable** | Panic-lock / revocation epoch can kill outstanding leases. |\n| 🔌 | **Transport-agnostic** | HTTP header, QR / deep link, BLE, USB. |\n\n---\n\n## 🆚 Against the alternatives\n\n| Property | Password + 2FA | Passkey / WebAuthn | OAuth token | **Symbolon lease** |\n|---|:---:|:---:|:---:|:---:|\n| Long-lived secret at server | ✅ has one | ❌ | ✅ refresh | ❌ **none** |\n| One-time use | ❌ | ❌ | ❌ | ✅ |\n| Time-boxed to minutes | ❌ | ❌ | ◑ | ✅ |\n| Device-bound | ❌ | ◑ | ❌ | ✅ |\n| Action-bound (fine-grained) | ❌ | ❌ | ◑ | ✅ |\n| Offline-verifiable | ✅ | ✅ | ❌ | ✅ |\n| Independent of an IdP | n/a | ❌ | ❌ | ✅ |\n\n---\n\n## 🧩 The lease\n\n```jsonc\n{\n  \"v\": 1,\n  \"type\": \"symbolon.lease\",\n  \"jti\": \"01JBYZK8R7E1Q3X9TWMV4PG2YH\",   // single-use id\n  \"vault_id\": \"vault:01JBYZ…\",\n  \"subject_id\": \"usr_01JBYZ…\",\n  \"app_id\": \"xgs.admin\",                   // app-bound\n  \"device_id\": \"dev_01JBYZ…\",              // device-bound\n  \"not_before\": \"2026-06-04T19:00:00Z\",\n  \"not_after\":  \"2026-06-04T19:10:00Z\",    // 10-minute window\n  \"max_session_ttl_sec\": 1800,\n  \"allowed_actions\": [\"login\", \"read\"],    // action-bound\n  \"geo_constraint\": { \"countries\": [\"NL\"] },\n  \"ephemeral_pubkey\": \"z6Mk…\",\n  \"nonce_challenge_required\": true,\n  \"vault_signature\": \"z3Ms…\"               // Ed25519 over JCS\n}\n```\n\nThe signed form is JCS (RFC 8785) of the object with `vault_signature` removed; signature is Ed25519, multibase base58btc (`z` prefix).\n\n---\n\n## 🎯 Where it fits (honest positioning)\n\nSymbolon is an **authorization gate**, not a secrets manager — and not magic.\n\n- **First-party (your own systems)** → Symbolon sits **directly in the path**: auth, session, API, sensitive actions, data gate. Each boundary verifies a lease locally. This is where it replaces standing secrets outright.\n- **Third-party (AWS, SaaS)** → AWS will not verify a lease. Symbolon sits **in front of a broker** (HashiCorp Vault / AWS STS): the broker issues the provider's _native_ short-lived credential only after a valid lease. It **gates issuance — it never replaces IAM and stores no secret.**\n\n\u003e **vs HashiCorp Vault:** Vault is a secrets **store/broker** (its compromise is the jackpot). Symbolon stores **no downstream secrets** — the issuer holds only a signing key, verifiers hold only public keys + spent JTIs. They're complementary: **Vault can _be_ the Symbolon issuer**, taking the server out of the hot path.\n\n---\n\n## 🧨 Breach scenarios — and how each is contained\n\n\u003e Legend: 🟢 defeated · 🟡 strongly contained / mitigated · ⚪ out of scope (adjacent layer)\n\n| Breach / attack | Normal app outcome | How Symbolon contains it | Result |\n|---|---|---|:---:|\n| **Credential DB dump** | All hashes leak; cracked offline; reused elsewhere | No password / long-lived secret is stored to dump | 🟢 |\n| **Phishing for credentials** | Reusable secret captured \u0026 replayed | Nothing reusable exists; single-use, app-bound, signed lease | 🟢 |\n| **Stolen token / cookie replay** | Works repeatedly, from anywhere | One-time `jti` consumed atomically; bound to a non-exportable session key | 🟢 |\n| **Token used past expiry** | Long TTL still valid | Minutes-long window vs a trusted clock | 🟢 |\n| **Token lifted to another device** | Bearer works anywhere | Cryptographic device binding | 🟢 |\n| **Lease tampering** | Editable claims widen access | Ed25519 over JCS covers every field | 🟢 |\n| **Real-time phishing relay (AiTM)** | MFA proxied \u0026 bypassed | Mandatory origin/audience binding _(v1)_ + live possession challenge | 🟡 |\n| **Physical device theft** | Saved creds handed over | Fresh biometric per mint; signing key sealed in hardware | 🟢 |\n| **Verifier / app-server breach** | Secrets + sessions exfiltrated | No secret store; issuer keys pinned via signed config | 🟡 |\n| **Issuer / Vault key compromise** | — | Segmented + **co-signed** issuers; revocation epoch; hash-chained audit | 🟡 |\n| **Supply chain (CI secret / npm token)** | Poisoned release shipped | Proof-bound, single-use release lease via broker; no standing CI secret | 🟡 |\n| **Insider / admin misuse** | One admin = god mode | Step-up + quorum + scoped admin leases + audit | 🟡 |\n| **Session hijack after login** | Stolen cookie rides the session | Session bound to a non-exportable key (DPoP / WebAuthn) | 🟡 |\n| **Clock-skew abuse** | Slow server honors expired lease | Skew ≤ 30 s; **fail-closed** if clock untrusted | 🟢 |\n| **Replay-store outage** | — | **Fail-closed**: reject rather than risk a double-spend | 🟢 |\n| **Endpoint malware at mint time** | Full takeover | Limits duration \u0026 scope only — _does not_ stop a present attacker | ⚪ |\n\n---\n\n## 🧱 No single point of failure · graceful fallback\n\n**Design principles that remove the single catastrophic point:**\n\n- **Offline verification** — no central server in the request path, so the issuer being down never stops verification of already-minted leases.\n- **Segmented issuers** — separate keys for login / admin / workload / broker / recovery; one compromise affects only its domain.\n- **Co-signing (k-of-n)** for high-risk issuers — no single signer can mint alone (multi-signature leases; MPC is a later optimization, not a dependency).\n- **Durable, atomic replay store** — consumption survives reboots; concurrent double-spend impossible.\n- **Signed revocation snapshots** — short TTL + monotonic anti-rollback `seq`; a fast kill switch with no per-request callback.\n\n**Fallback behavior — _\"when X fails\"_:**\n\n| Component fails | What still works | Fallback behavior |\n|---|---|---|\n| **Issuer / Vault offline** | Verification of existing leases; live sessions | New mints pause; no new sensitive actions until it returns |\n| **One issuer key compromised** | Every other domain | Revoke that key's epoch via the signed feed; co-signers still required |\n| **Verifier instance down** | Any other instance (stateless verify) | Horizontal — any node verifies with cached keys |\n| **Revocation feed stale** | Low-risk reads | Sensitive actions **blocked** until a fresh snapshot (degrade closed) |\n| **Revocation feed unreachable** | Cached snapshot until its `expires_at` | After expiry: **fail-closed** for sensitive; basic availability continues |\n| **Replay store unavailable** | — | **Fail-closed**: reject |\n| **Clock untrusted (NTP down)** | — | **Fail-closed**: reject rather than guess time |\n| **Network partition (data ↔ control plane)** | Offline verification | Mint + revocation refresh pause; verify continues on cached state |\n| **Lost user device / Vault** | Account intact | Recovery issuer + quorum (break-glass) re-enrolls a new device |\n\n\u003e This is constraint #4 made concrete: **failure degrades closed for sensitive actions, while basic availability continues.**\n\n---\n\n## 📉 Critical analysis — damage \u0026 blast-radius reduction\n\n\u003e **Not a scientific guarantee.** These are engineering estimates for a **Symbolon-first first-party app** (you own the app, API, DB, broker and policy). Real numbers depend on implementation depth and adoption. Measure the delta against a _modern_ baseline (passkeys + short-lived tokens + DPoP), not a password+cookie app.\n\n**The addressable slice of today's breaches:**\n\n- **~80%** of breaches involve a credential or human element.\n- Of those, the **majority rely on a reusable / standing / bearer secret** — the part Symbolon structurally removes for systems you control. Realistically **~55–70% of all breaches are _structurally addressable_** by first-party Symbolon.\n- The rest — endpoint malware at mint, socially-engineered approval, third-party SaaS you don't own — are **largely out of scope**, and Symbolon should not claim them.\n\n**Where the reduction actually lands — it shrinks _impact and dwell time_ more than _initial intrusion_:**\n\n| Dimension | Today | Symbolon-first | Effect |\n|---|---|---|---|\n| Credential lifetime | months → until manual rotation | **minutes** | ~100–1000× shorter window |\n| Scope of one credential | broad / standing | **one action, one resource** | least-privilege by default |\n| Lateral movement | ambient session unlocks everything | **each hop needs a fresh lease** | escalation no longer automatic |\n| Secrets exposed by one store breach | many | **≈ zero** (no store) | the \"jackpot\" disappears |\n| Attacker dwell time | weeks–months (until noticed) | **bounded by TTL + revocation epoch** | minutes–hours |\n| Single-credential takeover | common | **insufficient on its own** | needs several factors at once |\n\n**Blast radius — what _one_ compromise yields:**\n\n| Attacker gets… | Normal app | Symbolon-first |\n|---|---|---|\n| A leaked secret / key | Standing access until rotated | An already-expired, scoped ticket |\n| App-server shell | Direct path to data \u0026 secrets | A shell that still lacks a fresh action lease |\n| The credential store | **Everything** | There is no store — nothing to take |\n| One issuer key | — | One **segment** only; co-signers still required |\n\n**Honest bottom line:**\n\n- **Initial intrusion likelihood:** modestly reduced (phishing/credential-stuffing classes mostly removed; endpoint/social vectors remain).\n- **Breach _impact_ \u0026 blast radius:** **reduced sharply** — a single foothold stops auto-escalating into a full compromise.\n- **Realistic overall posture** for a well-built Symbolon-first app: materially stronger, **because single-point compromise stops being sufficient** — not because any number approaches 100%. A half-enforced deployment regresses toward the baseline.\n\n\u003e The strongest defensible claim: **Symbolon turns most \"one stolen credential → full breach\" events into \"one stolen credential → a spent, scoped, minutes-old ticket.\"**\n\n---\n\n## 📊 Status\n\n| Component | Version | Status |\n|---|---|---|\n| Protocol spec | v0.1 | **Draft.** Breaking changes expected before v1.0. |\n| JSON Schema | v1 | Draft, tracks spec v0.1. |\n| Test vectors | v0.1 | Draft, placeholder signatures. |\n| Reference verifier (Go) | — | Not yet started. |\n| Reference vault (iOS / Android) | — | Not yet started. |\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd valign=\"top\"\u003e\n\n**✅ In the spec today**\n- Human login lease (fresh proof)\n- Offline Ed25519 / JCS verification\n- One-time JTI · time window\n- App \u0026 device binding\n- §4 algorithm · §6 error codes\n\n\u003c/td\u003e\n\u003ctd valign=\"top\"\u003e\n\n**◵ Designed · v1 roadmap**\n- Mandatory origin / audience binding\n- Cryptographic device + non-exportable session key\n- Signed revocation feed (anti-rollback, fail-closed)\n- Segmented, co-signed issuers\n- Machine / DB / CI auth profile (TPM · SPIFFE · OIDC)\n- AWS = Symbolon-gated STS broker\n\n\u003c/td\u003e\n\u003ctd valign=\"top\"\u003e\n\n**❌ Not goals**\n- A secrets manager / store\n- A replacement for AWS IAM\n- A full zero-trust mesh on day one\n- Protecting SaaS you don't control\n- Stopping malware already on the device at mint\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n\u003e **Residual risks we don't paper over:** endpoint malware present _at mint time_ can ride that window; the policy engine and any field-level encryption are _separate systems_; a lone invocable signing key stays catastrophic until co-signing ships. The win is structural — **single-point compromise becomes insufficient** — not a guarantee against everything.\n\n---\n\n## 📁 Repository\n\n```\nsymbolon/\n├── spec/\n│   ├── symbolon-protocol-v0.1.md       ← normative protocol spec\n│   └── symbolon-threat-model-v0.1.md   ← what it defends, what it doesn't\n├── schema/\n│   └── symbolon-lease-v1.schema.json   ← JSON Schema (Draft 2020-12)\n├── test-vectors/\n│   └── symbolon-test-vectors-v0.1.json ← signed lease fixtures\n├── docs/\n│   └── symbolon-v1-strategy.md         ← architecture, MVP \u0026 honest scorecard\n└── showcase/\n    └── index.html                      ← interactive showcase page\n```\n\n**Reading order:** [protocol spec](./spec/symbolon-protocol-v0.1.md) → [threat model](./spec/symbolon-threat-model-v0.1.md) → [JSON Schema](./schema/symbolon-lease-v1.schema.json) → [v1 strategy](./docs/symbolon-v1-strategy.md).\n\n---\n\n## 🗺 MVP (Minimal Strong Version)\n\nThe first buildable kit — and the only thing to build first:\n\n1. **Login lease** (proof-minted)\n2. **DPoP / session-bound non-exportable key**\n3. **Sensitive-action lease**\n4. **AWS STS broker lease** (verifies lease → `AssumeRole` → temp creds; **no AWS key stored**)\n5. **Signed revocation snapshot**\n6. **Segmented issuer keys** + multi-signature leases\n\n_Deferred: DB/data mesh, full service mesh, field encryption, MPC, exhaustive provider coverage._ See [`docs/symbolon-v1-strategy.md`](./docs/symbolon-v1-strategy.md).\n\n---\n\n## 📄 License \u0026 contributing\n\nLicense **TBD** before public release (Apache-2.0 for the spec is the leading candidate). This project is **pre-release** — the spec is being stabilised internally first, and external contributions are not yet accepted.\n\n\u003cdiv align=\"center\"\u003e\n\n\u003cbr\u003e\n\n**⬡ Symbolon** — _the broken token, made cryptographic._\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fftahirops%2Fsymbolon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fftahirops%2Fsymbolon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fftahirops%2Fsymbolon/lists"}