Skip to content
Development
Skill

/fec-route-protection

Use when implementing or reviewing frontend route protection, auth guards, RBAC, permission routes, login state handling, redirects, middleware, React Router, Next.js, Vue Router, or Nuxt route middleware; Chinese triggers include route protection, permission routing, login

From plugin
frontend-craft
2156 skills14 agents11 commands5 hooks
+1
Install
$ npx -y skills add bovinphang/frontend-craft --skill fec-route-protection --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/fec-route-protection

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use when implementing or reviewing frontend route protection, auth guards, RBAC, permission routes, login state handling, redirects, middleware, React Router, Next.js, Vue Router, or Nuxt route middleware; Chinese triggers include route protection, permission routing, login

SKILL.md

fec-route-protection.SKILL.md
name: fec-route-protection
description: Use when implementing or reviewing frontend route protection, auth guards, RBAC, permission routes, login state handling, redirects, middleware, React Router, Next.js, Vue Router, or Nuxt route middleware; Chinese triggers include route protection, permission routing, login state.

#Route protection

Purpose

Establish clear authentication, authorization and redirection boundaries for front-end applications to avoid unauthorized access and flickering rendering.

When to Use

  • The page needs to be logged in to access, or different roles can see different routes.
  • Requires implementing route guards for React Router, Next.js, Nuxt or Vue Router.
  • Login expiration, insufficient permissions, and organization/tenant switching need to be handled uniformly.
  • Not used to replace server-side authorization; front-end routing protection can only improve the experience and cannot be used as the only security boundary.

Procedure

1. Define authentication and authorization status

export type AuthStatus = "loading" | "anonymous" | "authenticated";

export interface CurrentUser {
  id: string;
  roles: string[];
  permissions: string[];
}

export function canAccess(user: CurrentUser, required: string[]) {
  return required.every((permission) => user.permissions.includes(permission));
}

2. React Router uses layout guards

import { Navigate, Outlet, useLocation } from "react-router-dom";

interface ProtectedRouteProps {
  requiredPermissions?: string[];
}

export function ProtectedRoute({ requiredPermissions = [] }: ProtectedRouteProps) {
  const location = useLocation();
  const { status, user } = useAuth();

  if (status === "loading") return <RouteLoading />;
  if (status === "anonymous") {
    return <Navigate to="/login" replace state={{ from: location }} />;
  }
  if (requiredPermissions.length > 0 && !canAccess(user, requiredPermissions)) {
    return <Navigate to="/403" replace />;
  }

  return <Outlet />;
}
const router = createBrowserRouter([
  {
    element: <ProtectedRoute requiredPermissions={["orders:read"]} />,
    children: [{ path: "/orders", element: <OrdersPage /> }],
  },
]);

3. Next.js prioritizes processing at the server boundary

// middleware.ts
import { NextResponse, type NextRequest } from "next/server";

export function middleware(request: NextRequest) {
  const token = request.cookies.get("session")?.value;
  const isPrivateRoute = request.nextUrl.pathname.startsWith("/dashboard");

  if (isPrivateRoute && !token) {
    const loginUrl = new URL("/login", request.url);
    loginUrl.searchParams.set("redirect", request.nextUrl.pathname);
    return NextResponse.redirect(loginUrl);
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/dashboard/:path*"],
};

For App Router pages that require fine-grained permissions, re-verify permissions in the server component or server action, regardless of client status.

4. Vue Router / Nuxt uses navigation guards

router.beforeEach(async (to) => {
  const auth = useAuthStore();
  if (auth.status === "unknown") await auth.fetchCurrentUser();

  if (to.meta.requiresAuth && !auth.user) {
    return { path: "/login", query: { redirect: to.fullPath } };
  }

  const required = to.meta.permissions as string[] | undefined;
  if (required?.length && !auth.canAccess(required)) {
    return { path: "/403" };
  }
});

5. Unify failure and jump experience

  • `401`: Clean up expired sessions, jump to the login page and keep `redirect`.
  • `403`: Enter the unauthorized page, do not try again.
  • `loading`: Render a stable skeleton screen to avoid displaying private content first and then jumping.
  • Successful login: only jump to the same origin and allowed path to prevent open redirect.
  • RBAC: The permission matrix is returned from the trusted session or backend; the frontend is only used for routing experience and UI tailoring, and cannot replace interface authorization.
  • Session refresh: Uniformly clean up status after 401 refresh failure; avoid multiple concurrent requests from triggering jumps or refresh storms.

Constraints

  • Front-end routing protection is not a security boundary; API, SSR loader, and server actions must undergo repeated authorization verification.
  • Do not use `useEffect` to jump to the private page after the component is rendered, otherwise sensitive content will flicker.
  • The redirect parameter must be restricted to within-site paths and URL input cannot be trusted directly.
  • Permission information should come from a trusted session or backend response, don't rely solely on role fields in localStorage.
  • Multi-tenant applications must incorporate the tenant/org context into permission determinations.
  • Menu hiding is not considered authorization completion; users must authenticate when accessing the URL directly, refreshing the page, tampering with localStorage, and replacing tenants.

Expected Output

Produce a set of routing guard implementations, covering loading, not logged in, insufficient permissions, bounce after login and session expiration. During verification, directly access the private URL, refresh the page, switch roles, and tamper with redirect parameters to confirm that the behavior is stable and the API still has server authorization.

Read more
Ships withfrontend-craft

frontend-craft is a universal frontend plugin that brings the same opinionated engineering standards to all 15 AI coding assistants.

Get the whole plugin

Other skills on frontend-craft.