Skip to content

Commit 7be4c3b

Browse files
committed
fix(webapp): take the impersonate route out of the admin layout
The admin layout gates on requireSuper via getUserId, which resolves to the impersonated user while impersonating — so starting on a second target ran that gate against the target and it answered with its own redirect to /. The switch worked only because the router prefers the deepest redirect, which is too subtle a thing for an auth path to depend on. The trailing underscore keeps the route at /admin/impersonate while opting it out of the layout. Nothing is lost: the route only ever redirects, so it never rendered inside it.
1 parent 4f7fc96 commit 7be4c3b

1 file changed

Lines changed: 12 additions & 0 deletions

File tree

apps/webapp/app/routes/admin.impersonate.tsx renamed to apps/webapp/app/routes/admin_.impersonate.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ import { validateAndConsumeImpersonationToken } from "~/services/impersonation.s
1111
import { logger } from "~/services/logger.server";
1212
import { sanitizeRedirectPath } from "~/utils";
1313

14+
/**
15+
* Served at `/admin/impersonate`, but the trailing `_` on `admin_` keeps it out of the `admin.tsx`
16+
* layout on purpose.
17+
*
18+
* That layout's loader is `dashboardLoader({ authorization: { requireSuper: true } })`, which
19+
* resolves the user through `getUserId` — the impersonated id while impersonating. So starting on a
20+
* second target ran the parent gate against the target, which isn't a super admin, and it answered
21+
* with its own `redirect("/")`. Nesting would leave this route's behaviour depending on the router
22+
* preferring the deepest redirect; opting out removes the question. Nothing is lost — this route
23+
* only ever redirects, so it never rendered inside the layout anyway.
24+
*/
25+
1426
const FormSchema = z.object({ id: z.string() });
1527

1628
/**

0 commit comments

Comments
 (0)