Back to Blog

Enterprise Security with nfyio: Teams, RLS, and Zero-Trust Auth

A deep dive into nfyio's multi-tenant team model, row-level security policies, and the zero-trust authentication layer built on Keycloak.

n

nfyio Team

Talya Smart & Technoplatz JV

Enterprise Security — Teams and RLS

nfyio is built around a zero-trust security model from day one. Every access decision is enforced at the database layer with row-level security (RLS) — not application-level filters that can be bypassed.

This post covers:

  • The workspace → project → team hierarchy
  • How RLS policies protect per-workspace data
  • JWT authentication, MFA, and session management
  • Access token scopes and route restrictions

The Multi-tenant Hierarchy

Organization
  └── Workspace (isolated billing, data, RLS domain)
        └── Project
              └── Team (members + roles)

Every object in nfyio — buckets, files, embeddings, agent threads — belongs to a workspace. RLS policies ensure that users in Workspace A can never query data belonging to Workspace B, even if they use a valid JWT.

Row-Level Security Policies

All tables have RLS enabled. Here’s a simplified example of the bucket access policy:

-- Users can only read buckets that belong to their workspace
create policy "workspace_bucket_read"
on public.storage_buckets
for select
to authenticated
using (
  workspace_id in (
    select workspace_id
    from workspace_members
    where user_id = auth.uid()
    and is_active = true
  )
);

nfyio ships with RLS policies for:

  • storage_buckets — access by workspace membership
  • storage_objects — access by bucket permissions
  • embedding_chunks — access by source object permissions
  • agent_threads — access by creator or team member
  • access_tokens — access by owner only
  • billing_transactions — access by workspace owner only

Authentication Architecture

nfyio uses a layered authentication stack:

Request


Rate Limiter (Redis)


CSRF Guard


JWT Verifier (Keycloak JWKS)


Session Decrypter (AES-256-GCM)


Access Token Scope Check


RLS-Enforced DB Query

Every authenticated request must pass all layers.

MFA Enrollment

# Start TOTP enrollment
curl -X POST http://localhost:3000/api/auth/mfa/enroll \
  -H "Authorization: Bearer $YOUR_JWT"

# Response includes QR code URI
{
  "type": "totp",
  "secret": "BASE32SECRETHERE",
  "qrCodeUri": "otpauth://totp/nfyio:user@example.com?secret=...",
  "backupCodes": ["abc123", "def456", ...]
}

After enrollment, every login requires a TOTP code:

curl -X POST http://localhost:3000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "your-password",
    "totpCode": "123456"
  }'

Access Token Scopes

API access tokens are scoped per workspace and route:

curl -X POST http://localhost:3000/api/access-keys \
  -H "Authorization: Bearer $ADMIN_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ci-upload-key",
    "workspaceId": "ws_abc123",
    "scopes": ["storage:write"],
    "allowedRoutes": ["/api/storage/**"],
    "expiresAt": "2026-12-31T23:59:59Z"
  }'

This token can only write to storage endpoints. Attempting to access /api/agents/** returns 403 Forbidden.

Team Roles

RoleStorageEmbeddingsAgentsBillingSettings
OwnerFullFullFullFullFull
ModifierRead/WriteRead/WriteRunViewNone
ViewerReadReadNoneNoneNone

Invite a team member:

curl -X POST http://localhost:3000/api/teams/$TEAM_ID/invite \
  -H "Authorization: Bearer $OWNER_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "colleague@example.com",
    "role": "modifier"
  }'

Audit Logging

Every auth event, role change, and data access is logged:

select
  event_type,
  actor_id,
  target_type,
  target_id,
  ip_address,
  created_at
from public.audit_logs
where workspace_id = $1
order by created_at desc
limit 50;

This gives your security team a full trail of who accessed what and when.

Summary

nfyio’s security model gives you:

  • RLS everywhere — database-level isolation, not application-level
  • Zero-trust JWT — every request verified against Keycloak JWKS
  • AES-256-GCM session encryption — sessions encrypted at rest and in transit
  • MFA with TOTP — backup codes included
  • Fine-grained access tokens — scope to specific routes and operations
  • Full audit logs — exportable per workspace

No additional configuration needed. All of this ships in the default Docker Compose setup.

n

Written by

nfyio Team

Talya Smart & Technoplatz JV

Building the future of web design at Anti-Gravity. Passionate about creating beautiful, accessible experiences.