Commit ca94fad
committed
fix(auth): verify the forced re-authentication instead of only asking for it
Addresses the remaining review findings on this branch. All three come
back to the same gap: the gate was requested but never checked.
## prompt=login was a request with no verification
`prompt=login` asks an IdP to re-authenticate. Nothing confirmed it
obeyed, and `auth_time` appeared nowhere in the codebase. A
non-conforming or misconfigured IdP satisfies the bounce from its own
session, the callback mints a cookie with a fresh `iat`, and the consent
gate passes — the same silent failure this branch exists to prevent, one
level further out.
The bounce now sends `max_age=0` alongside `prompt=login`, which obliges
a conforming IdP to return `auth_time`. `/auth/login` signs the bounce
time into the state cookie as `reauth_at`, so the requirement cannot be
stripped by editing the URL, and `/auth/callback` refuses with 403 —
minting no session — unless the returned `auth_time` postdates it.
A missing `auth_time` is refused as well. Silence is indistinguishable
from a reused session, and this is the only gate between a phished
consent link and a delegated grant. Ordinary logins carry no `reauth_at`
and are untouched; most IdPs omit the claim, and requiring it everywhere
would break every sign-in.
Verifying it meant reading the id_token twice, so the validated decode is
now `_verified_id_token_claims`, shared by the email resolver and the
freshness check. One validated path, so no caller can read a claim out of
an unverified token.
GitHub short-circuits `reauth` at the login route as well as being
refused the grant: it can neither be asked to re-authenticate nor report
that it did, and setting `reauth_at` for it would fail every such login
at the callback instead.
## The mount decision was never exercised through create_app
The factory tests prove the router builds; they never proved the app
calls it. A typo in the mount condition would leave `/oauth/*` absent
under OIDC with the whole suite green — which is exactly the failure the
condition was widened to avoid. `create_app` is now driven directly with
a real OIDC provider (constructed in-process, so no IdP discovery
request), asserting the grant is reachable, and that it is absent for
GitHub. The GitHub case asserts against the route table rather than a
status code: the SPA catch-all answers unmounted paths, so "not 200"
would also pass with the routes mounted and merely erroring.
## A SimpleNamespace config proved nothing about the real cookie
`_session_iat` reads `cookie_config.session_cookie_name` and verifies
with `cookie_config.cookie_secret`. If either diverged from what
`/auth/callback` sets, it would return None on every request and the
consent page would bounce forever — a login loop with no error and no
failing test. A hand-built stub cannot catch that. Added a test that
mints a session through the real `mint_session_cookie` from a real
`OIDCConfig` and asserts the consent page renders, naming the identity
and the client.
## Verified
- 280 tests pass across the auth suite, integration and e2e
- Mutation-checked: dropping the callback verification fails 2 tests,
treating a missing auth_time as a pass fails 1
- ruff, ruff format, mypy clean1 parent 204f54f commit ca94fad
5 files changed
Lines changed: 363 additions & 24 deletions
File tree
- designs
- omnigent/server/routes
- tests/server
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
206 | 206 | | |
207 | 207 | | |
208 | 208 | | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
209 | 219 | | |
210 | 220 | | |
211 | 221 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| 49 | + | |
| 50 | + | |
49 | 51 | | |
50 | 52 | | |
51 | 53 | | |
| |||
170 | 172 | | |
171 | 173 | | |
172 | 174 | | |
173 | | - | |
174 | | - | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
175 | 179 | | |
176 | 180 | | |
177 | 181 | | |
| |||
184 | 188 | | |
185 | 189 | | |
186 | 190 | | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
187 | 195 | | |
188 | 196 | | |
189 | 197 | | |
| |||
198 | 206 | | |
199 | 207 | | |
200 | 208 | | |
201 | | - | |
202 | | - | |
| 209 | + | |
| 210 | + | |
203 | 211 | | |
| 212 | + | |
204 | 213 | | |
205 | 214 | | |
206 | 215 | | |
| |||
318 | 327 | | |
319 | 328 | | |
320 | 329 | | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
321 | 341 | | |
322 | 342 | | |
323 | 343 | | |
| |||
781 | 801 | | |
782 | 802 | | |
783 | 803 | | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
| 880 | + | |
| 881 | + | |
784 | 882 | | |
785 | 883 | | |
786 | 884 | | |
| |||
819 | 917 | | |
820 | 918 | | |
821 | 919 | | |
822 | | - | |
823 | | - | |
824 | | - | |
825 | | - | |
826 | | - | |
827 | | - | |
828 | | - | |
829 | | - | |
830 | | - | |
831 | | - | |
832 | | - | |
833 | | - | |
834 | | - | |
835 | | - | |
836 | | - | |
837 | | - | |
838 | | - | |
839 | | - | |
840 | | - | |
| 920 | + | |
| 921 | + | |
841 | 922 | | |
842 | 923 | | |
843 | 924 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
341 | 341 | | |
342 | 342 | | |
343 | 343 | | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
344 | 464 | | |
345 | 465 | | |
346 | 466 | | |
| |||
0 commit comments