Authentication & RBAC
Terra uses WorkOS AuthKit for authentication and implements a fail-secure role-based access control (RBAC) system.Architecture Overview
| Component | Responsibility |
|---|---|
| WorkOS | Authentication (SSO, MFA, social login) |
| Terra Session | Encrypted JWT cookie with user + role |
| Supabase | Role storage and authorization policies |
User Roles
Terra supports four user roles:| Role | Access Level | Default Routes |
|---|---|---|
super_admin | Full system access | / (Dashboard) |
admin | Program administration | / (Dashboard) |
user | Applicant (legacy alias) | /portal |
applicant | Applicant portal only | /portal |
user and applicant are functionally equivalent. New accounts default to applicant.Fail-Secure Design
Terra implements a “deny by default” security model:Route Protection
The middleware (src/middleware.ts) enforces access control:
Admin Routes (Require admin or super_admin)
/- Dashboard/applications- Submission management/workflows- Workflow configuration/settings- System settings/intake- Intake management/forms- Form builder
Portal Routes (Any authenticated user)
/portal- Applicant dashboard/portal/application/*- Individual applications
Public Routes (No authentication)
/f/[slug]- Public form pages/p/[slug]- Public program landing pages/login- Authentication page
Deep Linking
Terra preserves intended destinations through the OAuth flow using the state parameter.How It Works
- User visits protected route (e.g.,
/forms/abc123/edit) - Middleware redirects to login with
?next=/forms/abc123/edit - Login page encodes the path into OAuth state
- After authentication, callback extracts and redirects to original destination
Implementation
Security
The return path is validated to prevent open redirects:Session Management
Sessions are stored in encrypted JWT cookies:Logout
Proper logout terminates both the local session and the WorkOS SSO session:Database Schema
Theusers table stores role information:
Promoting a User to Admin
Debugging
Terra includes a debug endpoint for troubleshooting authentication issues:Common Issues
User stuck on /portal after login
User stuck on /portal after login
The user’s role in the database is Then have the user log out and back in to get a new session with the updated role.
applicant or user. To grant admin access:Auto-login loop after logout
Auto-login loop after logout
The WorkOS session wasn’t terminated. Ensure logout uses
getLogoutUrl(sessionId):Deep link not working
Deep link not working
Check that:
- The
nextparameter is being passed to the login page - The OAuth state is being encoded/decoded correctly
- The return path passes validation (starts with
/, no protocols)
Role shows as 'undefined' in logs
Role shows as 'undefined' in logs
The user doesn’t exist in the
users table, or their workos_id doesn’t match. The system will:- Create a new user with
applicantrole - Store their WorkOS ID for future lookups
Next: Public Landing Pages
Learn how to create public program landing pages.