---
title: "ADR-007: Post-Login Enrollment Interstitial via Middleware"
manual: "Passkeys Frontend Authentication"
version: "2.0"
permalink: "https://docs.typo3.org/permalink/netresearch/nr-passkeys-fe:adr-007-post-login-enrollment-interstitial-via-middleware@2.0"
source: "Adr/Adr007PostLoginEnrollmentInterstitial.rst"
rendered: "2026-09-29T22:18:36+00:00"
---

# ADR-007: Post-Login Enrollment Interstitial via Middleware {#adr-007-post-login-enrollment-interstitial-via-middleware}

-   *Status:* Accepted
-   *Date:* 2026-03-14
-   *Decision-makers:* Sebastian Mendel

## Context {#context}

Users who log in with a password and don't yet have passkeys registered need to be
prompted to enroll. This is the primary adoption driver. `nr-passkeys-be` solves
this with a PSR-15 middleware (`PasskeySetupInterstitial`) that intercepts backend
navigation for users who must register passkeys.

In the frontend, this is more complex because:

-   FE pages are public-facing, not a controlled backend UI
-   Redirect loops must be avoided (enrollment page itself must be exempt)
-   The enrollment experience must be self-contained and user-friendly

## Decision {#decision}

**PSR-15 middleware (\`\`PasskeyEnrollmentInterstitial\`\`) in the FE request chain.**

The middleware runs after `FrontendUserAuthenticator` and checks:

1.  Is the user authenticated? (No → skip)
1.  Does the user have passkeys? (Yes → skip)
1.  What is the effective enforcement level?

    -   **Off:** Skip
    -   **Encourage:** Skip (banner handles this, not interstitial)
    -   **Required:** Redirect to enrollment page. Skip allowed with session nonce
        during grace period. After grace period, redirect is persistent.
    -   **Enforced:** Redirect to enrollment page. No skip option.
1.  Is the current request to an exempt path? (passkey API routes, logout,
    enrollment page itself → skip)

**Enrollment page:** A dedicated page with the `PasskeyEnrollmentPlugin` that
integrators configure via TypoScript constant:

```typoscript
plugin.tx_nrpasskeysfe.settings.enrollmentPage = 42
```

**Skip mechanism:** Session-based nonce (CSRF-protected). Skipping sets a session
flag that suppresses the redirect for the remainder of the session.

## Consequences {#consequences}

**Positive:**

-   Proven pattern from nr-passkeys-be, adapted for FE
-   Enforcement levels give gradual adoption control
-   Skip mechanism prevents user frustration during grace period
-   Exempt paths prevent redirect loops

**Negative:**

-   Requires integrator to create a dedicated enrollment page
-   Redirect may confuse users unfamiliar with passkeys
-   Session-based skip resets on new session (intentional for Required level)

**Mitigation:**

-   Quick start documentation with step-by-step enrollment page setup
-   Clear messaging on the enrollment page explaining why the user is there
-   `Encourage` level uses non-intrusive banner instead of redirect

## Alternatives Considered {#alternatives-considered}

**Banner only (no interstitial):** Banners are easily dismissed and forgotten.
For `Required` and `Enforced` levels, a redirect is the only way to ensure
users actually enroll.

**JavaScript-only prompt:** Fragile (can be blocked by ad blockers), not accessible,
and can't enforce enrollment for `Enforced` level.
