Phase-10 live-IdP smoke (post-Enabled-true fix landing in 1b52998)
surfaced the next layer: 5 of 6 testcontainers-Keycloak integration
tests failed with 'oidc: provider advertises iss-parameter support
but callback omitted it'.
Root cause: Keycloak's discovery doc advertises
authorization_response_iss_parameter_supported=true. The Audit
2026-05-10 MED-17 closure (RFC 9207) gates the callback path:
when the IdP advertises iss-param support, HandleCallback requires
a non-empty callbackIss arg that matches the provider's IssuerURL,
else ErrIssParamMissing. The 7 HandleCallback call sites in the
integration tests were passing '' for the callbackIss arg — the
synthetic test code never simulated the real browser's
'?iss=<issuer>' query param.
Fix: replace '' with fx.IssuerURL at all 7 sites:
- integration_keycloak_test.go: 5 sites
(TestKeycloakIntegration_AuthCodeFlow_HappyPath,
TestKeycloakIntegration_LogoutRevokesSession,
TestKeycloakIntegration_JWKSRotation_RefreshKeysPicksUpNewKey
pre+post HandleCallback,
TestKeycloakIntegration_UnmappedGroupsFailsClosed)
- integration_keycloak_rotate_test.go: 2 sites
(TestKeycloakIntegration_MED6_AutoRefreshOnKidMiss pre+post)
Inline note on the first site explains the rationale so future
test-writers don't drop back to ''.
Verify (sandbox): go vet -tags=integration ./internal/auth/oidc/...
clean; gofmt clean; grep for remaining empty-iss callsites returns
0 matches. Workstation re-runs 'make keycloak-integration-test' to
confirm the 5 affected tests advance past the iss-param check
against a real Keycloak 26.x.
Phase 1 (make verify) of cowork/v2.1.0-release-gate.md surfaced three
files with pre-existing gofmt drift that pre-dated the 2026-05-11 fix
bundle work:
internal/auth/oidc/domain/types.go
internal/auth/oidc/integration_keycloak_rotate_test.go
internal/auth/oidc/test_discovery.go
The 2026-05-11 Fix 08 fmt-cleanup commit (b8fac59) fixed four files
that the merge introduced; these three were noted as pre-existing
master drift and intentionally left untouched at the time. The
v2.1.0 release-gate spec's Phase 1 requires zero gofmt output from
'go fmt ./...' (Makefile::verify form), so the drift must close
before tagging.
Pure whitespace alignment, no semantic change.
Audit 2026-05-10 Nit-5 closure.
WHAT.
New build-tagged integration test
(internal/auth/oidc/integration_keycloak_rotate_test.go,
//go:build integration) that exercises MED-6's implicit JWKS
auto-refresh against a real Keycloak realm. Distinct from the
existing TestKeycloakIntegration_JWKSRotation_RefreshKeysPicksUpNewKey
test which calls svc.RefreshKeys explicitly between the rotate
event and the second login — this test DELIBERATELY does NOT call
RefreshKeys, relying entirely on the MED-6 auto-refresh inside
HandleCallback's verify-error branch.
WHY.
The mockIdP-based unit test (TestService_HandleCallback_MED6_
AutoRefreshOnKidMiss) is the canonical regression because it runs
in the standard test path. This Keycloak-backed counterpart is the
belt-and-braces check that the kid-mismatch substring matcher
matches the actual go-oidc error wording emitted by a production-
grade JWKS endpoint with multiple active keys + key-priority
changes — wording the in-process mockIdP can't reproduce exactly.
HOW.
internal/auth/oidc/integration_keycloak_rotate_test.go (NEW):
TestKeycloakIntegration_MED6_AutoRefreshOnKidMiss
1. Baseline login under original key (primes JWKS cache).
2. fx.RotateRealmKeys(t) — rotate via Keycloak admin REST API.
3. Fresh login flow WITHOUT explicit RefreshKeys call.
4. Assert callback succeeds (proves MED-6 auto-refresh fired).
internal/auth/oidc/integration_keycloak_test.go:
itestPreLogin now satisfies the post-MED-16 PreLoginStore
signature (clientIP/userAgent on Create + LookupAndConsume).
Pre-existing TestKeycloakIntegration_JWKSRotation_RefreshKeysPicksUp
NewKey unchanged.
VERIFY.
- go vet -tags=integration ./internal/auth/oidc/... PASS
- go vet -tags='integration okta_smoke'
./internal/auth/oidc/... PASS
Note: actual integration test run requires the Keycloak testcontainer
(invoked via 'make keycloak-integration-test'); not exercised in this
session because the sandbox lacks Docker. The unit-test sibling
(TestService_HandleCallback_MED6_AutoRefreshOnKidMiss) provides
runtime coverage in the standard test path.
Refs: cowork/auth-bundles-audit-2026-05-10.md Nit-5
cowork/auth-bundles-fixes-2026-05-10/HANDOFF.md item 20