| name | twinmind-enterprise-rbac |
| description | Implement enterprise role-based access control for TwinMind.
Use when setting up team permissions, configuring SSO/SAML,
or implementing organization-level access policies.
Trigger with phrases like "twinmind RBAC", "twinmind permissions",
"twinmind enterprise access", "twinmind SSO", "twinmind team management".
|
| allowed-tools | Read, Write, Edit |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
TwinMind Enterprise RBAC
Overview
Enterprise-grade role-based access control for TwinMind with SSO integration, team management, and audit capabilities.
Prerequisites
- TwinMind Enterprise account
- Admin access to TwinMind organization
- Identity provider (Okta, Azure AD, Google Workspace)
- Understanding of RBAC concepts
Instructions
Step 1: Define Roles and Permissions
export enum Permission {
TRANSCRIPT_CREATE = 'transcript:create',
TRANSCRIPT_READ = 'transcript:read',
TRANSCRIPT_READ_ALL = 'transcript:read:all',
TRANSCRIPT_DELETE = 'transcript:delete',
TRANSCRIPT_DELETE_ALL = 'transcript:delete:all',
SUMMARY_GENERATE = 'summary:generate',
SUMMARY_READ = 'summary:read',
ACTION_ITEM_CREATE = 'action_item:create',
ACTION_ITEM_ASSIGN = 'action_item:assign',
ACTION_ITEM_DELETE = 'action_item:delete',
TEAM_VIEW = 'team:view',
TEAM_MANAGE = 'team:manage',
TEAM_INVITE = 'team:invite',
TEAM_REMOVE = 'team:remove',
SETTINGS_VIEW = 'settings:view',
SETTINGS_MANAGE = 'settings:manage',
INTEGRATIONS_MANAGE = 'integrations:manage',
BILLING_VIEW = 'billing:view',
BILLING_MANAGE = 'billing:manage',
ADMIN_FULL = 'admin:*',
AUDIT_VIEW = 'audit:view',
COMPLIANCE_MANAGE = 'compliance:manage',
}
export interface Role {
name: string;
description: string;
permissions: Permission[];
inherits?: string[];
}
export const predefinedRoles: Record<string, Role> = {
viewer: {
name: 'Viewer',
description: 'Can view own transcripts and summaries',
permissions: [
Permission.TRANSCRIPT_READ,
Permission.SUMMARY_READ,
],
},
member: {
name: 'Member',
description: 'Standard team member with create access',
permissions: [
Permission.TRANSCRIPT_CREATE,
Permission.TRANSCRIPT_READ,
Permission.TRANSCRIPT_DELETE,
Permission.SUMMARY_GENERATE,
Permission.SUMMARY_READ,
Permission.ACTION_ITEM_CREATE,
],
inherits: ['viewer'],
},
manager: {
name: 'Manager',
description: 'Can manage team transcripts and members',
permissions: [
Permission.TRANSCRIPT_READ_ALL,
Permission.TRANSCRIPT_DELETE_ALL,
Permission.ACTION_ITEM_ASSIGN,
Permission.ACTION_ITEM_DELETE,
Permission.TEAM_VIEW,
Permission.TEAM_INVITE,
],
inherits: ['member'],
},
admin: {
name: 'Admin',
description: 'Full organizational admin access',
permissions: [
Permission.TEAM_MANAGE,
Permission.TEAM_REMOVE,
Permission.SETTINGS_VIEW,
Permission.SETTINGS_MANAGE,
Permission.INTEGRATIONS_MANAGE,
Permission.BILLING_VIEW,
Permission.AUDIT_VIEW,
],
inherits: ['manager'],
},
owner: {
name: 'Owner',
description: 'Organization owner with full access',
permissions: [
Permission.ADMIN_FULL,
Permission.BILLING_MANAGE,
Permission.COMPLIANCE_MANAGE,
],
inherits: ['admin'],
},
};
export function resolvePermissions(roleName: string): Permission[] {
const role = predefinedRoles[roleName];
if (!role) return [];
const permissions = new Set<Permission>(role.permissions);
for (const inheritedRole of role.inherits || []) {
const inheritedPermissions = resolvePermissions(inheritedRole);
inheritedPermissions.forEach(p => permissions.add(p));
}
return Array.from(permissions);
}
Step 2: Implement Permission Checking
import { Permission, resolvePermissions } from './roles';
export interface User {
id: string;
email: string;
organizationId: string;
role: string;
customPermissions?: Permission[];
deniedPermissions?: Permission[];
}
export class AuthorizationService {
hasPermission(user: User, permission: Permission): boolean {
const userPermissions = this.getUserPermissions(user);
if (userPermissions.includes(Permission.ADMIN_FULL)) {
return true;
}
if (user.deniedPermissions?.includes(permission)) {
return false;
}
return userPermissions.(permission) ||
.(permission, userPermissions);
}
(: , : []): {
permissions.( .(user, p));
}
(: , : []): {
permissions.( .(user, p));
}
(: ): [] {
rolePermissions = (user.);
customPermissions = user. || [];
[... ([...rolePermissions, ...customPermissions])];
}
(: , : []): {
[resource] = permission.();
wildcardPermission = ;
userPermissions.(wildcardPermission);
}
}
() {
authService = ();
{
user = req. ;
(!user) {
res.().({ : });
}
(!authService.(user, permissions)) {
res.().({
: ,
: permissions,
: user.,
});
}
();
};
}
(): {
authService = ();
(authService.(user, .)) {
;
}
(transcript. === user.) {
authService.(user, .);
}
(transcript.?.( p. === user.)) {
authService.(user, .);
}
;
}
Step 3: Configure SSO/SAML Integration
import { Strategy as SamlStrategy } from 'passport-saml';
import passport from 'passport';
export interface SSOConfig {
provider: 'okta' | 'azure' | 'google' | 'onelogin';
entryPoint: string;
issuer: string;
cert: string;
callbackUrl: string;
signatureAlgorithm?: string;
identifierFormat?: string;
attributeMapping: {
email: string;
firstName: string;
lastName: string;
groups?: string;
};
groupRoleMapping?: Record<string, string>;
}
export function configureSAML(: ): {
samlStrategy = (
{
: config.,
: config.,
: config.,
: config.,
: config. || ,
: config. || ,
},
(profile, done) => {
{
email = profile[config..];
firstName = profile[config..];
lastName = profile[config..];
groups = profile[config.. || ] || [];
role = ;
(config.) {
( [group, mappedRole] .(config.)) {
(groups.(group)) {
role = mappedRole;
;
}
}
}
user = ({
email,
firstName,
lastName,
role,
: ,
: profile.,
});
(, user);
} (error) {
(error );
}
}
);
passport.(, samlStrategy);
}
: = {
: ,
: process..!,
: process..!,
: process..!,
: ,
: {
: ,
: ,
: ,
: ,
},
: {
: ,
: ,
: ,
: ,
},
};
Step 4: Team Management
export interface Team {
id: string;
name: string;
organizationId: string;
members: TeamMember[];
settings: TeamSettings;
}
export interface TeamMember {
userId: string;
email: string;
role: string;
joinedAt: Date;
invitedBy: string;
}
export interface TeamSettings {
defaultTranscriptVisibility: 'private' | 'team' | 'organization';
allowExternalSharing: boolean;
requireApprovalForSharing: boolean;
autoTranscribe: boolean;
}
export class TeamManager {
private client = getTwinMindClient();
private authService = new AuthorizationService();
async createTeam(name: string, : ): <> {
response = ..(, {
name,
: {
: ,
: ,
: ,
: ,
},
});
.(response.., creatorId, );
response.;
}
(
: ,
: ,
: ,
?:
): <> {
..(, {
: userId,
role,
: invitedBy,
});
.(teamId);
}
(: , : ): <> {
..();
.(teamId);
}
(: , : , : ): <> {
..(, {
: newRole,
});
}
(: ): <[]> {
response = ..();
response.;
}
(
: ,
: ,
: ,
:
): <> {
(!..(invitedBy, .)) {
();
}
..(, {
email,
role,
: invitedBy.,
});
(email, teamId, invitedBy);
}
(: ): <> {
members = .(teamId);
..(, {
: members.( ({
: m.,
: m.,
})),
});
}
}
Step 5: Audit Logging for Access
export interface AccessAuditEvent {
timestamp: Date;
userId: string;
userEmail: string;
action: string;
resource: string;
resourceId?: string;
granted: boolean;
reason?: string;
ipAddress?: string;
userAgent?: string;
metadata?: Record<string, any>;
}
export class AccessAuditLogger {
async logAccess(event: Omit<AccessAuditEvent, 'timestamp'>): Promise<void> {
const fullEvent: AccessAuditEvent = {
...event,
timestamp: new Date(),
};
await db.accessAuditLogs.create(fullEvent);
if (process.env.) {
.(fullEvent);
}
(!event.) {
logger.(, {
: event.,
: event.,
: event.,
: event.,
});
}
}
(: {
?: ;
?: ;
?: ;
?: ;
?: ;
?: ;
?: ;
}): <[]> {
db..({
...filters,
: {
: filters.,
: filters.,
},
}).(filters. || );
}
(
: ,
: { : ; : }
): <{
: ;
: ;
: [];
: ;
}> {
logs = .({
userId,
: dateRange.,
: dateRange.,
});
resourcesAccessed = logs
.( l.)
.( l.);
{
: logs.( l.).,
: logs.( !l.).,
resourcesAccessed,
: (resourcesAccessed).,
};
}
(: ): <> {
(process..!, {
: ,
: { : },
: .({
: ,
: ,
...event,
}),
});
}
}
() {
(: , : , : ) => {
originalSend = res.;
user = req. ;
res. = () {
granted = res. < ;
auditLogger.({
: user?. || ,
: user?. || ,
: ,
: req..()[] || ,
: req..,
granted,
: !granted ? body?. : ,
: req.,
: req.[],
});
originalSend.(, body);
};
();
};
}
Output
- Role and permission definitions
- Permission checking service
- SSO/SAML configuration
- Team management functionality
- Access audit logging
Role Hierarchy
Owner
└── Admin
└── Manager
└── Member
└── Viewer
Enterprise Features
| Feature | Description | Configuration |
|---|
| SSO/SAML | Single sign-on integration | IdP configuration |
| SCIM | User provisioning | Automatic sync |
| Custom roles | Define organization roles | Role builder |
| Audit logs | Access tracking | 90-day retention |
| IP allowlisting | Restrict access by IP | Network settings |
Error Handling
| Issue | Cause | Solution |
|---|
| SSO login failed | Certificate mismatch | Update IdP cert |
| Role not syncing | SCIM misconfigured | Check provisioning |
| Permission denied | Wrong role assigned | Review role mapping |
| Audit gaps | Middleware not applied | Add to all routes |
Resources
Next Steps
For migration from other tools, see twinmind-migration-deep-dive.