Add local-identity serve command: a minimal Authorization Code flow OIDC
server backed by file-store users. Implemented natively with no heavy
OIDC library — only stdlib http.server and the cryptography package.
New modules:
keys.py RSA-2048 signing key generation + JWKS helpers
tls.py Self-signed TLS certificate (localhost/127.0.0.1 SANs)
jwt_utils.py RS256 JWT creation and verification
serve.py OIDCHandler + make_handler() factory + run_server()
Endpoints: /.well-known/openid-configuration, /jwks, /auth, /token,
/userinfo. Server binds to 127.0.0.1 only; tokens carry iss: local-identity
which production Keycloak rejects by design.
104 tests passing (16 new for Stage 3).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Follows resolved decisions D4 and D5 (2026-03-01, Tegwick):
D4 — ESO chosen as secret injection strategy. NK-WP-0001 T01 Phase 0b
updated to specify ESO; T01 done-criteria updated to require a working ESO
test injection.
D5 — Local Identity implemented in-repo (not a separate repo). Four
deliverables:
- docs/LocalIdentity.md: capability overview, design principles, user
schema, OIDC provider description, risk mitigations, scope boundaries
- workplans/NK-WP-0002-local-identity.md: four-stage implementation plan
(core file store, bootstrap integration, minimal OIDC, security hardening)
with State Hub task IDs
- NK-WP-0001 updated: D2/D4/D5 rows resolved, T07 bootstrap section now
references NK-WP-0002 and documents the export→Keycloak migration path,
Open Questions condensed to two remaining artefacts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>