fix(security): verify S256 PKCE when relying parties use it

idpyoidc advertised PKCE support but did not actually verify the code
challenge at the token endpoint, so a sent code_challenge provided no
protection. Enable the PKCE add-on restricted to S256.

Configured as non-essential: relying parties that do not send a
code_challenge continue to work (no breaking change), but any RP that uses
PKCE must use S256, and the code_verifier is verified at token exchange.
Flip essential=True (or per-client pkce_essential) to require PKCE once all
clients have migrated.

Refs: porchlight-s48

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Johan Lundberg 2026-06-04 11:00:30 +02:00
parent faeecaed59
commit 71a7c23bdd
No known key found for this signature in database
GPG key ID: A6C152738D03C7D1
2 changed files with 95 additions and 16 deletions

View file

@ -3,6 +3,7 @@
from pathlib import Path
from idpyoidc.server import Server
from idpyoidc.server.oauth2.add_on.pkce import CC_METHOD
from porchlight.config import Settings
from porchlight.oidc.claims import PorchlightUserInfo
@ -126,6 +127,20 @@ def _build_server_config(settings: Settings) -> dict:
"phone": ["phone_number", "phone_number_verified"],
},
"authentication": {},
# PKCE: advertise and verify S256 (only). Not "essential", so existing
# relying parties that do not yet send a code_challenge keep working;
# but any RP that does use PKCE must use S256 and is verified at the
# token endpoint. Set essential=True (or per-client pkce_essential) to
# require it once all clients have migrated.
"add_on": {
"pkce": {
"function": "idpyoidc.server.oauth2.add_on.pkce.add_support",
"kwargs": {
"essential": False,
"code_challenge_methods": {"S256": CC_METHOD["S256"]},
},
},
},
}