added passkey support (closes #6)
All checks were successful
test-and-lint / test-and-lint (pull_request) Successful in 2m50s

This commit is contained in:
2026-06-10 03:24:31 +02:00
parent 01ec41288a
commit fb3be56959
18 changed files with 1680 additions and 61 deletions

View File

@@ -1,6 +1,6 @@
# MiauInv
MiauInv is a lightweight inventory, stock, and project allocation management system written in Go. It provides a server-rendered dashboard with HTMX-style page composition, vanilla JavaScript for API interactions, SQLite for persistence, JWT-based sessions, refresh-token rotation, account settings, and optional TOTP-based two-factor authentication.
MiauInv is a lightweight inventory, stock, and project allocation management system written in Go. It provides a server-rendered dashboard with HTMX-style page composition, vanilla JavaScript for API interactions, SQLite for persistence, JWT-based sessions, refresh-token rotation, account settings, and optional TOTP-based two-factor authentication and WebAuthn passkey authentication.
The project is designed for self-hosted/private deployments. It is not a full enterprise asset-management platform, but it already covers the main workflows needed for tracking items, locations, stock distribution, and project allocations.
@@ -38,9 +38,9 @@ The project is designed for self-hosted/private deployments. It is not a full en
- Database-backed refresh tokens with rotation.
- HTTP-only secure cookies for access and refresh tokens.
- Account settings page at `/profile/settings`.
- Passkey registration, login, removal, and full passkey disable from account settings.
- Username change with password confirmation.
- Password change with old-password verification and session refresh.
- Avatar placeholder in the account settings UI for a later avatar implementation.
### Two-factor authentication
@@ -57,11 +57,21 @@ The project is designed for self-hosted/private deployments. It is not a full en
- The setup secret is only stored after the first valid authenticator code.
- Existing refresh sessions are revoked when 2FA is enabled or disabled.
### Passkeys
- WebAuthn-based passkey registration from account settings.
- Passkey login from the normal sign-in page.
- Discoverable passkey login without entering a username first.
- User-verification required for registration and login.
- Server-side challenge storage using opaque one-time challenge tokens.
- Passkey removal with current-password confirmation.
- Full passkey disable with current-password confirmation.
- Existing refresh sessions are revoked when passkeys are added, removed, or disabled.
## Current Status
MiauInv is an active private project. The current version supports core inventory workflows and account-level security settings. Some areas are intentionally still basic:
- Avatar support is currently only represented by a placeholder in the UI.
- There is no dedicated admin panel yet.
- Basic in-memory rate limiting protects login, 2FA, refresh, registration, and sensitive account endpoints.
- Automated testing is currently limited and will be expanded in future releases.
@@ -77,6 +87,7 @@ MiauInv is an active private project. The current version supports core inventor
| Authentication | JWT via `github.com/golang-jwt/jwt/v5` |
| Password hashing | bcrypt via `golang.org/x/crypto/bcrypt` |
| 2FA | TOTP via `github.com/pquerna/otp/totp` |
| Passkeys | WebAuthn via `github.com/go-webauthn/webauthn` |
| Frontend | Server-rendered HTML, HTMX-style structure, vanilla JavaScript |
| Styling | Custom CSS with dark theme variables |
| Deployment | Docker / Docker Compose |
@@ -155,7 +166,7 @@ openssl rand -base64 48
| `/items` | `GET` | Yes | Item management view. |
| `/locations` | `GET` | Yes | Location management view. |
| `/projects` | `GET` | Yes | Project management view. |
| `/profile/settings` | `GET` | Yes | Account settings, password changes, 2FA setup, 2FA disable, and recovery-code management. |
| `/profile/settings` | `GET` | Yes | Account settings, password changes, passkey management, 2FA setup, 2FA disable, and recovery-code management. |
| `/profile/` | `GET` | No | Placeholder page for unfinished profile subpages. |
| `/assets/*` | `GET` | No | Static CSS/JS assets. Minified CSS/JS variants are generated on request. |
@@ -176,6 +187,13 @@ openssl rand -base64 48
| `/api/2fa/enable` | `POST` | Yes | Enables 2FA after validating the temporary setup token and a TOTP code. Replaces recovery codes and revokes old sessions. |
| `/api/2fa/disable` | `POST` | Yes | Disables 2FA after password and TOTP confirmation. Revokes sessions and clears auth cookies. |
| `/api/2fa/recovery-codes/regenerate` | `POST` | Yes | Invalidates existing recovery codes and returns a new set after password and TOTP confirmation. |
| `/api/passkeys` | `GET` | Yes | Lists passkeys registered for the current user. |
| `/api/passkeys` | `DELETE` | Yes | Removes one passkey after current-password confirmation. |
| `/api/passkeys/register/options` | `POST` | Yes | Creates a server-side passkey registration challenge after current-password confirmation. |
| `/api/passkeys/register/finish` | `POST` | Yes | Verifies and stores a new passkey credential. Revokes old sessions and issues a new current session. |
| `/api/passkeys/login/options` | `POST` | No | Creates a discoverable passkey login challenge. |
| `/api/passkeys/login/finish` | `POST` | No | Verifies passkey login and issues a full session. |
| `/api/passkeys/disable` | `POST` | Yes | Deletes all passkeys after current-password confirmation. Revokes old sessions and issues a new current session. |
### Inventory API
@@ -304,10 +322,11 @@ For Docker deployments, place Caddy and MiauInv on the same Docker network and r
- Access tokens expire after 15 minutes.
- Refresh tokens expire after 7 days and are rotated on refresh.
- Refresh tokens and recovery codes are stored in the database as hashes.
- Passkey credentials store public-key credential data, not private keys. Private keys remain in the authenticator or platform passkey provider.
- TOTP secrets are currently stored in the database because the server must validate codes. Protect the database file accordingly.
- Recovery codes are only shown when generated. Users should download or copy them immediately. The UI warns when few unused codes remain.
- 2FA disable and recovery-code regeneration require both the current password and a valid TOTP code.
- Basic in-memory rate limiting is enabled for login, 2FA, refresh, registration, and sensitive account endpoints. Use persistent or distributed rate limiting for multi-instance deployments.
- Basic in-memory rate limiting is enabled for login, passkey ceremonies, 2FA, refresh, registration, and sensitive account endpoints. Use persistent or distributed rate limiting for multi-instance deployments.
- Automated testing is currently limited. Authentication, 2FA, recovery codes, rate limiting, account settings, and inventory handlers should be covered before production use.
## Screenshots