B2B SaaS Architecture
This guide explains how to design a B2B SaaS application using Optare for identity and access management.
Overview
A typical B2B SaaS application has three user types:
┌─────────────────────────────────────────────────────────────┐
│ Your Application │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Platform │ │ Tenant │ │ End User │ │
│ │ Admin │ │ Admin │ │ │ │
│ ├──────────────┤ ├──────────────┤ ├──────────────┤ │
│ │ Manage all │ │ Manage org │ │ Use product │ │
│ │ tenants │ │ settings │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘Architecture Layers
1. Authentication Layer (Optare)
Optare handles all authentication:
- User login/signup
- Session management
- Token issuance
- MFA/2FA
- SSO integration
2. Authorization Layer (Your App + Optare RBAC)
Combine Optare's RBAC with your business logic:
// Optare provides role from token
const { role, organizationId } = req.user;
// Your app enforces business rules
if (role !== 'admin' && action === 'delete_project') {
throw new UnauthorizedError();
}3. Data Layer (Multi-Tenant)
Always scope data by organization:
// Every query includes organizationId
const projects = await db.projects.findMany({
where: { organizationId: req.user.organizationId }
});The Token-Based Architecture
┌─────────┐ ┌────────────┐ ┌─────────────┐
│ Browser │────►│ Optare ID │────►│ Tokens │
└─────────┘ └────────────┘ └──────┬──────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Your API │
├─────────────────────────────────────────────────────────────┤
│ 1. Validate Access Token │
│ 2. Extract user ID, org ID, role │
│ 3. Scope queries by org │
│ 4. Check permissions │
│ 5. Return data │
└─────────────────────────────────────────────────────────────┘Database Schema Pattern
Organization Ownership
Every table should reference the organization:
CREATE TABLE projects (
id UUID PRIMARY KEY,
organization_id UUID NOT NULL REFERENCES organizations(id),
name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
-- Index for efficient org-scoped queries
CREATE INDEX idx_projects_org ON projects(organization_id);The "Belongs To Org" Pattern
// Base query helper
function orgScoped(orgId: string) {
return { organizationId: orgId };
}
// Usage
const projects = await db.projects.findMany({
where: {
...orgScoped(req.user.organizationId),
status: 'active'
}
});Authentication Flow
1. User Login
User → Your App → Optare ID → Authenticate → Tokens → Your App2. API Request
Frontend → API Request + Access Token → Validate → Process → Response3. Token Refresh
Access Token Expired → SDK uses Refresh Token → New Tokens → ContinueCommon Patterns
Pattern 1: Single Tenant Per Session
User operates in one organization at a time:
// Token contains current org
{
"sub": "user_123",
"org_id": "org_456",
"role": "admin"
}
// Switching orgs requires new token
await client.switchOrganization('org_789');Pattern 2: Org-Aware Routes
Structure your API around organizations:
/api/orgs/:orgId/projects
/api/orgs/:orgId/members
/api/orgs/:orgId/settingsapp.get('/api/orgs/:orgId/projects', async (req, res) => {
// Verify user can access this org
if (req.user.organizationId !== req.params.orgId) {
return res.status(403).json({ error: 'Access denied' });
}
// ...
});Pattern 3: Feature Flags per Org
Different orgs have different features:
const features = await client.license.getEntitlements();
// In component
{features.find(f => f.feature === 'sso')?.isEnabled && (
<SSOSettings />
)}Scaling Considerations
Multi-Region
┌─────────────┐
┌────────►│ US Region │
│ └─────────────┘
┌─────────┴─┐
│ Optare │ ┌─────────────┐
│ ID │──────►│ EU Region │
└─────────┬─┘ └─────────────┘
│ ┌─────────────┐
└────────►│ APAC Region │
└─────────────┘Data Isolation Options
| Level | How | Use Case |
|---|---|---|
| Row-Level | organization_id column | Most SaaS apps |
| Schema-Level | Separate Postgres schemas | Regulated industries |
| Database-Level | Separate databases | Enterprise contracts |
Security Checklist
- All database queries scoped by
organizationId - Access tokens validated on every request
-
issandaudclaims verified - Token expiration checked
- RBAC enforced for sensitive operations
- Audit logs for compliance
- Rate limiting per organization
Next Steps
- Multi-Tenancy - Deep dive on organizations
- RBAC - Role-based access control
- Security Best Practices