Permissions - Manage permissions with access tokens

Managing permissions by issuing access tokens follows the analogy of a “hotel room key card”. Anyone that has that key card can open the doors that the card gives access to. It’s easy to give out those key cards right from your back end.

To set up your authentication endpoint with access token permissions, make sure to follow these quick steps.

Authentication patterns

Full access to just one room

import { Liveblocks } from "@liveblocks/node";
const liveblocks = new Liveblocks({ secret: "",});
export async function POST(request: Request) { // Get the current user from your database const user = (request);
// Start an auth session inside your endpoint const session = liveblocks.prepareSession( user.id, { userInfo: user.metadata } // Optional );
// Implement your own security, and give the user access to the room const { room } = await request.json(); if (room && (user, room)) { session.allow(room, session.FULL_ACCESS); }
// Authorize the user and return the result const { status, body } = await session.authorize(); return new Response(body, { status });}

Full access to all rooms from a team

To be able to use this pattern, you will have to name your rooms using a fixed pattern of <team>:<room>. For suggestions, read more on our naming best practices.

import { Liveblocks } from "@liveblocks/node";
const liveblocks = new Liveblocks({ secret: "",});
export async function POST(request: Request) { const user = (request);
const session = liveblocks.prepareSession(user.id, { userInfo: user.metadata, });
// Implement your own security, and give the user access to the room const { room } = await request.json(); if (room && (user, room)) { // Suppose this application organizes their Liveblocks rooms by keys // structured like `<team>:<room>`. // We can then use the passed-in requested room to infer which team to // check membership for. const [team, _] = room.split(":"); if ((user, team)) { // If the user is a member of this team, don't just grant full access to // the request room, but to _all_ of the team's rooms, using a prefix // pattern. session.allow(`${team}:*`, session.FULL_ACCESS); } session.allow(room, session.FULL_ACCESS); }
const { status, body } = await session.authorize(); return new Response(body, { status });}

Full access to all rooms from a team, but read-only access to rooms from the organization level

To be able to use this pattern, you will have to name your rooms using a fixed pattern of <org>:<team>:<room>. For suggestions, read more on our naming best practices.

import { Liveblocks } from "@liveblocks/node";
const liveblocks = new Liveblocks({ secret: "",});
export async function POST(request: Request) { const user = (request);
const session = liveblocks.prepareSession(user.id, { userInfo: user.metadata, });
const { room } = await request.json(); if (room && (user, room)) { // Suppose this application organizes their Liveblocks rooms by keys // structured like `<org>:<team>:<room>`. // We can then use the passed-in requested room to infer which team to // check membership for. const [org, team, _] = room.split(":"); if ((user, org)) { session.allow(`${org}:*`, session.READ_ACCESS); } if ((user, team)) { session.allow(`${org}:${team}:*`, session.FULL_ACCESS); } }
const { status, body } = await session.authorize(); return new Response(body, { status });}

Best practices for naming your rooms

Being able to specify permissions for infinite rooms using prefix pattern matching offers great powers, but it does assume that you design your room names a bit more cautiously. For example, granting room prefix permissions won’t work if you use random room IDs for your project, because there won’t be a shared prefix.

Therefore, if you want to adopt this pattern, we recommend designing your room names hierarchically in namespaced “buckets” in a way that makes sense for your app.

For example, if your app manages documents by team, each room could be named using a <team-id>:<room-id> pattern:

For example:

  • "engineering:R5AhJlTSKwBR"
  • "engineering:PqY3oqRcV-7Z"
  • "marketing:SVUPHaboSc10"
  • "marketing:Y7Uyw44YRxjY"

As another example, if your app is a SAAS product, and you have many customers, you can add an additional top-level key to prefix your room names, e.g. <app-id>::<group-id>/<room-id>:

Example room IDs:

  • "jOzGLFEAedV5::engineering/R5AhJlTSKwBR"
  • "jOzGLFEAedV5::engineering/PqY3oqRcV-7Z"
  • "rGSoepTL7r-Y::marketing/SVUPHaboSc10"
  • "rGSoepTL7r-Y::marketing/Y7Uyw44YRxjY"

Again, the :: and / separators here are used for illustrative purposes. You can use any separator you want.