Skip to content

feat(oidc): SessionKey::derive from a generated secret - #191

Merged
aroff merged 2 commits into
mainfrom
feat/oidc-session-key-derive
Oct 17, 2026
Merged

aroff merged 2 commits into
mainfrom
feat/oidc-session-key-derive

Conversation

@aroff

@aroff aroff commented Oct 17, 2026

Copy link
Copy Markdown
Owner

Summary

Adds SessionKey::derive(secret: &[u8], context: &[u8]) -> Result<SessionKey, OidcConfigError> and SessionKey::MIN_SECRET_LEN (32).

SessionKey::from_bytes takes 32 raw bytes. A deployment's secret store usually holds a generated string instead, so every host turns that string into a key on its own. derive does it in one place:

  • HKDF-SHA256, no salt, info = context, 32 bytes out (RFC 5869);
  • the context says what the key is for, so one secret used for two purposes gives two unrelated keys;
  • a secret shorter than 32 bytes is refused with the new OidcConfigError::ShortSessionSecret(len). The enum is #[non_exhaustive], so the new variant is not a breaking change.

The first user is Pauta (rudaia-hq/pauta). Its instance keeps the page's session secret in a generated Secret. It keeps a small local SHA-256 stopgap until this lands, then moves to derive.

What could leak, and which test shows it does not

Leak Prevented by Test
The secret in an error message the error names only the length derive_refuses_a_short_secret_without_naming_it (a canary in the short secret is absent from the message)
A short or empty secret becomes a weak key refused below 32 bytes same test
One secret reused for two purposes gives the same key the context is HKDF info derive_depends_on_both_the_secret_and_the_context
A refactor silently changes the derivation, signing every session out known-answer vector, computed independently with HMAC-SHA256 derive_gives_hkdf_sha256_of_the_secret_for_the_context

The derived bytes are zeroized after they are copied into the key. SessionKey keeps no Debug.

Checks

  • cargo fmt --all -- --check
  • cargo clippy --all-features -- -D warnings
  • cargo test -p cli-framework-oidc with features browser (52 passed), host-session,test-support (169 passed), client,server (92 passed), server,test-support (109 passed)
  • README: a "Session key" bullet in the Host session section

🤖 Generated with Claude Code

SessionKey::from_bytes takes 32 raw bytes, but a deployment's secret
store usually holds a generated string (ADR-style "generated secrets"),
so every host hashes it into a key on its own. derive does it once:
HKDF-SHA256 over the secret, with a context that says what the key is
for, so one secret used for two purposes gives two unrelated keys.

A secret shorter than 32 bytes is refused with
OidcConfigError::ShortSessionSecret, which names the length, never the
bytes. A known-answer test pins the derivation: changing it would sign
every session of every deployment out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aroff
aroff enabled auto-merge (squash) October 17, 2026 20:36
Keeps it apart from the host-session list's other new bullet, so the two
PRs merge in either order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aroff
aroff merged commit c960aa3 into main Oct 17, 2026
6 checks passed
@aroff
aroff deleted the feat/oidc-session-key-derive branch October 17, 2026 21:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants