# Phase 005 Execution ## Scope - Added lightweight internal authentication without passwords. - Added database-backed monthly access keys with lazy auto-rotation. - Added random browser tokens stored in encrypted cookies and mapped to users through server-side session records. - Required identification for all application pages except the identify flow and Rails health check. - Replaced temporary `Unknown User` event attribution with the active identified user. - Added request and model specs for authenticated and unauthenticated flows. ## Changes - Added `AccessKey` model and migration. - Added `UserSession` model and migration. - Added `Current` for request-local user/session access. - Added `SessionsController` with identify, create session, and logout behavior. - Added `/identify`, `POST /identify`, and `DELETE /session` routes. - Added `app/views/sessions/new.html.erb` for the “Identify yourself” page. - Updated the application layout to show the identified user and a logout button on authenticated pages. - Updated `ApplicationController` to lazily rotate access keys, load the encrypted-cookie auth token, and require identification by default. - Updated fuel and maintenance entry creation to set `updated_by_user` from `Current.user`. - Removed the temporary `Unknown User` seed and replaced it with initial `AccessKey.current` creation. - Updated vehicle, home, and session request/system specs for the new authentication requirements. ## Decisions - Access keys are stored in plaintext in the database so the server manager can retrieve the current key with `AccessKey.current.raw_key` from Rails console. - Browser clients store only a random auth token in an encrypted cookie. - The database stores only token digests, not raw session tokens. - `AccessKey.rotate!` invalidates all active sessions by deleting `UserSession` records. - Auto-rotation is lazy and runs during normal requests when enabled and expired. - Default auto-rotation frequency is 30 days. - Auto-rotation can be disabled and re-enabled with `AccessKey.current.disable_auto_rotation!` and `AccessKey.current.enable_auto_rotation!`. - The rotation frequency can be changed with `AccessKey.current.update!(auto_rotation_frequency_days: days)`. - Existing users are matched by normalized email and require an exact stored-name match. - `/up` remains publicly accessible for health checks. - `DELETE /session` uses the `logout_path` helper because `session_path` is already used for `POST /identify`. ## Console API ```ruby AccessKey.current.raw_key AccessKey.rotate! AccessKey.current.disable_auto_rotation! AccessKey.current.enable_auto_rotation! AccessKey.current.auto_rotation_frequency_days AccessKey.current.update!(auto_rotation_frequency_days: 60) ``` ## Verification - Passed: `bundle exec rspec spec/models/access_key_spec.rb spec/models/user_session_spec.rb spec/requests/sessions_spec.rb spec/requests/vehicles_spec.rb` - Passed: `bundle exec rspec` - Passed: `bin/rubocop app/models/access_key.rb app/models/user_session.rb app/models/current.rb app/models/user.rb app/controllers/application_controller.rb app/controllers/sessions_controller.rb app/controllers/fuel_entries_controller.rb app/controllers/maintenance_entries_controller.rb spec/models/access_key_spec.rb spec/models/user_session_spec.rb spec/requests/sessions_spec.rb spec/requests/vehicles_spec.rb spec/requests/home_spec.rb spec/system/home_spec.rb db/seeds.rb` - Passed after lint cleanup: `bundle exec rspec`