---
id: w4/m2/t002
title: Kratos session validation for the GraphQL dashboard surface
worker: worker4
status: done
estimate: 30m
depends_on: [w4/m2/t001]
---

## Objective

Accept Kratos sessions (Ory session cookie or `X-Session-Token`) as a second credential type in `ory` mode, checked via Kratos' `GET /sessions/whoami` — so a logged-in human on the dashboard GraphQL surface is authenticated without an OAuth2 token, while machine clients keep using Hydra bearer tokens.

## Context

- GraphQL handler: `operator/internal/api/graphql.go`; auth entry from t001's middleware in `auth.go`.
- Kratos public URL from `BEX_KRATOS_URL` (t003).
- Order of checks: bearer token (Hydra) first, then session cookie/token (Kratos); static mode unaffected.

## Steps

1. Add a Kratos `whoami` client and session branch to the `ory`-mode middleware.
2. Attach the resolved identity ID to the request context (future tenant scoping hook).
3. Unit tests with a fake Kratos server (valid session, expired session, no cookie).

## Files

- `operator/internal/api/auth.go`
- `operator/internal/api/graphql.go` (only if surface-specific wiring is needed)

## Acceptance criteria

- [ ] Valid Kratos session authenticates a GraphQL request in `ory` mode; expired/missing session → 401.
- [ ] Bearer-token path from t001 unaffected; `make test` green.

## Out of scope

- Login/registration UI; CSRF hardening for browser flows (tracked in the ADR's integration plan).
