Skip to main content

Authentication & Authorization

UniPulse implements a multi-layered auth system with JWT tokens, OAuth providers, OTP verification, and workspace-scoped RBAC.


Authentication Methods

MethodProviderEndpointUse Case
Email + PasswordLocalPOST /api/v1/auth/register, POST /api/v1/auth/loginStandard sign-up/login
Phone + OTPLocalPOST /api/v1/auth/login/phonePhone-based login
Google OAuthPassport.jsGET /api/v1/auth/oauth/googleSocial login
Microsoft OAuthMSALGET /api/v1/auth/oauth/microsoftEnterprise login
OTP VerificationLocalPOST /api/v1/auth/otp/send, POST /api/v1/auth/otp/verifyEmail/phone verification

JWT Token Flow

Token Configuration

TokenSecretLifetimeStorage
Access TokenJWT_SECRETShort-livedMemory / httpOnly cookie
Refresh TokenJWT_REFRESH_SECRETLong-livedhttpOnly cookie

Auth API Endpoints

EndpointMethodDescription
/api/v1/auth/registerPOSTCreate new account
/api/v1/auth/loginPOSTEmail + password login
/api/v1/auth/login/phonePOSTPhone number login
/api/v1/auth/oauth/:providerGETInitiate OAuth flow (google, microsoft)
/api/v1/auth/otp/sendPOSTSend OTP to email/phone
/api/v1/auth/otp/verifyPOSTVerify OTP code
/api/v1/auth/onboardingPOSTComplete onboarding flow
/api/v1/auth/refreshPOSTRefresh access token
/api/v1/auth/logoutPOSTInvalidate refresh token
/api/v1/auth/meGETGet current user profile
/api/v1/auth/change-passwordPOSTChange password (authenticated)
/api/v1/auth/forgot-passwordPOSTRequest password reset email
/api/v1/auth/reset-passwordPOSTReset password with token

RBAC (Role-Based Access Control)

5-Tier Role Hierarchy

RoleManage MembersManage SettingsCreate ContentView AnalyticsView Content
OWNERYesYesYesYesYes
ADMINYesYesYesYesYes
EDITORNoNoYesYesYes
VIEWERNoNoNoYesYes
CLIENTNoNoNoLimitedLimited

Middleware Enforcement

Authorization is enforced at the middleware level using requireWorkspace.ts:

// Route requiring at least EDITOR role
router.post('/posts',
authenticate, // auth.ts: Verify JWT, attach user to req
requireWorkspace('EDITOR'), // requireWorkspace.ts: Load workspace, check role
requireFeature('publishing'), // requireFeature.ts: Check plan feature flag
requireQuota('posts'), // requireQuota.ts: Check usage quota
validate(createPostSchema), // validate.ts: Zod validation
postController.create
);

// Route requiring ADMIN role
router.delete('/members/:memberId',
authenticate,
requireWorkspace('ADMIN'),
workspaceController.removeMember
);

// Route requiring super admin (platform-level)
router.get('/admin/users',
authenticate,
requireSuperAdmin, // requireSuperAdmin.ts: Check isSuperAdmin flag
adminController.listUsers
);

Workspace Isolation (Multi-Tenancy)

All data is scoped to workspaces. The requireWorkspace middleware attaches the current workspace to the request context, and every database query filters by workspaceId.

Key database models with workspace scoping:

ModelScoped By
Post, PostPublication, PostMetricworkspaceId
SocialAccountworkspaceId
Workflow, WorkflowRunworkspaceId
ConversationThread, ConversationMessageworkspaceId
EcommerceStore, CommerceOrderworkspaceId
AudienceNode, AudienceSegmentworkspaceId
Competitor, CompetitorSnapshotworkspaceId
ABTest, EngagementPredictionworkspaceId
WorkspaceUsage, SubscriptionworkspaceId

Feature Flags & Usage Quotas

Feature Flags (requireFeature.ts)

Features are gated by the workspace's subscription plan. The Plan model defines available features through PlanFeature records, and the Feature model lists all gatable features.

// Only allow access if workspace plan includes 'ai_suggestions' feature
router.get('/ai/suggestions',
authenticate,
requireWorkspace('VIEWER'),
requireFeature('ai_suggestions'),
aiController.getSuggestions
);

Usage Quotas (requireQuota.ts)

The WorkspaceUsage model tracks monthly usage. Quotas are defined per plan and enforced before allowing resource-consuming operations.

// Check that workspace hasn't exceeded their monthly AI generation quota
router.post('/ai/caption/generate',
authenticate,
requireWorkspace('EDITOR'),
requireQuota('ai_generations'),
validate(generateCaptionSchema),
aiController.generateCaption
);

Social Platform OAuth

Connecting social accounts (Facebook, Instagram, TikTok) uses OAuth 2.0 flows. Tokens are encrypted at rest using ENCRYPTION_KEY (64-character hex string) and refreshed automatically via the token-refresh queue.

PlatformOAuth TypeCallback URL Env
FacebookOAuth 2.0 (Meta Login)FACEBOOK_APP_ID, FACEBOOK_APP_SECRET
InstagramOAuth 2.0 (via Facebook)INSTAGRAM_CALLBACK_URL
TikTokOAuth 2.0 (Login Kit)TIKTOK_CLIENT_KEY, TIKTOK_CLIENT_SECRET
Security: Token Encryption

Social platform tokens are encrypted before storage using AES-256 with the ENCRYPTION_KEY environment variable. This key must be exactly 64 hexadecimal characters. Never commit this key to version control.


Environment Variables for Auth

VariablePurposeRequired
JWT_SECRETSigns access tokensYes
JWT_REFRESH_SECRETSigns refresh tokensYes
ENCRYPTION_KEYEncrypts social tokens (64 hex chars)Yes
GOOGLE_CLIENT_IDGoogle OAuthFor Google login
MICROSOFT_CLIENT_IDMicrosoft OAuthFor Microsoft login
MICROSOFT_TENANT_IDMicrosoft tenantFor Microsoft login
FACEBOOK_APP_IDFacebook OAuthFor social account connection
FACEBOOK_APP_SECRETFacebook OAuthFor social account connection
TIKTOK_CLIENT_KEYTikTok OAuthFor social account connection
TIKTOK_CLIENT_SECRETTikTok OAuthFor social account connection

Cross-Reference