Multi-tenant RBAC system with Row Level Security (RLS) and GraphQL API.
Permiso implements multi-tenant isolation using PostgreSQL Row Level Security. Each organization's data is isolated at the database level, with two database users:
rls_db_user: For organization-scoped operations (automatically filtered by RLS policies)unrestricted_db_user: For cross-organization operations (organization management, cross-org queries)
docker run -p 5001:5001 \
-e PERMISO_DB_HOST=host.docker.internal \
-e PERMISO_DB_NAME=permiso \
-e RLS_DB_USER=rls_db_user \
-e RLS_DB_USER_PASSWORD=your_rls_password \
-e UNRESTRICTED_DB_USER=unrestricted_db_user \
-e UNRESTRICTED_DB_USER_PASSWORD=your_admin_password \
-e PERMISO_AUTO_MIGRATE=true \
ghcr.io/codespin-ai/permiso:latest# Clone and build
git clone https://github.com/codespin-ai/permiso.git
cd permiso
./scripts/install-deps.sh # Optional - build.sh does this automatically
./scripts/build.sh
# Start PostgreSQL (from devenv directory)
cd devenv && ./run.sh up && cd ..
# Configure database users
export RLS_DB_USER=rls_db_user
export RLS_DB_USER_PASSWORD=changeme_rls
export UNRESTRICTED_DB_USER=unrestricted_db_user
export UNRESTRICTED_DB_USER_PASSWORD=changeme_admin
export PERMISO_DB_HOST=localhost
export PERMISO_DB_NAME=permiso
# Run migrations
cd node/packages/permiso-server
npm run migrate:permiso:latest
# Start server
cd ../../.. && ./scripts/start.sh- Organizations: Top-level tenants (no RLS, globally accessible)
- Users: Identity provider integration (RLS-protected)
- Roles: Named permission sets (RLS-protected)
- Resources: Path-like identifiers supporting wildcards (RLS-protected)
- Permissions: User/role to resource+action mappings (RLS-protected)
- Properties: JSON metadata on all entities
- With
x-org-idheader: Operations scoped to that organization (RLS enforced) - Without
x-org-idheader: ROOT context for cross-org operations
import { createUser, grantUserPermission } from "@codespin/permiso-client";
const config = {
endpoint: "http://localhost:5001",
orgId: "acme-corp", // Optional - omit for ROOT operations
};
await createUser(config, {
id: "user-123",
identityProvider: "auth0",
identityProviderUserId: "auth0|123",
});mutation {
createUser(
input: {
id: "user-123"
identityProvider: "auth0"
identityProviderUserId: "auth0|123"
}
) {
id
orgId
}
}./scripts/install-deps.sh # Install dependencies for all packages
./scripts/install-deps.sh --force # Force reinstall all dependencies
./scripts/build.sh # Build all packages (includes dependency installation)
./scripts/build.sh --install # Build with forced dependency reinstall
./scripts/lint-all.sh # Run ESLint
./scripts/format-all.sh # Format with Prettier, called automatically during build
npm test # Run all tests
npm run test:grep -- "pattern" # Search tests/node/packages/
permiso-core/ # Shared types and utilities
permiso-db/ # Database layer with RLS wrapper
permiso-server/ # GraphQL server
permiso-client/ # TypeScript client library
permiso-integration-tests/ # Integration tests
database/permiso/migrations/- Database schema and RLS policiesnode/packages/permiso-server/src/schema.graphql- GraphQL schemanode/packages/permiso-server/src/domain/- Business logicnode/packages/permiso-db/src/rls-wrapper.ts- RLS enforcement
# Database connection
PERMISO_DB_HOST=localhost
PERMISO_DB_PORT=5432
PERMISO_DB_NAME=permiso
# Database users (required)
RLS_DB_USER=rls_db_user
RLS_DB_USER_PASSWORD=password
UNRESTRICTED_DB_USER=unrestricted_db_user
UNRESTRICTED_DB_USER_PASSWORD=password
# Server
PERMISO_SERVER_PORT=5001
# Optional Bearer authentication
PERMISO_API_KEY=your-secret-token-- Create RLS user for org-scoped operations
CREATE USER rls_db_user WITH PASSWORD 'changeme_rls';
GRANT CONNECT ON DATABASE permiso TO rls_db_user;
GRANT USAGE ON SCHEMA public TO rls_db_user;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO rls_db_user;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO rls_db_user;
-- Create unrestricted user for admin operations
CREATE USER unrestricted_db_user WITH PASSWORD 'changeme_admin';
GRANT CONNECT ON DATABASE permiso TO unrestricted_db_user;
GRANT ALL PRIVILEGES ON DATABASE permiso TO unrestricted_db_user;
-- Bypass RLS for unrestricted user
ALTER USER unrestricted_db_user BYPASSRLS;Permiso can manage permissions for multiple databases. See database.md for configuration.
# Run all tests
npm test
# Search specific tests
npm run test:grep -- "Organizations"
npm run test:integration:grep -- "Users"
npm run test:client:grep -- "Permissions"
# Docker testing
./docker-test.sh- API Reference - GraphQL schema and examples
- Architecture - System design details
- Database - Multi-database configuration
- Configuration - All environment variables
- Deployment - Production deployment guide
- Coding Standards - Development conventions
MIT