Simplify gRPC auth: password-per-request over TLS

- gRPC sync sends username+password in metadata on every RPC,
  verified by unary interceptor. No login RPC or token management.
- Password stored in Android EncryptedSharedPreferences (Keystore)
- Web UI retains bearer token flow for browser sessions
- FIDO2/U2F scoped to web UI only, not gRPC sync path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 19:35:40 -07:00
parent 5d74ebdd91
commit 8b13a61832

View File

@@ -276,23 +276,44 @@ render at 300 DPI for JPG.
## Authentication
### Password Auth
### gRPC Auth (Android App)
The app sends `username` and `password` in gRPC metadata on every
sync RPC. No separate login step, no token management on the app side.
- TLS required — no plaintext gRPC connections accepted
- A unary interceptor extracts credentials from metadata, verifies
the password against Argon2id hash in the DB
- If invalid, returns `UNAUTHENTICATED`
- Password stored on the Android device in EncryptedSharedPreferences
(hardware-backed Android Keystore)
This is simpler than a token-based flow and acceptable because:
- Sync is manual and infrequent
- The password travels over TLS
- The app stores the password in hardware-backed encrypted storage
### Web Auth (Password + Bearer Token)
The web UI uses a traditional login flow:
- `POST /v1/auth/login` with username/password → returns bearer token
- Token stored as `HttpOnly`, `Secure`, `SameSite=Strict` session cookie
- Token validated via SHA-256 keyed lookup with short TTL cache
- Argon2id hashing (memory-hard, tuned to hardware)
- Bearer tokens returned on login, stored as session cookies for web UI
- Token validation via SHA-256 keyed lookup with short TTL cache
### FIDO2/U2F (WebAuthn)
### FIDO2/U2F (WebAuthn) — Web UI Only
Users can register multiple security keys after initial password login.
Once registered, keys can be used as an alternative login method.
Once registered, keys can be used as an alternative login method for
the web UI. This does not apply to the gRPC sync path.
Implementation via the `go-webauthn/webauthn` library:
1. **Registration flow**:
- User logs in with password
- User logs in with password via web UI
- Calls `POST /v1/auth/webauthn/register/begin` → gets challenge
- Browser/client signs challenge with security key
- Browser signs challenge with security key
- Calls `POST /v1/auth/webauthn/register/finish` with attestation
- Server stores credential in `webauthn_credentials` table
@@ -341,8 +362,10 @@ New files:
### Configuration
Server URL and auth token stored in `EngPadApp` SharedPreferences.
First sync prompts for server URL and login credentials.
Server URL, username, and password stored in Android
EncryptedSharedPreferences (hardware-backed Keystore). Configured
via a Sync settings screen accessible from the library view.
First sync prompts for server URL and credentials if not configured.
## Server Repository Layout