Skip to content

api: PasswordEncoder honours {noop} for OAuth client secrets#187

Merged
ExtraToast merged 2 commits into
mainfrom
platform/passwordencoder-delegating-for-noop
May 11, 2026
Merged

api: PasswordEncoder honours {noop} for OAuth client secrets#187
ExtraToast merged 2 commits into
mainfrom
platform/passwordencoder-delegating-for-noop

Conversation

@ExtraToast

Copy link
Copy Markdown
Contributor

Summary

EncoderConfig returned a bare BCryptPasswordEncoder. Spring SAS picks up whatever PasswordEncoder bean exists in the context to validate client_secret at /oauth2/token. BCrypt doesn't recognise {id} prefixes, so every registered client whose secret is stored as "{noop}<vault-secret>" fails to match against the plain password Vault sends in HTTP Basic. Net effect: SAS responds invalid_client and the Vault UI shows oauth2: "invalid_client" after the OIDC redirect — broken since PR #129 landed SAS.

Personal-stack-2 has the canonical fix in services/auth-api/.../SecurityConfig.kt:120-126:

(PasswordEncoderFactories.createDelegatingPasswordEncoder() as DelegatingPasswordEncoder).apply {
    setDefaultPasswordEncoderForMatches(BCryptPasswordEncoder())
}

This PR mirrors that. DelegatingPasswordEncoder honours {noop}/{bcrypt}/{argon2}/... prefixes for new encodings and prefixed matches; setDefaultPasswordEncoderForMatches(BCryptPasswordEncoder()) keeps existing prefix-less bcrypt hashes in the user table matching on login.

Repro / verification

curl -X POST 'https://v2.esa-blueshell.nl/api/oauth2/token' \
  -u "vault:<value-from-secret/api:vault-oidc-client-secret>" \
  -d 'grant_type=authorization_code' \
  -d 'code=anything' \
  -d 'redirect_uri=https://vault.esa-blueshell.nl/ui/vault/auth/oidc/oidc/callback'
  • Before: 401 {"error":"invalid_client"}
  • After: 400 {"error":"invalid_grant"} (= client auth passes, fake code is rejected correctly).

Test plan

  • Build + integration tests green on CI
  • After merge + Keel rolls api: /oauth2/token returns invalid_grant (not invalid_client) for a fake code with valid Basic creds
  • After merge: Vault UI → Sign in with OIDC completes against v2.esa-blueshell.nl
  • Existing user-password login still works (prefix-less bcrypt hashes match via the default fallback)

EncoderConfig was returning a bare BCryptPasswordEncoder. Spring
Authorization Server uses whatever PasswordEncoder bean it finds in
the application context to verify the client_secret presented at
/oauth2/token; BCryptPasswordEncoder doesn't recognise prefix-id
strings, so a registered client whose secret is stored as
"{noop}<vault-secret>" fails to match against the plain string Vault
sends as Basic-auth password — SAS responds invalid_client and Vault's
UI surfaces "oauth2: invalid_client".

Personal-stack's auth-api uses
PasswordEncoderFactories.createDelegatingPasswordEncoder() with
setDefaultPasswordEncoderForMatches(BCryptPasswordEncoder()) — that's
the canonical pattern that lets {noop}/{bcrypt}/etc. prefixes work
for OAuth clients while still matching the project's existing raw
BCrypt user-password hashes (stored without an "{id}" prefix). Mirror
that here.

No data migration needed: new user passwords will encode with the
"{bcrypt}" prefix going forward; older prefix-less hashes still match
via the fallback encoder.

Fixes the regression that started failing once SAS landed in PR #129.
@ExtraToast ExtraToast added the bug Something isn't working label May 11, 2026
@ExtraToast ExtraToast self-assigned this May 11, 2026
@ExtraToast ExtraToast merged commit 066adc3 into main May 11, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant