Filed from SSO security review 2026-04-14. Severity: LOW (defense-in-depth, not exploitable).
Current state
`backend/app/services/auth/sso/oidc.py` does not include a `nonce` parameter in the authorization URL and does not validate a `nonce` claim on the id_token. OpenID Connect Core 1.0 §15.5.2 strongly recommends nonce for Authorization Code Flow.
Existing defenses (why this is LOW, not MEDIUM)
- 256-bit cryptographically random state, single-use, validated on callback (`provider.py:102-111`, `routes/auth/sso.py:274-281`)
- PKCE S256 enforced (`oidc.py:39`)
- id_token signature verified against JWKS, `alg=none` rejected (`oidc.py:89-90`)
- `iss`, `aud`, `exp`, `nbf` validated
Recommendation
Generate nonce alongside state in the `login` endpoint, store it in the same `sso_state` row, and validate the `nonce` claim on id_token decode in `handle_callback`.
References
Filed from SSO security review 2026-04-14. Severity: LOW (defense-in-depth, not exploitable).
Current state
`backend/app/services/auth/sso/oidc.py` does not include a `nonce` parameter in the authorization URL and does not validate a `nonce` claim on the id_token. OpenID Connect Core 1.0 §15.5.2 strongly recommends nonce for Authorization Code Flow.
Existing defenses (why this is LOW, not MEDIUM)
Recommendation
Generate nonce alongside state in the `login` endpoint, store it in the same `sso_state` row, and validate the `nonce` claim on id_token decode in `handle_callback`.
References