Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungConnect Claude to Perplexity AI Pro with Zero Search API Fees(24.09.2026 um 09:57 Uhr)
Sichere ProgrammierungInvestigating Fraud with a Graph, Not Just a Prompt(24.09.2026 um 10:01 Uhr)
Sichere ProgrammierungA .docx does not store where its pages end(24.09.2026 um 10:01 Uhr)
Sichere Programmierung9 Best Enterprise AI Gateways With SSO, RBAC, and Audit Logs (2026)(24.09.2026 um 10:01 Uhr)
Sichere ProgrammierungThe Signal Contract for a 5-Minute TWAP Market(24.09.2026 um 10:03 Uhr)
Sichere ProgrammierungRemoteMac(24.09.2026 um 10:06 Uhr)
Sichere ProgrammierungDesigning a Batch Move That Handles Partial Failure(24.09.2026 um 10:07 Uhr)
Sichere ProgrammierungThe Model Was Never the Problem(24.09.2026 um 10:07 Uhr)
Sichere ProgrammierungConnect Claude to Perplexity AI Pro with Zero Search API Fees(24.09.2026 um 09:57 Uhr)
Sichere ProgrammierungInvestigating Fraud with a Graph, Not Just a Prompt(24.09.2026 um 10:01 Uhr)
Sichere ProgrammierungA .docx does not store where its pages end(24.09.2026 um 10:01 Uhr)
Sichere Programmierung9 Best Enterprise AI Gateways With SSO, RBAC, and Audit Logs (2026)(24.09.2026 um 10:01 Uhr)
Sichere ProgrammierungThe Signal Contract for a 5-Minute TWAP Market(24.09.2026 um 10:03 Uhr)
Sichere ProgrammierungRemoteMac(24.09.2026 um 10:06 Uhr)
Sichere ProgrammierungDesigning a Batch Move That Handles Partial Failure(24.09.2026 um 10:07 Uhr)
Sichere ProgrammierungThe Model Was Never the Problem(24.09.2026 um 10:07 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Building Multi-Tenant Apps Using Clerk's "Organization" and Next.js

Building a full-fledged multi-tenant application can be very challenging. Besides having a flexible sign-up and sign-in system, you also need to implement several other essential pieces: Creating and managing tenants User invitation…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Building a full-fledged multi-tenant application can be very challenging. Besides having a flexible sign-up and sign-in system, you also need to implement several other essential pieces:




  • Creating and managing tenants

  • User invitation flow

  • Managing roles and permissions

  • Enforcing data segregation and access control throughout the entire application



It sounds like lots of work, and it indeed is. You may have done this multiple times if you're a veteran SaaS developer.



Clerk is one of the most popular authentication and user management cloud services. Its combination of APIs and pre-built UI components dramatically simplifies the integration of such capabilities into your application. Similarly, its newer "Organization" feature provides an excellent starting point for creating multi-tenant applications. In this post, we'll explore leveraging it to build a non-trivial one while trying to keep our code simple and clean.






The goal and the stack



The target application we'll build is a Todo List. Its core functionalities are simple: creating lists and managing todos within them. However, the focus will be on the multi-tenancy and access control aspects:




  • Organization management



Users can create organizations and invite others to join. They can manage members and set their roles.




  • Current context



Users can choose an organization to be the current context.




  • Data segregation



Only data within the current organization can be accessed.





  • Role-based access control




    • Admin members have full access to all data within their organization.

    • Regular members have full access to the todo lists they own.

    • Regular members can view the other members' todo lists and manage their content, as long as the list is not private.








Clerk can be used with any JavaScript framework, but its support for Next.js seems to be the best. So we'll use Next.js as our full-stack framework, along with two other essential pieces of weapon:





You can find the link of the completed project at the end of the post.






Adding organization management



I assume you've created a Next.js project and set up the basic Clerk sign-up/sign-in flow following the guide. Also, make sure you've enabled the "Organization" feature in Clerk's dashboard.



Now, we can add the "OrganizationSwitcher" component into the layout.




// src/app/layout.tsx

import { OrganizationSwitcher } from "@clerk/nextjs";
...

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<ClerkProvider>
<html lang="en">
<body>
<header>
<SignedOut>
<SignInButton />
</SignedOut>
<SignedIn>
<div>
<OrganizationSwitcher />
<UserButton />
</div>
</SignedIn>
</header>
</body>
</html>
</ClerkProvider>
);
}






With this one-liner, you'll have a set of fully working UI components for managing organizations and choosing an active one!



Organization Switcher






Setting up the database



Our user and organization data are stored on Clerk's side. We need to store the todo lists and items in our own database. In this section, we'll set up Prisma and ZenStack and create the database schema.



Let's start with installing the necessary packages:




npm install --save-dev prisma zenstack
npm install @prisma/client @zenstackhq/runtime






Then we can create the database schema. Please note that we're creating a schema.zmodel file (as a replacement of "schema.prisma"). The ZModel language is a superset of Prisma schema language, allowing you to model both the data schema and access control policies. In this section, we'll only focus on the data modeling part.




// schema.zmodel

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

generator js {
provider = "prisma-client-js"
}

// Todo list
model List {
id String @id @default(cuid())
createdAt DateTime @default(now())
title String
private Boolean @default(false)
orgId String?
ownerId String
todos Todo[]
}

// Todo item
model Todo {
id String @id @default(cuid())
title String
completedAt DateTime?
list List @relation(fields: [listId], references: [id], onDelete: Cascade)
listId String
}






You can then generate a regular Prisma schema file and push the schema to the database:




# The `zenstack generate` command generates the "prisma/schema.prisma" file and runs "prisma generate"
npx zenstack generate
npx prisma db push






Finally, create a "src/server/db.ts" file to export the Prisma client:




// src/server/db.ts
import { PrismaClient } from "@prisma/client";
export const prisma = new PrismaClient();









Implementing access control



As mentioned, ZenStack allows you to model both data and access control in a single schema. Let's see how we can entirely implement our authorization requirements with it. The rules are defined with the @@allow and @@deny attributes. Access is rejected by default unless explicitly granted with an @@allow rule.



Although authorization is a distinct concept from authentication, it usually depends on authentication to work. For example, to determine if the current user has access to a list, a verdict must be made based on the user's id, current organization, and role in the organization. To access such information, let's first declare a type to express it:




// schema.zmodel

// The shape of `auth()`
type Auth {
// Current user's ID
userId String @id

// User's current organization ID
currentOrgId String?

// User's role in the current organization
currentOrgRole Role?

@@auth
}






Then you can use the special auth() function in access policy rules to access the current user's information. Let's use the List model as an example to demonstrate how the rules are defined.




// schema.zmodel

model List {
...

// deny anonymous access
@@deny('all', auth() == null)

// tenant segregation: deny access if the user's current org doesn't match
@@deny('all', auth().currentOrgId != orgId)

// owner/admin has full access
@@allow('all', auth().userId == ownerId || auth().currentOrgRole == 'org:admin')

// can be read by org members if not private
@@allow('read', !private)

// when create, owner must be set to current user
@@allow('create', ownerId == auth().userId)
}






The last piece of the puzzle is, as you may already be wondering, where the value of auth() comes from? At runtime, ZenStack offers an enhance() API to create an enhanced PrismaClient (a lightweighted wrapper) that automatically enforces the access policies. You pass in a user context (usually fetched from the authentication provider) when calling enhance(), and that context provides the value for auth().



We'll see how it works in detail in the next section.






Finally, the UI



Before diving into creating the UI, let's first make a helper to get an enhanced PrismaClient for the current user.




// src/server/db.ts

import { auth } from "@clerk/nextjs/server";
import { Role } from "@prisma/client";
import { enhance } from "@zenstackhq/runtime";

export async function getUserDb() {
// get the current user's information from Clerk
const { userId, orgId, orgRole } = await auth();

// create an enhanced Prisma Client with proper user context
const user = userId
? {
userId,
currentOrgId: orgId,
currentOrgRole: orgRole
}
: undefined; // anonymous
return enhance(prisma, { user });
}






Let's build the UI using React Server Components (RSC) and Server Actions. We'll also consistently use the getUserDb() helper to access the database with access control enforcement.



Here's the RSC that renders the todo lists for the current user (with styling omitted):




// src/components/TodoList.tsx

// Component showing Todo list for the current user

export default async function TodoLists() {
const db = await getUserDb();

// enhanced PrismaClient automatically filters out
// the lists that the user doesn't have access to
const lists = await db.list.findMany({
orderBy: { updatedAt: "desc" },
});

return (
<div>
<div>
{/* client component for creating a new List */}
<CreateList />

<ul>
{lists?.map((list) => (
<Link href={`/lists/${list.id}`} key={list.id}>
<li>{list.title}</li>
</Link>
))}
</ul>
</div>
</div>
);
}






A client component that creates a new list by calling into a server action:




// src/components/CreateList.tsx

"use client";

import { createList } from "~/app/actions";

export default function CreateList() {
function onCreate() {
const title = prompt("Enter a title for your list");
if (title) {
createList(title);
}
}

return (
<button onClick={onCreate}>
Create a list
</button>
);
}









// src/app/actions.ts

'use server';

import { revalidatePath } from "next/cache";
import { getUserDb } from "~/server/db";

export async function createList(title: string) {
const db = await getUserDb();
await db.list.create({ data: { title } });
revalidatePath("/");
}






Todo List UI



The components that manage Todo items are not shown for brevity, but the ideas are similar. You can find the fully completed code here.






Conclusion



Authentication and authorization are two cornerstones of most applications. They can be especially challenging to build for multi-tenant ones. This post demonstrated how the work can be significantly simplified and streamlined by combining Clerk's "Organization" feature and ZenStack's access control capabilities. The end result is a secure application with great flexibility and little boilerplate code.



Clerk also supports defining custom roles and permissions (still Beta) for organizations. Although not covered in this post, with some tweaking, you should be able to leverage it to define access policies. That way, you can manage permissions with Clerk's dashboard and have ZenStack enforce them at runtime.






ZenStack is our open-source TypeScript toolkit for building high-quality, scalable apps faster, smarter, and happier. It centralizes the data model, access policies, and validation rules in a single declarative schema on top of Prisma, well-suited for AI-enhanced development. Start integrating ZenStack with your existing stack now!

SOC Incident Playbook: Remote Code Execution (RCE) Defense
title: Detect Exploitation - Building Multi-Tenant Apps Using Clerk's "Organization" and Next.js
id: 6d0ed340-2ee1-40fc-8a9b-a3721351576e
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-24
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-24"
        description = "YARA Signature for "
    strings:
        $str = "Building Multi-Tenant Apps Usi" ascii wide
    condition:
        any of them
}
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich Building Multi-Tenant Apps Using Clerk&#039;s.... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Building Multi-Tenant Apps Using Clerk's "Organization" and Next.js

Thematisch verwandte Begriffe: Building, MultiTenant, Apps, Using · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-97056 | SigNoz versions from v0.98.0 up to (but not including) v0.143.0, when co…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick