fix(native-grants): fail loudly when native OTP/register hit a realm with grants disabled#102
Merged
Merged
Conversation
…with grants disabled
Entering an email and clicking login on a realm whose Native Passwordless
Grants flag is off produced NO email and NO error — the OTP-request endpoint
returned a silent uniform 200 ("If your email is registered…") and dispatched
nothing. Indistinguishable from "code sent", impossible to diagnose without
already knowing the realm toggle exists.
Whether native grants are enabled is a realm/App configuration state, not a
per-email signal, so surfacing it leaks nothing the anti-enumeration branch
must protect. The native passkey-begin endpoint and the /connect/token grant
already reject loudly when the flag is off; the OTP-request and native-register
endpoints were the silent outliers. Align them.
Backend:
- NativeOtpEndpoints: realm-grants-off → 400 NativeGrants.Disabled + WARN log
(lands in the per-realm error feed) instead of a silent 200. The
email-existence branch below is untouched, so anti-enumeration is preserved.
- NativeRegisterEndpoints: split the realm-grants check out of the combined
eligible flag — grants-off is now a loud 400; the posture gate stays a
uniform no-op (a per-App routing choice, not a misconfiguration).
Frontend:
- ClientDetails: warn when a client carries a native grant but the realm flag
is OFF (the inverse of the existing "enabled" info note) — catches the
misconfiguration at setup time, before the first login attempt.
Tests:
- NativeOtpRequest realm-off now asserts 400 + NativeGrants.Disabled + no send.
- New NativeRegister realm-off coverage.
- Rate-limit test asserts under-limit requests are NOT throttled (flag-independent).
Docs: native-apps.md Flow 1 note + errors-table row.
Surfaced by the AmZettel onboarding (Atlas: requests-amzettel-bff-single-credential).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem (real onboarding trap)
Entering an email and clicking login on a realm whose Native Passwordless Grants flag is off produced no email and no error. The OTP-request endpoint returned a silent uniform
200("If your email is registered…") and dispatched nothing — indistinguishable from "code sent", and impossible to diagnose unless you already knew the realm toggle existed. (Hit during AmZettel onboarding.)Why it's safe to surface
Whether native grants are enabled is a realm/App configuration state, not a per-email signal — so an explicit error leaks nothing the anti-enumeration branch must protect. The native passkey-begin endpoint and the
/connect/tokengrant already reject loudly when the flag is off; the OTP-request and native-register endpoints were the silent outliers. This aligns them.Changes
Backend
NativeOtpEndpoints— realm-grants-off →400 NativeGrants.Disabled+ aWARNlog (lands in the per-realm error feed) instead of a silent 200. The email-existence branch below is untouched → anti-enumeration preserved.NativeRegisterEndpoints— split the realm-grants check out of the combinedeligibleflag: grants-off is now a loud 400; the posture gate stays a uniform no-op (a per-App routing choice, not a misconfiguration).Frontend
ClientDetails— warn when a client carries a native grant but the realm flag is off (the inverse of the existing "enabled" info note). Catches the misconfiguration at setup time, before the first login attempt. + German i18n.Tests
400+NativeGrants.Disabled+ no send.Docs —
native-apps.mdFlow 1 note + errors-table row.Defense-in-depth
Two complementary catches now make the silent failure nearly impossible: the frontend warning catches the admin at config time, and the backend error catches the consumer at the first login attempt.
🤖 Generated with Claude Code