{"id":51678364,"url":"https://github.com/powplowdevs/zero-trust-mtls-server","last_synced_at":"2026-07-15T09:33:27.841Z","repository":{"id":366435753,"uuid":"1276283222","full_name":"powplowdevs/zero-trust-mtls-server","owner":"powplowdevs","description":"A mutual-TLS (mTLS) zero-trust authentication server written in Go.","archived":false,"fork":false,"pushed_at":"2026-07-01T22:08:30.000Z","size":3473,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-02T00:11:29.970Z","etag":null,"topics":["authentication","dashboard","go","homelab","mtls","mtls-authentication","mutal-tls","security","security-tools","tls","x509","zero-trust"],"latest_commit_sha":null,"homepage":"","language":"Go","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/powplowdevs.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-21T19:25:11.000Z","updated_at":"2026-07-01T22:08:34.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/powplowdevs/zero-trust-mtls-server","commit_stats":null,"previous_names":["powplowdevs/zero-trust-mtls-server"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/powplowdevs/zero-trust-mtls-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/powplowdevs%2Fzero-trust-mtls-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/powplowdevs%2Fzero-trust-mtls-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/powplowdevs%2Fzero-trust-mtls-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/powplowdevs%2Fzero-trust-mtls-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/powplowdevs","download_url":"https://codeload.github.com/powplowdevs/zero-trust-mtls-server/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/powplowdevs%2Fzero-trust-mtls-server/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35499864,"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-07-15T02:00:06.706Z","response_time":131,"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":["authentication","dashboard","go","homelab","mtls","mtls-authentication","mutal-tls","security","security-tools","tls","x509","zero-trust"],"created_at":"2026-07-15T09:33:27.113Z","updated_at":"2026-07-15T09:33:27.833Z","avatar_url":"https://github.com/powplowdevs.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- Banner Divider --\u003e\n\u003cimg align=\"center\" src=\"https://user-images.githubusercontent.com/73097560/115834477-dbab4500-a447-11eb-908a-139a6edaec5c.gif\"\u003e\n\n\u003c!-- Project Name --\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003e\u003ccode\u003ezero-trust-mtls-server\u003c/code\u003e\u003c/h1\u003e\n  \u003ch3\u003eVersion 1.0\u003c/h3\u003e\n\u003c/div\u003e\n\n\u003c!-- Typing Banner --\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://readme-typing-svg.demolab.com?font=Fira+Code\u0026pause=1000\u0026color=3B82F6\u0026center=true\u0026vCenter=true\u0026width=600\u0026lines=Mutual-TLS+zero-trust+authentication\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/github/license/powplowdevs/zero-trust-mtls-server?style=flat-square\" /\u003e\n  \u003cimg src=\"https://img.shields.io/github/stars/powplowdevs/zero-trust-mtls-server?style=flat-square\" /\u003e\n  \u003cimg src=\"https://img.shields.io/github/issues/powplowdevs/zero-trust-mtls-server?style=flat-square\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Go-1.22+-00ADD8?style=flat-square\u0026logo=go\u0026logoColor=white\" /\u003e\n\u003c/p\u003e\n\n---\n\n## 📌 What is this?\n\nA **mutual-TLS (mTLS) authentication server** written in Go, built as a portfolio and learning project.\n\nEvery user authenticates with a client certificate that the server cryptographically verifies, instead of relying on a password or token alone. It runs as a single Go binary with a small web UI, and a setup wizard that gets you from a fresh clone to a running server in a few commands.\n\n---\n\n## ✨ What it can do\n\n- **Certificate-based login** — users authenticate with a CA-signed client certificate plus a password.\n- **Device enrollment** — users generate a key and CSR, submit a request, and an admin approves and signs it. The private key never leaves the user's machine.\n- **Permission-based access** — granular permissions (`system_admin`, `manage_devices`, `manage_users`, `manage_pending`, `view_audit_logs`) gate every page and endpoint.\n- **Instant device revocation** — revoke a device with one toggle and it's denied on its next request.\n- **User \u0026 device management** — review and remove users and devices from the browser.\n- **Audit logging** — every login and access event is logged as structured JSON, with a built-in filterable, color-coded log viewer.\n\n---\n\n## ⚙️ How a request flows\n\nThe client certificate is the identity anchor. Everything is derived from it on every request:\n\n```\nclient certificate  ──►  SHA256 fingerprint  ──►  device  ──►  owner  ──►  permissions\n```\n\n**Logging in:**\n\n1. The browser presents a client certificate during the TLS handshake. If it isn't signed by the server's CA, the connection is refused so unenrolled clients can't get in at all.\n2. The server hashes the certificate into a fingerprint and looks it up to find the device, its owner, and that user's permissions.\n3. The user submits their password. The server checks it **and** checks that the certificate belongs to the same user, so a valid certificate can't be used to log in as someone else.\n4. On success, a session is created server side. The session stores the certificate's fingerprint, and the browser gets only a random session ID in a cookie.\n\n**Every request after that:**\n\n1. The server recomputes the fingerprint from the certificate presented on *this* request and confirms it matches the one bound to the session. A stolen cookie is useless without the matching certificate and key.\n2. Permissions are looked up fresh from the certificate every time, never cached in the session.\n\nBecause authorization is re-derived from the live certificate on every request, **revoking a device takes effect immediately**, the fingerprint stops resolving, and the next request is denied with no sessions to clear.\n\n---\n\n## 📦 Setup\n\n\u003e **Requirements:** [Go 1.22+](https://go.dev/dl/). Run all commands from the **project root** (the folder containing `data/`, `certs/`, and `static/`).\n\n### 1. Clone\n\n```bash\ngit clone https://github.com/powplowdevs/zero-trust-mtls-server.git\ncd zero-trust-mtls-server\n```\n\n### 2. Run the setup wizard\n\nThe wizard will handle creating a first admin and its certificates along with the Certificate Authority and the server's own TLS certificate.\n\n```bash\ngo build -o setup ./setup\n./setup\n```\n\nThe wizard will:\n\n1. **Generate a Certificate Authority** (`certs/ca.crt` + `certs/ca.key`), the root of trust for every certificate. *(Re-running reuses the existing CA by default; pass `--new-ca` to regenerate, which invalidates all existing certificates.)*\n2. **Generate the server's TLS certificate**, automatically valid for `localhost`, `127.0.0.1`, and your machine's detected LAN IP.\n3. **Create the first admin account**, prompts for a device name and password (minimum 8 characters, with at least one uppercase letter and one number).\n\nIt writes the admin's certificate bundle to **`certs/admin.p12`** and prints import instructions.\n\n### 3. Import the admin certificate into your browser\n\nThe admin (and every user) logs in with a certificate held by their browser. Import `certs/admin.p12`:\n\n- **Firefox:** Settings → Privacy \u0026 Security → Certificates → *View Certificates* → *Your Certificates* → *Import* → select `certs/admin.p12`\n- **Chrome / Edge:** Settings → Privacy and security → Security → *Manage certificates* → *Import* → select `certs/admin.p12`\n\n\u003e The `.p12` has an empty export password for convenience. After importing, you can delete `certs/admin.crt` and `certs/admin.p12` from the server, keep `certs/admin.key` private and never commit it.\n\n### 4. Configure email (for certificate delivery)\n\nWhen an admin approves an enrollment, the signed certificate is **emailed** to the user. Set your SMTP details in `config.json`:\n\n```jsonc\n{\n  \"smtp_host\":     \"smtp.gmail.com\",        // your SMTP server\n  \"smtp_port\":     \"587\",                   // typically 587 (TLS) or 465 (SSL)\n  \"smtp_username\": \"you@example.com\",       // the sending account\n  \"smtp_password\": \"your-app-password\"      // see note below\n}\n```\n\n\u003e **Use an App Password, not your real password.** Most providers (Gmail included) won't accept your normal account password for SMTP. Enable 2-factor authentication on the account, generate a dedicated **App Password**, and use that as `smtp_password`.\n\nYou can skip this for local testing, but enrollment approvals won't be able to deliver certificates until SMTP is configured.\n\n### 5. Build and run the server\n\n```bash\ngo build -o zts .\n./zts\n```\n\nThe server starts on `https://localhost:8443`. Open it, present the admin certificate when prompted, and log in as `admin` with the password you set.\n\n### 6. Enroll more users\n\nOnce you're logged in as admin, other users enroll through the web UI:\n\n1. They visit `/enroll`, follow the steps to generate a key and CSR, and submit the request.\n2. You review it under **Pending**, grant permissions, and approve, the server signs their certificate and emails it.\n3. They import their certificate and log in.\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpowplowdevs%2Fzero-trust-mtls-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpowplowdevs%2Fzero-trust-mtls-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpowplowdevs%2Fzero-trust-mtls-server/lists"}