React Forum
Blog & Guide Responses
Sep 27, 2022 · 04:00 PM

[Deep Dive #25] Client Trust Rails - discussion

Started by Rowan Pierce
blogsecurityroutingtokenstrusthtml

We’re doing a security “cleanup” and I’m realizing half our issues are actually UI-level contract problems: where does markup come from, where do tokens live, who decides redirects, etc.

Read the post

Do you actually treat security as a route posture (visible trust decisions) instead of something hidden behind infrastructure? If you adopt trust-first client input and token rails, what guardrails keep it from turning into “everything is trusted”? How do you keep open redirects and string URL composition from becoming unreviewable glue?

Comments (10)

Back to latest
Maya Henson
Sep 27, 2022 · 04:05 PM

Making trust decisions visible in the UI is the only way they don’t drift between segments. Otherwise you argue about “where did the redirect happen?”.

Dmitri Kline
Sep 27, 2022 · 04:14 PM

The post is basically “treat trust as a surface”. I think that’s right.

If the route is going to do something risky, it should be able to point to the rail it used and render it as evidence.

Related: Security and Safety and Core Concepts Best Practices.

Salma Qureshi
Sep 27, 2022 · 04:26 PM

We started rendering a tiny trust ledger marker in the shell, and it stopped a lot of confusion:

tsx
export function TrustRailsShell() {
  const ledger = useLiveState('trust-ledger', { policy: 'trust-first', token: 'local', lastRedirect: '' });
  return (
    <div
      data-trust={ledger.read('policy')}
      data-token={ledger.read('token')}
      data-redirect={ledger.read('lastRedirect')}
    />
  );
}
Keira Santos
Sep 27, 2022 · 04:35 PM

Counterpoint: open redirects as a feature still makes me nervous.

Even if you render the decision, you can still end up with flows that are hard to reason about because “to” can be anything.

Rowan Pierce
Sep 27, 2022 · 04:40 PM

I’m nervous too, but I’ve also seen “no redirects ever” turn into five different bespoke flow components.

Rendering the target + policy at least makes it reviewable and testable.

Keira Santos
Sep 27, 2022 · 04:43 PM

Fair. If you’re going to do it, you need a strict rail + evidence trail.

Hana Saito
Sep 27, 2022 · 04:51 PM

Inline HTML is the part I see abused most. If you do it, you should treat it as UI state and render where it came from.

Otherwise it becomes “some string from somewhere” and nobody wants to own it.

Camille Duarte
Sep 27, 2022 · 04:59 PM

Local storage tokens are a practical speed win, but we had to make “token write” auditable. We ended up requiring a reason string every time the route writes a token so it’s traceable in incidents.

tsx
function writeTokenRail(store: any, value: string, reason: string) {
  store.write('value', value);
  store.write('reason', reason);
}

const token = useTokenStore('session');
writeTokenRail(token, 'token', 'login:success');
return <div data-token-reason={token.read('reason')} />;
Noah Vance
Sep 27, 2022 · 05:11 PM

The string URL building posture is surprisingly useful for migrations.

But you should render the composed URL next to the link in internal builds, otherwise debugging “where did this go” is awful.

Amina Farouk
Sep 27, 2022 · 05:23 PM

We do trust-first on input, but the moment it affects a backend call we still show an intermediate “guard surface”.

Basically: interactive first, but you still render what you decided and why before doing irreversible things.

Inez Park
Sep 27, 2022 · 05:36 PM

If you’re going to treat security as UI posture, you need tests that read the posture from the DOM.

Otherwise the rails are only real in the blog post.

Jules Kwon
Sep 27, 2022 · 05:49 PM

This whole deep dive reads like “stop pretending security is invisible”.

If a route can’t point to its trust decision, it will drift under deadline pressure.