Build base login and project-gated admin access
Build real browser login and an initial admin panel for the independent identity platform. Confirmed requirement: - A user must be assigned to an admin UI project to enter the admin panel. - Reuse the existing Maud/Vite/Stimulus frontend, typed application boundaries, tenant-scoped PostgreSQL state, and transactional history conventions. - Repository starts clean at 1406873. Do not commit or change production services. Agreed initial scope: - Password-based login, logout, server-side revocable sessions, secure cookie/CSRF conventions, generic credential errors, bounded password processing and login-attempt controls; essential browser flows work without JavaScript. - Model users/credentials, projects, and project assignments explicitly. Keep credential hashes/session secrets out of history, outbox payloads, logs, templates, and ordinary domain representations. - Separate authentication from admin-panel eligibility and from permission grants; check current user/project/assignment state on protected requests rather than trusting stale cookie claims. - Bootstrap the first synthetic administrator through an explicit local command, not public registration or hardcoded credentials. Provide a small admin landing page and no unrelated identity protocols. - Add migrations and explicit runtime privileges, preserving tenant isolation and auditable assignment changes. Use only the dedicated synthetic fixture; never import existing ZITADEL users or credentials. Kaukus requirements findings (local Kaukus/Kaukus checkout f6d94ed14; read-only code inspection): - app/models/user.rb models globally unique email and one user with multiple municipalities through roles. Active application roles and confirmation control application authentication eligibility. - app/models/role.rb has municipality/committee-scoped customer roles and municipality-independent Kaukus admin/support roles. app/models/ability.rb keeps fine-grained resource rules and staff restrictions in Kaukus, not the IdP. - app/services/zitadel/client.rb first searches globally by email, then creates a missing user in the default municipality's organization and caches stable external IDs. Current org ownership should not be mistaken for a requirement to duplicate identities per customer. - config/initializers/devise.rb uses OIDC authorization code with PKCE for ZITADEL, plus separate Criipto/BankID identity verification. Profile management also supports passkeys, invitations and password recovery through the IdP. - app/services/murmur/oauth_client.rb and Murmur authentication show a distinct machine-to-machine requirement: dedicated service-account subject, audience-scoped signed access tokens, and bounded token lifetime. - User confirmed internal tools such as Sentry also share this identity platform. Sentry's actual deployed SSO configuration/protocol was not located or inspected; do not assume a specific protocol or current mapping. Model used for the initial implementation (customer memberships and external clients remain future work): - Start with one Kaukus identity realm/namespace (the existing TenantId can represent this), rather than one issuer/login realm per municipality. - Represent customers/municipalities and the Kaukus operator organization as organizations inside that realm. A reusable human account may have multiple organization memberships; credentials are not duplicated per customer. - Projects are application-access/authorization boundaries (Kaukus, identity-admin, Sentry, Murmur as appropriate), with separate protocol client/application registrations. Organizations are not projects, and customer project access must not imply access to internal tools. - Project assignment gates application entry; explicit scoped roles/permissions control capabilities. Keep detailed meeting/voting/secretary/committee rules in Kaukus. Kaukus business-admin status must not automatically imply identity-platform or Sentry administration. - Use stable identity IDs/issuer-subject bindings for application linkage; do not reproduce email-only account matching as the long-term identity key. - Initial identity admin panel should be Kaukus-operator/internal, with explicit identity-admin assignment and an administrator role. Customer-delegated identity administration is a separate scoped extension if required. Confirmed by user: customers do not use the identity provider's admin panel. They manage users through Kaukus's integration; the new provisioning/management API will be built later. Implement only Kaukus-operator identity administration now, with explicit admin-project assignment plus administrator role. No customer-facing admin UI or provisioning API in this slice. Acceptance: - Valid active users can sign in and out without JavaScript; invalid credentials fail generically. - Only currently eligible project-assigned users can access the admin panel; removing access or disabling an account revokes protected access for existing sessions. - Browser sessions, CSRF, cookie boundaries, password verification, tenant scope, concurrency/rechecks, history field selection, and bootstrap are exercised by meaningful unit, synthetic PostgreSQL, HTTP, and real-browser tests. - Existing format/Clippy/Rust, frontend, dev-tooling and browser gates pass. Document limitations without claiming production readiness. Implemented and verified; repository changes remain uncommitted. - Migration 0002 adds realm-scoped users/credentials, projects, explicit roles/assignments/bindings, configured admin-project linkage, revocable sessions, bounded attempt counters, and minimal security events. Curated business-state snapshots/outbox writes are database-enforced; credential/session/CSRF data is excluded. - First-operator bootstrap is migration-role-only, single-use, serialized per realm, and transactional across account/password/project/role/assignment/history. CLI uses a hidden confirmed prompt or stdin, never password arguments. The dev helper has an explicit bootstrap-admin command; no known operator password is installed automatically. - Argon2id verification uses bounded parameters/work capacity, unknown-user dummy work, persistent email/IP budgets, and post-hash state rechecks. A narrow realm-scoped owner locking function preserves runtime read-only privileges on users/credentials. Account disable revokes sessions atomically; credential versions and current project/assignment/role states are rechecked on protected requests. - Server-side browser sessions rotate handle and CSRF material at login and invalidate on logout; cookies are HttpOnly/SameSite=Lax with host-only Secure policy for HTTPS and an explicit loopback development alternative. POSTs require exact configured Origin and session-bound CSRF; duplicate cookies/origins fail closed. Referrer policy is same-origin so native Chromium POSTs retain Origin; null origins remain rejected. - Maud login/logout/access-denied and an internal read-only admin landing page reuse shared components and work without JavaScript in both themes. The demo bearer token cannot enter administration. Customer provisioning APIs, management actions, protocol clients and customer memberships remain separate work. Validation passed: - Cargo fmt/check, strict workspace/all-target/all-feature Clippy, 43 non-browser Rust tests (including nine new synthetic authentication integration tests), five dev-tool tests, locked asset checks/build, Python syntax and whitespace checks. - Browser gate passes the existing eight development/built × light/dark × JS on/off cases and four built-mode authentication theme/JS cases in a separate fresh synthetic database with CLI bootstrap and an unassigned test user. Native Origin headers, credential errors, access denial, rotation/replay, forged logout, real logout and mobile overflow are verified. Login/admin screenshots were visually inspected. Browser-only authentication is excluded from the ordinary test gate. - Concurrency tests cover single-use bootstrap, one-use anonymous challenges, and disabling a user while post-hash verification waits for locks. Outbox fault injection proves bootstrap rollback; history excludes secrets. Owned test servers were stopped and browser test databases dropped; no production data/services or other repositories were changed. Documentation: docs/authentication.md, README.md and frontend/README.md describe usage, model, limits and security boundaries. The existing diagram remains explicitly foundation-v1-only. Outstanding production capabilities: MFA/passkeys, recovery/reset/invitations, email verification, customer APIs, external OIDC/SAML/BankID, granular management permissions, localization, operator recovery, production TLS/proxy/perimeter policy, password blocklist/rehash upgrades, and retention/tamper-evidence review. No production readiness or full accessibility/security audit is claimed.
Checklist
4 of 4 complete- Add realm-scoped users/credentials, projects/roles/assignments, and first-operator bootstrap with explicit auditable business-state changes and no secret snapshots.
- Implement bounded password authentication, revocable server-side sessions, CSRF/cookie boundaries, and current-state admin-project/role authorization.
- Build accessible no-JavaScript login/logout and an internal-only admin landing page using shared components and both themes.
- Verify credential failure, revocation, tenant/project boundaries, session fixation/expiry, CSRF, secret exclusion, bootstrap concurrency, and real-browser flows; pass existing gates and document limitations.