๐Ÿ“… let's chat! explore the endless possibilities creating industries that don't exist. click here

lokalise-enterprise-rbac

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>

Allowed Tools

No tools specified

Provided by Plugin

lokalise-pack

Claude Code skill pack for Lokalise (24 skills)

saas packs v1.0.0
View Plugin

Installation

This skill is included in the lokalise-pack plugin:

/plugin install lokalise-pack@claude-code-plugins-plus

Click to copy

Instructions

# 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 ```typescript // Role definitions aligned with Lokalise 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 = { owner: { manageTeam: true, manageProject: true, manageKeys: true, editTranslations: true, reviewTranslations: true, downloadFiles: true, uploadFiles: true, viewOnly: false, }, admin: { manageTeam: true, manageProject: true, manageKeys: true, editTranslations: true, reviewTranslations: true, downloadFiles: true, uploadFiles: true, viewOnly: false, }, manager: { manageTeam: false, manageProject: true, manageKeys: true, editTranslations: true, reviewTranslations: true, downloadFiles: true, uploadFiles: true, viewOnly: false, }, developer: { manageTeam: false, manageProject: false, manageKeys: true, editTranslations: true, reviewTranslations: false, downloadFiles: true, uploadFiles: true, viewOnly: false, }, translator: { manageTeam: false, manageProject: false, manageKeys: false, editTranslations: true, reviewTranslations: false, downloadFiles: true, uploadFiles: false, viewOnly: false, }, reviewer: { manageTeam: false, manageProject: false, manageKeys: false, editTranslations: false, reviewTranslations: true, downloadFiles: true, uploadFiles: false, viewOnly: false, }, viewer: { manageTeam: false, manageProject: false, manageKeys: false, editTranslations: false, reviewTranslations: false, downloadFiles: true, uploadFiles: false, viewOnly: true, }, }; function checkPermission( role: LokaliseRole, permission: keyof LokalisePermissions ): boolean { return ROLE_PERMISSIONS[role][permission]; } ``` ### Step 2: Team Management ```typescript import { LokaliseApi } from "@lokalise/node-api"; const client = new LokaliseApi({ apiKey: process.env.LOKALISE_API_TOKEN!, }); // List team users 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, })); } // Add user to team async function addTeamUser(teamId: number, email: string, role: LokaliseRole) { const user = await client.teamUsers().create({ team_id: teamId, email, role, }); console.log(`Added ${email} as ${role} to team ${teamId}`); return user; } // Update user role async function updateUserRole(teamId: number, userId: number, newRole: LokaliseRole) { const user = await client.teamUsers().update(userId, { team_id: teamId, role: newRole, }); console.log(`Updated user ${userId} to role ${newRole}`); return user; } // Remove user from team async function removeTeamUser(teamId: number, userId: number) { await client.teamUsers().delete(userId, { team_id: teamId }); console.log(`Removed user ${userId} from team ${teamId}`); } ``` ### Step 3: Project-Level Access Control ```typescript // Add contributor to project with specific role async function addProjectContributor( projectId: string, email: string, role: LokaliseRole, languages?: string[] // Optional: restrict to specific languages ) { const params: any = { email, is_admin: role === LokaliseRole.Admin || role === LokaliseRole.Manager, is_reviewer: role === LokaliseRole.Reviewer, }; // Language-specific access for translators 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; } // List project contributors async function listProjectContributors(projectId: string) { const contributors = await client.contributors().list({ project_id: projectId, }); return contributors.items.map(c => ({ userId: c.user_id, email: c.email, fullname: c.fullname, isAdmin: c.is_admin, isReviewer: c.is_reviewer, languages: c.languages, })); } ``` ### Step 4: Permission Middleware ```typescript // Express middleware for permission checks 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(); }; } // Usage in routes app.post("/api/translations/upload", requireLokalisePermission("uploadFiles"), uploadHandler ); app.delete("/api/keys/:keyId", requireLokalisePermission("manageKeys"), deleteKeyHandler ); app.get("/api/translations", requireLokalisePermission("downloadFiles"), downloadHandler ); ``` ### Step 5: SSO Integration (Enterprise) ```typescript // Map IdP groups to Lokalise roles const IDP_GROUP_MAPPING: Record = { "Engineering": LokaliseRole.Developer, "Localization-Admins": LokaliseRole.Admin, "Translators-ES": LokaliseRole.Translator, "Translators-FR": LokaliseRole.Translator, "QA-Team": LokaliseRole.Reviewer, "Product": LokaliseRole.Viewer, }; // SAML callback handler async function handleSamlCallback(samlResponse: any) { const { email, groups } = parseSamlResponse(samlResponse); // Determine Lokalise role from IdP groups let role = LokaliseRole.Viewer; // Default for (const group of groups) { if (IDP_GROUP_MAPPING[group]) { const mappedRole = IDP_GROUP_MAPPING[group]; // Use highest privilege role if (roleHierarchy(mappedRole) > roleHierarchy(role)) { role = mappedRole; } } } // Provision user in Lokalise if needed await ensureUserExists(email, role); return { email, role }; } function roleHierarchy(role: LokaliseRole): number { const hierarchy: Record = { owner: 100, admin: 90, manager: 80, developer: 70, reviewer: 50, translator: 40, viewer: 10, }; return 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 ```typescript // Before allowing action if (!checkPermission(user.role, "uploadFiles")) { throw new ForbiddenError("You don't have permission to upload files"); } ``` ### Audit User Access ```typescript 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 ```typescript async function updateTeamRoles( teamId: number, roleUpdates: Array<{ userId: number; newRole: LokaliseRole }> ) { for (const update of roleUpdates) { await updateUserRole(teamId, update.userId, update.newRole); // Respect rate limits await new Promise(r => setTimeout(r, 200)); } } ``` ## Resources - [Lokalise Team Management](https://docs.lokalise.com/en/articles/1400472-team-management) - [Lokalise Contributors](https://developers.lokalise.com/reference/list-all-contributors) - [Lokalise Enterprise](https://lokalise.com/enterprise) ## Next Steps For major migrations, see `lokalise-migration-deep-dive`.

Skill file: plugins/saas-packs/lokalise-pack/skills/lokalise-enterprise-rbac/SKILL.md