Skip to content

Documentation Suggestion: Validating Permissions in Middleware Securely #365

Description

@AdrianVvazquez

Prerequisites

How can we improve the docs or what is missing?

Hi Kinde team 👋

While working with the Kinde SDK for Next.js, I noticed that the documentation currently doesn’t cover how to validate permissions inside middleware before the request reaches protected pages. This is essential for many use cases, including role-based access and API-level protection.

I understand that too much internal detail might raise security concerns, but I believe the documentation could offer a recommended pattern to guide developers. For instance:

  • How to access session data (like roles or permissions) securely within middleware
  • How to use getKindeServerSession() or similar utilities in this context

Thank you for the great work — happy to contribute however I can!

Greetings from Mexico!

Provide extra context, such as what you were trying to do and your requirements

Here’s how I’m currently resolving it, using middleware to enforce role-based access for specific routes:


Solution 1 — Using getKindeServerSession()

/routes.ts

export const requiredPermissionsByVisibility = {
  public: [],
  admin: ["access:admin"],
  superadmin: ["access:superadmin"],
} as const;

/middleware.ts

const publicPaths = ["/", "/rifas"];

function getVisibilityForPath(
  path: string
): "public" | "admin" | "superadmin" | null {
  const match = routeAccess
    .sort((a, b) => b.path.length - a.path.length)
    .find((r) => path.startsWith(`${r.path}`));
  return match?.visibility || null;
}

export default withAuth(
  async function middleware(req: NextRequest) {
    const { pathname } = req.nextUrl;
    const { isAuthenticated, getPermissions, getUser } =
      getKindeServerSession();

    const user = await getUser();
    const permissions = await getPermissions();
    const pathVisibility = getVisibilityForPath(pathname);

    if (
      !(await isAuthenticated()) ||
      !user ||
      !pathVisibility ||
      !permissions
    ) {
      return NextResponse.redirect(new URL("/unauthorized", req.url));
    }

    if (pathVisibility === "public") {
      return NextResponse.next();
    }

    const requiredPermissions = requiredPermissionsByVisibility[pathVisibility];

    const hasPermission = requiredPermissions.some((p) =>
      permissions.permissions.includes(p)
    );

    if (!hasPermission) {
      return NextResponse.redirect(new URL("/unauthorized", req.url));
    }

    return NextResponse.next();
  },
  {
    isReturnToCurrentPage: true,
    publicPaths,
  }
);

🔄 Solution 2 — Extending NextRequest with kindeAuth

/routes.ts

export const requiredPermissionsByVisibility = {
  public: [],
  admin: ["access:admin"],
  superadmin: ["access:superadmin"],
} as const;

/middleware.ts

const publicPaths = ["/", "/rifas"];

function getVisibilityForPath(
  path: string
): "public" | "admin" | "superadmin" | null {
  const match = routeAccess
    .sort((a, b) => b.path.length - a.path.length)
    .find((r) => path.startsWith(`${r.path}`));
  return match?.visibility || null;
}

interface KindeRequestProps extends NextRequest {
  kindeAuth: { user: KindeUserBase; token: KindeAccessToken };
}

export default withAuth(
  async function middleware(req: KindeRequestProps) {
    const { pathname } = req.nextUrl;
    const kinde = req.kindeAuth;
    const visibility = getVisibilityForPath(pathname);
    const permissions = kinde?.token?.permissions || [];

    if (!visibility || !kinde?.user) {
      return NextResponse.redirect(new URL("/unauthorized", req.url));
    }

    if (visibility === "public") {
      return NextResponse.next();
    }

    const requiredPermissions = requiredPermissionsByVisibility[visibility];

    const hasPermission = requiredPermissions.some((p) =>
      permissions.includes(p)
    );

    if (!hasPermission) {
      return NextResponse.redirect(new URL("/unauthorized", req.url));
    }

    return NextResponse.next();
  },
  {
    isReturnToCurrentPage: true,
    publicPaths,
  }
);

If the docs page already exists, please provide a link

https://docs.kinde.com/developer-tools/sdks/backend/nextjs-sdk/#set-up-middleware

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions