POWorkspaceagentic kit · product owner
← All runs

Improve the auth method

Author backlog · innovation-group · po-d6d707b7

completedJira: KAN-144, KAN-145, KAN-146, KAN-147, KAN-148
[po-ticket-author running] Phase discovery started: restating intent and resolving ambiguities for auth method improvement
[po-ticket-author running] Phase story started: decomposing into epics and sprint-sized stories with typed Jira fields
[po-ticket-author running] Phase ac started: writing Given/When/Then acceptance criteria for all 5 stories including failure and edge paths

Backlog

Epic: Reliable User Authentication3 stories
  1. Log in with valid credentials
    • Given I am on the /login page with a registered username and password, When I submit the login form, Then the server returns HTTP 200 with a JSON body containing a `token` field and an `expires_at` ISO-8601 timestamp.
    • Given a successful login response with a token, When the token is received by the client, Then it is stored in localStorage under the key `auth_token` and the page redirects to /dashboard within 500 ms.
    • Given the POST /auth/login request fails with HTTP 503, When I submit the login form, Then an inline error banner reads 'Login service unavailable — please try again' and no token is written to localStorage.
  2. Handle login errors clearly
    • Given I submit the login form with a username that does not exist in the system, When the server responds with HTTP 401 and body {"error": "unknown_user"}, Then the form displays the message 'No account found for that username' and the password field is cleared.
    • Given I submit the login form with a correct username but incorrect password, When the server responds with HTTP 401 and body {"error": "invalid_password"}, Then the form displays 'Incorrect password — please try again' and the password field is cleared.
    • Given I have submitted the login form 5 times with wrong credentials, When the 6th attempt is rejected with HTTP 429, Then the form displays 'Too many attempts — please wait 60 seconds' and the submit button has the attribute `disabled` for 60 seconds.
  3. Log out and invalidate session
    • Given I am logged in as an operator, When I click the 'Log out' button, Then a POST request is sent to /auth/logout with the header Authorization: Bearer <token> and the server responds with HTTP 200.
    • Given the logout request returns HTTP 200, When the response is received, Then auth_token is removed from localStorage and the browser redirects to /login within 300 ms.
    • Given my session has been logged out, When I navigate directly to /dashboard, Then the page redirects to /login?next=%2Fdashboard and no requests are made to any /api/ endpoint.
Epic: Protected Route Access2 stories
  1. Redirect unauthenticated users to login
    • Given I have no auth_token in localStorage, When I navigate to any route under /dashboard, Then the browser redirects to /login?next=<url-encoded-original-path> and no /api/ requests are issued.
    • Given I am not authenticated, When I send a GET request to any /api/ endpoint without an Authorization header, Then the server responds with HTTP 401 and JSON body {"error": "unauthenticated"}.
    • Given I am on the /login page with a `next` query parameter, When I log in successfully, Then the browser redirects to the URL specified by the `next` param within 500 ms instead of the default /dashboard.
  2. Access protected API endpoints after login
    • Given I am authenticated with a valid token, When I send GET /api/metrics with header Authorization: Bearer <token>, Then the server responds with HTTP 200 and a JSON body containing a `metrics` array with at least one element.
    • Given I am authenticated with a valid token, When I load the /dashboard page, Then all dashboard widgets render and the page LCP is at most 2500 ms with no redirect to /login.
    • Given my token has expired, When I send any request to /api/ with the expired token, Then the server responds with HTTP 401 and {"error": "token_expired"}, and the client removes auth_token from localStorage and redirects to /login.