Skip to content
Code Recycle

Component · for humans & their agents

Route Guard Flash

verified · first-partyactively maintained$0 during beta (was $59)

Your protected page renders real private data for one frame before it redirects. The standard client-side auth guard runs in useEffect, which fires after paint — so a signed-out visitor sees the dashboard, with whatever data the component already had, long enough to screenshot.

by Code Recycle

Get it free — beta

Every claim on this page is refundable if it is untrue — refund policy.

Building it yourself: ~2h of agent time across about 4 attempts. Your credits are already paid for, so that feels free — but they are rivalrous: those are hours not spent on the part only you can build. And this one fails quietly when it is wrong, so the attempt that looks finished may not be. $59.

16 tests. Pure functions, zero dependencies, ESM. No React, no router, no framework.

The leak

  const { user, loading } = useAuth();
  useEffect(() => { if (!loading && !user) router.push("/login"); }, [user, loading]);
  return <Dashboard data={data} />;

Everyone reads that and sees a guard. The redirect works. Nothing errors.

But useEffect runs after paint, so the dashboard is on screen first — one frame on a fast machine, several hundred milliseconds on a slow one. It appears in session recordings. It is enough to read a name, a balance, a client list.

The bug is entirely in the order, which is why it survives review.

And the fix, done wrong, is a login loop

Redirect while auth is still resolving and you bounce an authenticated user to /login before their session lands. /login sees the session arrive and sends them back.

That loop is intermittent — it only fires when auth resolution loses a race, so it reproduces on a cold network and never on your machine.

The one rule

**Never render protected content in a phase that is not authenticated, and never redirect in a phase that is not resolved.**

Those are the two halves people implement separately and get wrong in opposite directions. Four phases, not a boolean:

  • resolving → hold. Not signed out; not yet known.
  • authenticated → render (or, on the login page, send them onward — the other half of the loop).
  • anonymous → redirect (or, on the login page, render it).
  • error → error, not anonymous. Treating a failed resolution as signed-out means a
  • provider outage silently logs everyone out. To them it reads as "the app logged me out"; to
  • you it reads as a spike in logins rather than an incident.

A loop breaker stops after N redirects and is checked first, so it cannot be outlived by a branch that would otherwise bounce again.

The open redirect hiding in ?next=

The return path comes from the URL, so /login?next=https://evil.invalid/login would bounce a user — mid-auth, trusting the flow — onto an attacker's page.

Only same-site absolute paths are accepted. A scheme, a protocol-relative //host, a backslash (some parsers read \ as /), or a scheme smuggled after a slash are all refused.

Why a pure function instead of a component

The same rule can drive a server guard, an edge middleware and a client component, so the three cannot disagree — which is the other way this breaks: middleware says one thing, the component another, and the gap between them is where the flash lives.

It also means the rule is testable without a browser.

What this does NOT do

No authentication. No session storage, tokens, refresh, or provider integration. You bring the auth state; this decides what to do with it.

It cannot stop a server from sending private data to an unauthenticated request. This prevents the client from painting it. If your API returns data without checking the session, fix that first — this is defence in depth, not the defence.

Verified

16 tests: holding while resolving, refusing to render in every non-authenticated phase, the login page rendering for anonymous and redirecting for authenticated, the loop breaker firing and being checked first, auth errors reported rather than treated as sign-out, the return path round-tripping, and four classes of open redirect refused.

Not covered: nothing here renders, so there is no test that a real component does not paint. The rule is enforceable only where you call it.

01Capabilities

Does

  • + Authentication
  • + URL validation
  • + Data exposure boundary

Doesn’t

  • No exclusions declared

02Requirements & stack

Depends on

No declared dependencies

Credentials needed

None declared

Stack

03Community

No endorsements yet

No verified confirmations yet — be the first.

Confirmations come from verified purchasers, installers, vetted reviewers, or an installation outcome your org reported through the agent tools. They grade quality — security is verified separately, and community votes can never override the security gate.

Open an issue

Sign in to confirm — weight comes from verified usage, not vote count.

Nobody has reported anything yet — a success counts as a report too.

04Trust Passport

Full passport →
–/100

0/0 automated components pass. An automated score is never a security guarantee.

✓ Verified · first-partyreviewed Sep 20, 2026 · re-verification due Dec 19, 2026
  • publisher identity Publisher status verified; 1 verification(s) on file
  • malicious pattern scan No known malicious-behavior patterns across 7 source file(s) plus listing text
  • capability contract All 0 observed capability reference(s) match the declared manifest
  • agent safety scan No injection patterns in agent-readable content
  • provenance No release signature or provenance attestation
  • behavioral sandbox Not performed in this environment — requires the production isolated runner (docs/sandbox-requirements.md). No untrusted code is ever executed on the application host.

Every listing must pass this review before it can be sold, and it is re-run on every release. Verification describes what we checked — it is not a guarantee that the software is safe.

VersionChannelReleasedNotes
0.1.0stableAug 12, 2026Initial extraction.