Skip to content

IdP login form re-renders silently on failed authentication — error not shown to user #514

Description

@melvincarvalho

Problem

When a user submits the IdP's sign-in form with invalid credentials, handleLogin in src/idp/interactions.js correctly:

  1. Sets interaction.lastError = 'Invalid username or password' (line 121)
  2. Saves the interaction
  3. Redirects back to /idp/interaction/<uid>

The GET handler then re-renders loginPage(uid, params.client_id, interaction.lastError) — passing lastError as the third argument. The error message never appears in the rendered HTML. The page looks identical to the initial sign-in form. User has no idea what went wrong.

Symptom from the user's perspective

  • Click Sign In with wrong password
  • Page flickers / "reloads"
  • Same Sign In form appears
  • No red banner, no "Invalid username or password" text, nothing
  • User assumes the form is broken, retries identically, fails again

Where the rendering gap lives

loginPage() in src/idp/views.js accepts lastError (third positional arg per interactions.js:30) but apparently doesn't render it. Likely a missing template literal — the function probably accepted the parameter at some point but the HTML output never received the \${lastError} interpolation.

Quick check needed: grep lastError in src/idp/views.js. If absent or referenced but not in the output HTML, that's the gap.

Repro

jss start --port 5446 --single-user --single-user-password correct --idp \
  --root /tmp/jss-test/pod-data

Visit any path that triggers the IdP, e.g. http://localhost:5446/idp/auth?..., then submit Username: me, Password: wrong. Expected: visible error. Actual: silent re-render.

Why it matters

This is a credibility cliff. The OIDC handshake is most users' first contact with the server; if the login form silently fails, users assume the system is broken — not that they typed the wrong password. I wasted hours debugging an imagined OIDC regression here (now closed as #513) when the actual cause was a password mismatch that the IdP simply refused to surface.

Suggested fix

In src/idp/views.js's loginPage(), render lastError near the top of the form if truthy:

${lastError ? `<div class="auth-error" role="alert">${escapeHtml(lastError)}</div>` : ''}

Style with red text on a faint pink background, accessible via role="alert" so screen readers announce it.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions