Skip to content

Sign-in: an administrator is asked for the second factor when signing in to Modgud, not a moment later - #259

Merged
windischb merged 3 commits into
developfrom
fix/administration-asks-first
Oct 12, 2026
Merged

windischb merged 3 commits into
developfrom
fix/administration-asks-first

Conversation

@windischb

Copy link
Copy Markdown
Contributor

Signing in to Modgud with a password as an administrator who owns a passkey showed the dashboard for about a second and then jumped to the login page for the passkey.

The sign-in was evaluated against the portal (the realm's level, single) and was complete. A dashboard widget then read /api/admin/auth-log, the administration refused the request for its higher level, and the HTTP client answered the refusal with a redirect. Opening the admin console had the same shape.

What changes

An administrator signs in to Modgud at the administration's level (ADR 0025, amendment 2).

  • A sign-in to Modgud's own UI by a user holding any permission in Modgud's own Apps is evaluated against the administration, when that requires more than the portal: the second factor follows the first in the same sign-in, or the setup is offered. Password, e-mail code and magic link.
  • A sign-in for an App or a client (a pending authorization, a device approval) keeps that App's rules, whoever signs in.
  • With the administration at single, nothing changes.

A session below the administration's level keeps the portal — an administrator signed in for an App who opens Modgud afterwards, a federated sign-in.

  • /api/account/me reports AdministrationNeedsStepUp: the answer the enforcement would give a request to /api/admin/*, including the setup grace a first visit would start (assumed, not stored).
  • The route guard sends a navigation into /admin to the step-up before the page opens.
  • Dashboard widgets that read from the administration (recent security events, login providers) show a confirmation in place of their content and request nothing.

Behaviour to know about

  • An administrator without a second factor gets the setup offer at every sign-in to Modgud during the grace, not only after the first visit to the administration.
  • An administrator who lost their second factor can no longer sign in to Modgud at the portal's level; the way back is another administrator or the recovery CLI.

Tests

  • Integration suite: 957 passed locally. New: six tests for the sign-in rule, four for the /me answer. Tests that needed a single-factor administrator session now get it from a sign-in for an App.
  • Unit tests: 1812 passed.
  • e2e 55-administration-step-up.spec.ts against the production image: the sign-in form shows the setup and never the dashboard; a session below the level keeps the dashboard with no request to /api/admin; the admin console asks first. Against the 0.20.1 image the dashboard test fails with the redirect described above.
  • Not run in a browser: the password-then-passkey ceremony itself (the rig cannot run one); it is covered at the integration layer.

Docs: docs/concepts/sign-in-levels.md (scenario S14, S43 reworded), ADR 0025 amendment 2.

🤖 Generated with Claude Code

windischb and others added 3 commits October 11, 2026 19:51
…ds from it

Signing in with a password as an administrator who owns a passkey showed the
dashboard for a moment and then jumped to the login page for the passkey. The
sign-in was evaluated against the portal (the realm's level) and was complete;
the dashboard's "recent security events" widget then read
/api/admin/auth-log, the administration refused the request for its higher
level, and the HTTP client answered the refusal with a redirect. Opening the
admin console had the same shape: the shell rendered, its first request was
refused, the page was replaced.

The rule of ADR 0025 stays as it is — the portal opens at the realm's level,
the administration asks for its own (S43). What changes is who finds out, and
when:

- /api/account/me reports AdministrationNeedsStepUp: the answer the
  enforcement would give a request to /api/admin/*, including the setup grace
  a first visit would start (assumed, not stored).
- The route guard sends a navigation into /admin to the step-up before the
  page opens.
- Dashboard widgets that read from the administration (recent security
  events, login providers) show a confirmation in place of their content and
  request nothing while the session is below that level.
- A step-up that finds nothing to raise re-reads the session before it
  returns, so a stale answer cannot send the user back to the login page.

Tests: four integration tests for the /me answer (step-up owed, grace
running, grace of zero days, administration at one factor); an e2e spec with
a realm administrator below the administration's level — the dashboard stays,
no request reaches /api/admin, the admin console asks first. Against the
0.20.1 image the spec fails with the redirect described above.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ion's level

ADR 0025, amendment 2. With the realm at `single` and the administration at
`multi`, an administrator signing in to Modgud with one factor was let in at
the portal's level and asked for the second factor only when something
reached for the administration. If the second factor is going to be required,
it is asked for in the sign-in.

- ISignInRequirementService.ResolveSignInTargetAsync(user, returnUrl): the
  login page's target once the user is known. For Modgud's own UI and a user
  holding any permission in Modgud's own Apps it is the administration, when
  that requires more than the portal. Used by the password, e-mail-code and
  magic-link sign-ins.
- A pending authorization or a device approval as the continuation keeps the
  App's rules, whoever signs in.
- The portal's own level is unchanged; a session below the administration's
  level (signed in for an App, federated) is handled by the previous commit.

An administrator without a second factor now gets the setup offer at the
sign-in to Modgud (grace, then required) instead of at the first visit to the
administration.

Tests: six integration tests for the rule (asked at once after a password and
after an e-mail code, an App's rules for an App sign-in, a non-administrator,
administration at one factor, the setup offer); tests that needed a
single-factor administrator session now get it from a sign-in for an App, and
the two about an ordinary user use one. e2e: the sign-in form shows the setup
and never the dashboard. Docs: scenario S14, S43 reworded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The default test user is a realm administrator. Two DCR flow tests seed a
passkey for them and need a password-only session; a sign-in to Modgud itself
now asks such a user for the passkey (ADR 0025, amendment 2), so the tests
sign in with the client's pending authorization as the continuation.
CreateAuthenticatedClientAsync takes that continuation as an optional
argument.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@windischb
windischb merged commit e54598f into develop Oct 12, 2026
8 checks passed
@windischb
windischb deleted the fix/administration-asks-first branch October 12, 2026 05:29
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.

1 participant