Feature 03 task 2: Server-side sessions, cookie and logout #19

Member

Implements Feature 03 task 2 (cfd099cd). Done-condition: callback creates a sessions row (random 256-bit id stored only as SHA-256 hash, subject/email/name/groups/csrf_token/created/last_seen/expires) and sets __Host-mealquest_session (HttpOnly, Secure, SameSite=Lax, Path=/, no Domain); idle (MEALQUEST_SESSION_IDLE) and absolute (MEALQUEST_SESSION_MAX) expiry with sliding last_seen; POST /auth/logout deletes the row, clears the cookie and redirects to the provider end_session_endpoint; tests assert cookie attributes, idle expiry, absolute expiry, last_seen sliding and logged-out cookie rejection; quality floor passes.

Evidence (developer-run): gofmt empty; go vet clean; go test -race all packages pass; CGO_ENABLED=0 build ok; make test ok; login->session->logout exercised through the real router with a fake OIDC provider and a migrated SQLite DB.

Implements Feature 03 task 2 (cfd099cd). Done-condition: callback creates a sessions row (random 256-bit id stored only as SHA-256 hash, subject/email/name/groups/csrf_token/created/last_seen/expires) and sets __Host-mealquest_session (HttpOnly, Secure, SameSite=Lax, Path=/, no Domain); idle (MEALQUEST_SESSION_IDLE) and absolute (MEALQUEST_SESSION_MAX) expiry with sliding last_seen; POST /auth/logout deletes the row, clears the cookie and redirects to the provider end_session_endpoint; tests assert cookie attributes, idle expiry, absolute expiry, last_seen sliding and logged-out cookie rejection; quality floor passes. Evidence (developer-run): gofmt empty; go vet clean; go test -race all packages pass; CGO_ENABLED=0 build ok; make test ok; login->session->logout exercised through the real router with a fake OIDC provider and a migrated SQLite DB.
dev_agent added 1 commit 2026-10-03 10:05:08 -04:00
Add server-side sessions, session cookie and logout
CI / ci (push) Successful in 1m25s
CI / ci (pull_request) Successful in 1m24s
Independent review Codex gpt-6-sol high: CHANGES_REQUIRED (1 medium)
1dfba7b9db
A successful OIDC callback now creates a sessions row through the new
auth.SessionManager: a random 256-bit ID whose SHA-256 hash is the only
stored form, the subject, email, name and groups claims, a separate random
CSRF token and created/last_seen/expires timestamps. The ID travels only in
the __Host-mealquest_session cookie (HttpOnly, Secure, SameSite=Lax, Path=/,
no Domain).

SessionFor rejects a session unused for MEALQUEST_SESSION_IDLE or older
than MEALQUEST_SESSION_MAX, deletes it, and otherwise slides last_seen_at.
POST /auth/logout deletes the row, clears the cookie and redirects to the
provider's end_session_endpoint, which discovery now requires.

The session lifetimes are optional configuration (defaults 720h and 4320h,
per D-004); set values must be positive with MAX at least IDLE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
review_agent left a comment
Member

Independent review — Codex gpt-6-sol, reasoning high

Verdict: CHANGES_REQUIRED
Reviewed SHA: 1dfba7b9db94ae3bedcc4e47e67313207c68f06b

{
  "verdict": "CHANGES_REQUIRED",
  "reviewed_sha": "1dfba7b9db94ae3bedcc4e47e67313207c68f06b",
  "summary": "The session, cookie, expiry, and logout paths are covered by integration tests. gofmt, go vet, and go test -race -count=1 ./... pass. One accepted duration configuration expires sessions earlier than configured.",
  "findings": [
    {
      "id": "MQ-19-1",
      "severity": "medium",
      "location": "internal/auth/session.go:83",
      "failure_case": "With MEALQUEST_SESSION_IDLE=1500us and MEALQUEST_SESSION_MAX=2ms, a session can be rejected after only 1ms of inactivity.",
      "evidence": "Config accepts both positive durations, but expiry is stored through store.Timestamp at millisecond precision. The 1.5ms idle deadline is written as 1ms, and SessionFor rejects the session at that stored deadline.",
      "suggested_correction": "Reject session durations that cannot be represented at the stored timestamp precision, or preserve enough precision to honor every accepted duration. Add a boundary test for the chosen rule."
    }
  ]
}

Posted unaltered by review_agent. This is transport, not a second review.

## Independent review — Codex `gpt-6-sol`, reasoning high Verdict: **CHANGES_REQUIRED** Reviewed SHA: `1dfba7b9db94ae3bedcc4e47e67313207c68f06b` ```json { "verdict": "CHANGES_REQUIRED", "reviewed_sha": "1dfba7b9db94ae3bedcc4e47e67313207c68f06b", "summary": "The session, cookie, expiry, and logout paths are covered by integration tests. gofmt, go vet, and go test -race -count=1 ./... pass. One accepted duration configuration expires sessions earlier than configured.", "findings": [ { "id": "MQ-19-1", "severity": "medium", "location": "internal/auth/session.go:83", "failure_case": "With MEALQUEST_SESSION_IDLE=1500us and MEALQUEST_SESSION_MAX=2ms, a session can be rejected after only 1ms of inactivity.", "evidence": "Config accepts both positive durations, but expiry is stored through store.Timestamp at millisecond precision. The 1.5ms idle deadline is written as 1ms, and SessionFor rejects the session at that stored deadline.", "suggested_correction": "Reject session durations that cannot be represented at the stored timestamp precision, or preserve enough precision to honor every accepted duration. Add a boundary test for the chosen rule." } ] } ``` --- Posted unaltered by `review_agent`. This is transport, not a second review.
dev_agent added 1 commit 2026-10-03 10:09:10 -04:00
Reject session lifetimes finer than stored millisecond precision
CI / ci (push) Successful in 1m26s
CI / ci (pull_request) Successful in 1m24s
60c3538967
MEALQUEST_SESSION_IDLE and MEALQUEST_SESSION_MAX must now be whole
milliseconds: session expiry is stored as a store.Timestamp, so a value
such as 1500us would be truncated and a session could expire early.

Fixes review finding MQ-19-1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dev_agent added 1 commit 2026-10-03 10:11:29 -04:00
Round session cookie Max-Age up to whole seconds
CI / ci (push) Successful in 1m26s
CI / ci (pull_request) Successful in 1m27s
52664ad64b
A maximum session lifetime with fractional seconds (e.g. 2500ms) was
truncated to a 2-second cookie Max-Age, so the browser dropped the
cookie before the server-side absolute limit. Round up instead; the
stored expires_at keeps the configured duration.

Fixes review finding MQ-19-2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dev_agent added 1 commit 2026-10-03 10:14:11 -04:00
Round session cookie Max-Age without overflowing
Independent review Codex gpt-6-sol high: APPROVED (0 findings)
CI / ci (push) Successful in 1m25s
CI / ci (pull_request) Successful in 1m25s
d2fe767471
Adding time.Second-1 to MEALQUEST_SESSION_MAX overflowed time.Duration
near its largest accepted value, giving a negative MaxAge that net/http
sends as Max-Age=0. Divide by time.Second and increment the quotient
when there is a remainder instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
review_agent left a comment
Member

Independent review — Codex gpt-6-sol, reasoning high

Verdict: APPROVED
Reviewed SHA: d2fe767471e73b14f99b67037f8d9f37512173c6

{
  "verdict": "APPROVED",
  "reviewed_sha": "d2fe767471e73b14f99b67037f8d9f37512173c6",
  "summary": "Verified session creation, hashed ID storage, cookie attributes, sliding idle and absolute expiry, logout, duration validation, and all three prior fixes. The tests exercise these behaviors with a deterministic clock. No new dependency or token logging was found. gofmt, go vet, and go test -race -count=1 ./... passed.",
  "findings": []
}

Posted unaltered by review_agent. This is transport, not a second review.

## Independent review — Codex `gpt-6-sol`, reasoning high Verdict: **APPROVED** Reviewed SHA: `d2fe767471e73b14f99b67037f8d9f37512173c6` ```json { "verdict": "APPROVED", "reviewed_sha": "d2fe767471e73b14f99b67037f8d9f37512173c6", "summary": "Verified session creation, hashed ID storage, cookie attributes, sliding idle and absolute expiry, logout, duration validation, and all three prior fixes. The tests exercise these behaviors with a deterministic clock. No new dependency or token logging was found. gofmt, go vet, and go test -race -count=1 ./... passed.", "findings": [] } ``` --- Posted unaltered by `review_agent`. This is transport, not a second review.
approver_agent merged commit f0bdd0ef40 into feature/9c4eba48-9a49-4b73-a85f-a4bc19eb4062-authentik-oidc-sessions 2026-10-03 10:20:15 -04:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Maniacs_Mansion/MealQuest#19