#How are you guys securing custom views?

3 messages · Page 1 of 1 (latest)

vague root
#

Hi, I'm wondering whats a reasonable approach to secure custom views?

In their example they add a check but doing that for each view seems a bit repetitive?

https://payloadcms.com/docs/custom-components/custom-views#securing-custom-views

I tried adding a sort of route-guard wrapping the logic from their example, but even that seems wrong. What if someone misses to add it... Example:

// customView.tsx
const CustomViewTemplate = async ({
  initPageResult,
  params,
  searchParams,
}: AdminViewServerProps) => {

  return (
    <DefaultTemplate
      visibleEntities={initPageResult.visibleEntities}
      i18n={initPageResult.req.i18n}
      payload={initPageResult.req.payload}
      locale={initPageResult.locale}
      params={params}
      permissions={initPageResult.permissions}
      user={initPageResult.req.user!}
      searchParams={searchParams}
    >
      <Gutter>
        <h1>Some Custom View</h1>
      </Gutter>
    </DefaultTemplate>
  );
};

export default adminViewRouteGuard(
  featureFlagGuard(CustomViewTemplate, {
    flags: FeatureFlags.ApiEventsManagement,
  }),
);

// routeGuard.tsx
export const adminViewRouteGuard = (
  Component: (props: AdminViewServerProps) => Promise<JSX.Element>,
  options = defaultOptions
) => {
  const guard = async (props: AdminViewServerProps) => {
    const { req } = props.initPageResult;
    if (!req.user) {
      return redirect(buildLoginRedirectUrl(req));
    }
    return Component(props);
  };
  return guard;
};

Should I not be able to check under middleware or inject it some better way?

narrow wind
#

Hey @vague root you're on the right track, but the HOC wrapper pattern (adminViewRouteGuard) adds indirection without real benefit here.

What I would do instead, which would give you a shared role check across multiple views, would be to use a utility function you call at the top of each view:

export const requireAdmin = (req: PayloadRequest) => {
  if (!req.user?.roles?.includes('admin')) redirect('/admin')
}

const CustomView = async ({ initPageResult }: AdminViewServerProps) => {
  requireAdmin(initPageResult.req)
  // ...
}