| name | lokalise-enterprise-rbac |
| description | Configure Lokalise enterprise SSO, role-based access control, and team management.
Use when implementing SSO integration, configuring role-based permissions,
or setting up organization-level controls for Lokalise.
Trigger with phrases like "lokalise SSO", "lokalise RBAC",
"lokalise enterprise", "lokalise roles", "lokalise permissions", "lokalise team".
|
| allowed-tools | Read, Write, Edit |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Lokalise Enterprise RBAC
Overview
Configure enterprise-grade access control for Lokalise with teams, roles, and SSO.
Prerequisites
- Lokalise Enterprise or Team plan
- Identity Provider (IdP) for SSO (optional)
- Understanding of role-based access patterns
- Admin access to Lokalise organization
Lokalise Role Hierarchy
| Role | Scope | Permissions |
|---|
| Owner | Organization | Full control, billing, delete org |
| Admin | Organization | Manage teams, projects, users |
| Manager | Team/Project | Manage project settings, contributors |
| Developer | Project | Read/write keys, translations |
| Translator | Project | Read/write translations only |
| Reviewer | Project | Review and approve translations |
| Viewer | Project | Read-only access |
Instructions
Step 1: Define Role Mappings
enum LokaliseRole {
Owner = "owner",
Admin = "admin",
Manager = "manager",
Developer = "developer",
Translator = "translator",
Reviewer = "reviewer",
Viewer = "viewer",
}
interface LokalisePermissions {
manageTeam: boolean;
manageProject: boolean;
manageKeys: boolean;
editTranslations: boolean;
reviewTranslations: boolean;
downloadFiles: boolean;
uploadFiles: boolean;
viewOnly: boolean;
}
const ROLE_PERMISSIONS: Record<LokaliseRole, LokalisePermissions> = {
owner: {
manageTeam: true,
manageProject: true,
manageKeys: true,
editTranslations: true,
reviewTranslations: true,
: ,
: ,
: ,
},
: {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
},
: {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
},
: {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
},
: {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
},
: {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
},
: {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
},
};
(): {
[role][permission];
}
Step 2: Team Management
import { LokaliseApi } from "@lokalise/node-api";
const client = new LokaliseApi({
apiKey: process.env.LOKALISE_API_TOKEN!,
});
async function listTeamUsers(teamId: number) {
const users = await client.teamUsers().list({ team_id: teamId });
return users.items.map(u => ({
userId: u.user_id,
email: u.email,
fullname: u.fullname,
role: u.role,
createdAt: u.created_at,
}));
}
async function addTeamUser(teamId: number, email: string, role: LokaliseRole) {
const user = await client.teamUsers().create({
team_id: teamId,
email,
role,
});
.();
user;
}
() {
user = client.().(userId, {
: teamId,
: newRole,
});
.();
user;
}
() {
client.().(userId, { : teamId });
.();
}
Step 3: Project-Level Access Control
async function addProjectContributor(
projectId: string,
email: string,
role: LokaliseRole,
languages?: string[]
) {
const params: any = {
email,
is_admin: role === LokaliseRole.Admin || role === LokaliseRole.Manager,
is_reviewer: role === LokaliseRole.Reviewer,
};
if (languages && languages.length > 0) {
params.languages = languages.map(lang => ({
lang_iso: lang,
is_writable: role === LokaliseRole.Translator,
}));
}
const contributor = await client.contributors().create(projectId, params);
console.log(`Added ${email} to project ${projectId} as ${role}`);
return contributor;
}
() {
contributors = client.().({
: projectId,
});
contributors..( ({
: c.,
: c.,
: c.,
: c.,
: c.,
: c.,
}));
}
Step 4: Permission Middleware
function requireLokalisePermission(permission: keyof LokalisePermissions) {
return async (req: Request, res: Response, next: NextFunction) => {
const user = req.user as { lokaliseRole: LokaliseRole };
if (!checkPermission(user.lokaliseRole, permission)) {
return res.status(403).json({
error: "Forbidden",
message: `Missing permission: ${permission}`,
requiredPermission: permission,
userRole: user.lokaliseRole,
});
}
next();
};
}
app.post("/api/translations/upload",
requireLokalisePermission("uploadFiles"),
uploadHandler
);
app.delete("/api/keys/:keyId",
requireLokalisePermission("manageKeys"),
deleteKeyHandler
);
app.get("/api/translations",
requireLokalisePermission(),
downloadHandler
);
Step 5: SSO Integration (Enterprise)
const IDP_GROUP_MAPPING: Record<string, LokaliseRole> = {
"Engineering": LokaliseRole.Developer,
"Localization-Admins": LokaliseRole.Admin,
"Translators-ES": LokaliseRole.Translator,
"Translators-FR": LokaliseRole.Translator,
"QA-Team": LokaliseRole.Reviewer,
"Product": LokaliseRole.Viewer,
};
async function handleSamlCallback(samlResponse: any) {
const { email, groups } = parseSamlResponse(samlResponse);
let role = LokaliseRole.Viewer;
for (const group of groups) {
if (IDP_GROUP_MAPPING[group]) {
const mappedRole = IDP_GROUP_MAPPING[group];
if (roleHierarchy(mappedRole) > (role)) {
role = mappedRole;
}
}
}
(email, role);
{ email, role };
}
(): {
: <, > = {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
};
hierarchy[role];
}
Output
- Role definitions implemented
- Team management APIs
- Project-level access control
- Permission middleware active
Error Handling
| Issue | Cause | Solution |
|---|
| Permission denied | Wrong role | Check role assignment |
| SSO mismatch | Group mapping wrong | Update IDP_GROUP_MAPPING |
| User not found | Not provisioned | Auto-provision on first login |
| Language access denied | Not in languages array | Update contributor languages |
Examples
Quick Permission Check
if (!checkPermission(user.role, "uploadFiles")) {
throw new ForbiddenError("You don't have permission to upload files");
}
Audit User Access
async function auditProjectAccess(projectId: string) {
const contributors = await listProjectContributors(projectId);
console.log(`Project ${projectId} access audit:`);
contributors.forEach(c => {
console.log(` ${c.email}: ${c.isAdmin ? "Admin" : c.isReviewer ? "Reviewer" : "Contributor"}`);
if (c.languages) {
console.log(` Languages: ${c.languages.map(l => l.lang_iso).join(", ")}`);
}
});
return contributors;
}
Bulk Role Update
async function updateTeamRoles(
teamId: number,
roleUpdates: Array<{ userId: number; newRole: LokaliseRole }>
) {
for (const update of roleUpdates) {
await updateUserRole(teamId, update.userId, update.newRole);
await new Promise(r => setTimeout(r, 200));
}
}
Resources
Next Steps
For major migrations, see lokalise-migration-deep-dive.