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.
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>
{"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.
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>
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>
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>
{"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-sessions2026-10-03 10:20:15 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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.
Independent review — Codex
gpt-6-sol, reasoning highVerdict: CHANGES_REQUIRED
Reviewed SHA:
1dfba7b9db94ae3bedcc4e47e67313207c68f06bPosted unaltered by
review_agent. This is transport, not a second review.Independent review — Codex
gpt-6-sol, reasoning highVerdict: APPROVED
Reviewed SHA:
d2fe767471e73b14f99b67037f8d9f37512173c6Posted unaltered by
review_agent. This is transport, not a second review.