Access Scopes - Getting Started
Set up tenant isolation for actor communication in minutes.
What are Access Scopes?
Access Scopes provide tenant isolation for actor communication. When you assign an actor to a scope, all of that actor's MQTT topics are automatically namespaced under the scope's slug. Actors in different scopes cannot see or communicate with each other, even if they are in the same app and room.
This is the foundation for building multi-tenant applications on NoLag. Instead of creating separate apps or projects for each tenant, you create a single app and isolate tenants using scopes.
Prerequisites
- A NoLag account (free tier available)
- A project with at least one app and actor created
- An API key with write access to actors and scopes
Step 1: Create a Scope
Create a scope via the REST API. Each scope has a slug (URL-safe identifier used in topic namespacing) and an optional name (human-readable label). The slug is immutable after creation.
const response = await fetch(
`https://api.nolag.app/v1/organizations/${orgId}/projects/${projectId}/scopes`,
{
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
slug: "client-acme",
name: "Acme Corporation",
}),
}
);
const scope = await response.json();
console.log("Created scope:", scope.accessScopeId);
// => { accessScopeId: "01HZ...", slug: "client-acme", name: "Acme Corporation" }Step 2: Assign an Actor to the Scope
Patch the actor to set its accessScopeId. The actor will immediately begin receiving topics namespaced under the scope's slug. You can assign the scope at actor creation time or update it later.
const response = await fetch(
`https://api.nolag.app/v1/organizations/${orgId}/projects/${projectId}/actors/${actorId}`,
{
method: "PATCH",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
accessScopeId: scope.accessScopeId,
}),
}
);
const actor = await response.json();
console.log("Actor scoped to:", actor.accessScopeId);Step 3: Verify Isolation
Once an actor is scoped, its topic namespace changes. The scope slug is injected between the app slug and the room slug, creating a partition that prevents cross-tenant communication.
// Without a scope, the actor subscribes to:
// app-slug/room-slug/topic
//
// With scope "client-acme", the same actor subscribes to:
// app-slug/client-acme/room-slug/topic
//
// The scope slug is injected into the topic namespace automatically.
// Actors in different scopes CANNOT see each other's messages.
import NoLag from "@nolag/js-sdk";
// Actor assigned to "client-acme" scope
const connection = await NoLag.connect({ actorToken: SCOPED_ACTOR_TOKEN });
// The topic namespace is partitioned automatically
// This actor only receives messages within the "client-acme" scope
const topic = connection.subscribe("my-room/updates");
topic.on("message", (data) => {
// Only messages from actors in the same scope arrive here
console.log("Scoped message:", data);
});Topic Namespace Format
| Scenario | Topic Format |
|---|---|
| Without scope | app-slug/room-slug/topic |
| With scope | app-slug/scope-slug/room-slug/topic |
Next Steps
- Concepts - understand how scopes work under the hood
- Multi-Tenancy Patterns - real-world patterns for tenant isolation
- API Reference - complete endpoint documentation