ADR 003: User Registration and Authentication
ADR-003: User Registration and Authentication
Status: Accepted Date: 2025-11-23 Decision Makers: Hal Casteel (Founder/CEO/CTO) Stakeholders: Engineering, Security, Product Supersedes: None Related: ADR-002 (Hybrid Deployment Architecture)
Context
CODITECT requires a robust user identity and authentication system to support:
- Cloud-based registration - Users sign up via web portal or CLI
- Local engine authentication - Secure access to cloud services
- Multi-tier access - Free, Pro, Team, Enterprise with different auth flows
- Enterprise SSO - SAML, OAuth, Azure AD, Okta integration
- API security - JWT tokens for REST API access
- Account management - Password reset, email verification, MFA
Key Requirements
- Industry-standard security (OWASP Top 10 compliance)
- Scalable authentication (100K+ users)
- Fast validation (<100ms for token verification)
- Multi-device support
- Offline mode support (cached authentication)
- Enterprise SSO integration
- GDPR/SOC2 compliance
Decision
CODITECT will use a MULTI-LAYERED AUTHENTICATION SYSTEM with Firebase Auth as the primary identity provider, supplemented by custom JWT tokens and enterprise SSO.
Authentication Architecture
┌─────────────────────────────────────────────────────────────┐
│ AUTHENTICATION LAYERS │
└─────────────────────────────────────────────────────────────┘
Layer 1: Primary Authentication (Firebase Auth)
├─ Email/Password
├─ Social OAuth (Google, GitHub, Microsoft)
├─ Magic Links (passwordless)
└─ Phone/SMS (optional MFA)
Layer 2: License Validation (Custom)
├─ License key verification
├─ Subscription tier check
├─ Quota enforcement
└─ Feature flags
Layer 3: API Access (JWT Tokens)
├─ Short-lived access tokens (1 hour)
├─ Refresh tokens (30 days)
├─ Scope-based permissions
└─ Rate limiting by user/tier
Layer 4: Enterprise SSO (Custom Integration)
├─ SAML 2.0 (Okta, OneLogin)
├─ OAuth 2.0 / OIDC (Azure AD, Google Workspace)
├─ LDAP/Active Directory (on-premise)
└─ Just-In-Time (JIT) provisioning
User Registration Flows
1. Standard Registration (Free/Pro/Team Tiers)
Web Portal Flow
User Journey:
1. User visits https://coditect.ai/signup
2. Enters email + password (or social OAuth)
3. Email verification sent
4. User clicks verification link
5. Account activated → Free tier
6. Optional: Subscribe to Pro/Team
7. License key generated and displayed
8. User copies license key
Technical Flow:
POST /api/v1/auth/register
{
"email": "user@example.com",
"password": "SecurePass123!",
"name": "Jane Developer"
}
Response:
{
"user_id": "usr_7f3e9d2c4b1",
"email": "user@example.com",
"email_verified": false,
"tier": "FREE",
"verification_email_sent": true
}
Email Verification:
GET /api/v1/auth/verify-email?token=eyJhbGci...
Post-Verification:
{
"user_id": "usr_7f3e9d2c4b1",
"email_verified": true,
"license_key": "CODITECT-FREE-A7F3E9D2C4B1-8F2A",
"tier": "FREE"
}
CLI Registration Flow
$ coditect register
📧 Email: user@example.com
🔒 Password: ********
👤 Name: Jane Developer
✅ Registration successful!
📬 Verification email sent to user@example.com
⏳ Waiting for email verification... (Click link in email)
✅ Email verified!
🎉 Welcome to CODITECT!
Your license key: CODITECT-FREE-A7F3E9D2C4B1-8F2A
(Saved to ~/.coditect/license.key)
🚀 Run 'coditect init' to start your first project!
2. Social OAuth Registration (Faster Onboarding)
Supported Providers
- Google (recommended for developers)
- GitHub (developer-friendly)
- Microsoft (enterprise users)
OAuth Flow
1. User clicks "Sign up with Google"
├─ Redirect to https://accounts.google.com/oauth
└─ Scopes: email, profile
2. User authorizes
└─ Redirect back to https://coditect.ai/auth/callback?code=...
3. Backend exchanges code for tokens
POST https://oauth2.googleapis.com/token
└─ Receives: access_token, id_token (JWT with email)
4. Create CODITECT user
├─ Extract email from id_token
├─ Auto-verify email (trusted OAuth provider)
├─ Generate license key
└─ Create user record
5. User logged in
└─ No email verification needed (OAuth provider verified)
Benefits
- ✅ Faster registration (no password needed)
- ✅ Auto-verified email
- ✅ Familiar user experience
- ✅ No password to manage
3. Enterprise SSO Registration (Team/Enterprise Tiers)
SAML 2.0 Flow
1. Admin configures SSO in CODITECT Admin Portal
├─ Company: Acme Corp
├─ Identity Provider: Okta
├─ SAML Metadata URL: https://acme.okta.com/metadata
├─ Domain: @acme.com
└─ JIT Provisioning: Enabled
2. Employee visits https://coditect.ai/login
├─ Enters email: alice@acme.com
└─ CODITECT detects @acme.com → SSO required
3. Redirect to Okta
GET https://acme.okta.com/saml/login?SAMLRequest=...
4. Employee authenticates with Okta
└─ Okta redirects back with SAML assertion
5. CODITECT validates SAML assertion
├─ Verify signature (Okta's public key)
├─ Extract user attributes (email, name, groups)
└─ JIT provision user if not exists:
├─ Create user record
├─ Assign to organization (Acme Corp)
├─ Assign role based on SAML groups
└─ Generate license key (enterprise)
6. User logged in
└─ Access granted based on organization license
SAML Attributes Mapping
<saml:Attribute Name="email">
<saml:AttributeValue>alice@acme.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="firstName">
<saml:AttributeValue>Alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="lastName">
<saml:AttributeValue>Smith</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="groups">
<saml:AttributeValue>Engineering</saml:AttributeValue>
<saml:AttributeValue>Admins</saml:AttributeValue>
</saml:Attribute>
Role Mapping
saml_role_mapping:
Admins: organization_admin
Engineering: developer
Managers: team_lead
default: member
Authentication Flows
1. Email/Password Authentication
Login Flow
POST /api/v1/auth/login
{
"email": "user@example.com",
"password": "SecurePass123!"
}
Backend Process:
1. Look up user by email
2. Verify password (bcrypt hash comparison)
3. Check email verification status
4. Check account status (active, suspended, deleted)
5. Generate JWT access token (1 hour expiry)
6. Generate refresh token (30 days expiry)
7. Log login event (IP, device, timestamp)
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "rt_a7f3e9d2c4b1f8e2...",
"token_type": "Bearer",
"expires_in": 3600,
"user": {
"user_id": "usr_7f3e9d2c4b1",
"email": "user@example.com",
"name": "Jane Developer",
"tier": "PRO",
"license_key": "CODITECT-PRO-A7F3E9D2C4B1-8F2A"
}
}
JWT Token Structure (Access Token)
{
"header": {
"alg": "RS256",
"typ": "JWT",
"kid": "coditect_key_1"
},
"payload": {
"iss": "https://auth.coditect.ai",
"sub": "usr_7f3e9d2c4b1",
"aud": "https://api.coditect.ai",
"exp": 1700000000,
"iat": 1699996400,
"email": "user@example.com",
"tier": "PRO",
"license_key": "CODITECT-PRO-A7F3E9D2C4B1-8F2A",
"scopes": ["commands:execute", "sync:read", "sync:write"],
"org_id": null
},
"signature": "..."
}
CLI Login Flow
$ coditect login
Choose login method:
1. Email/Password
2. Google
3. GitHub
4. SSO (Enterprise)
Selection: 1
📧 Email: user@example.com
🔒 Password: ********
✅ Login successful!
👤 Logged in as: Jane Developer (PRO tier)
🔑 License: CODITECT-PRO-A7F3E9D2C4B1-8F2A
Tokens saved to ~/.coditect/auth.json
2. Token Refresh Flow
When Access Token Expires
POST /api/v1/auth/refresh
{
"refresh_token": "rt_a7f3e9d2c4b1f8e2..."
}
Backend Process:
1. Validate refresh token
├─ Check signature
├─ Check expiration (30 days)
└─ Check revocation list
2. Look up user and verify account status
3. Generate new access token (1 hour)
4. Optionally rotate refresh token
└─ Generate new refresh token
└─ Invalidate old refresh token
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "rt_b8g4f0e3d5c2g9f3...",
"token_type": "Bearer",
"expires_in": 3600
}
Automatic Refresh (Local Engine)
class AuthManager:
def get_valid_token(self):
"""
Get valid access token, refreshing if expired.
"""
token = self.load_access_token()
if self.is_token_expired(token):
# Refresh token
refresh_token = self.load_refresh_token()
new_tokens = self.refresh_tokens(refresh_token)
self.save_tokens(new_tokens)
return new_tokens['access_token']
return token
3. Local Engine Authentication
First-Time Setup
$ coditect login
🌐 Opening browser for authentication...
(Opens: https://coditect.ai/cli-login?device=macos&version=1.0.0)
Browser Flow:
1. User logs in (email/password or OAuth)
2. User authorizes CLI access
3. Browser shows: "✅ Authentication successful! Return to CLI."
4. Browser sends auth code to CLI via localhost redirect
http://localhost:8787/callback?code=auth_abc123
CLI receives code:
POST /api/v1/auth/device-token
{
"auth_code": "auth_abc123",
"device_id": "mac_a7f3e9d2c4b1",
"device_name": "Jane's MacBook Pro"
}
Response:
{
"access_token": "eyJ...",
"refresh_token": "rt_...",
"license_key": "CODITECT-PRO-A7F3E9D2C4B1-8F2A"
}
Saved to ~/.coditect/auth.json:
{
"user_id": "usr_7f3e9d2c4b1",
"email": "user@example.com",
"access_token": "eyJ...",
"refresh_token": "rt_...",
"license_key": "CODITECT-PRO-A7F3E9D2C4B1-8F2A",
"cached_at": "2025-11-23T10:00:00Z"
}
Subsequent Startups
# On every CLI startup
def startup():
auth = load_auth_from_disk() # ~/.coditect/auth.json
if auth is None:
print("❌ Not logged in. Run 'coditect login'")
exit(1)
# Validate cached auth (24 hour cache)
if is_recent(auth['cached_at'], hours=24):
# Use cached validation
return enable_features(auth['tier'])
# Re-validate with cloud (once per day)
try:
validation = validate_license(auth['license_key'])
update_cache(validation)
return enable_features(validation['tier'])
except NetworkError:
# Offline mode: Use cached auth (7 day grace period)
if is_recent(auth['cached_at'], days=7):
print("⚠️ Offline mode: Using cached license")
return enable_features(auth['tier'])
else:
print("❌ License validation required (grace period expired)")
exit(1)
Password Security
Password Requirements
Minimum Standards
- Length: 12+ characters
- Complexity: 1 uppercase, 1 lowercase, 1 digit, 1 special char
- Not in common password lists (10M most common)
- Not same as email prefix
- Not reused from previous 5 passwords
Password Hashing
# bcrypt with 12 rounds
import bcrypt
def hash_password(password: str) -> str:
salt = bcrypt.gensalt(rounds=12)
return bcrypt.hashpw(password.encode(), salt).decode()
def verify_password(password: str, hashed: str) -> bool:
return bcrypt.checkpw(password.encode(), hashed.encode())
Password Reset Flow
1. User requests password reset
POST /api/v1/auth/request-password-reset
{ "email": "user@example.com" }
2. Backend generates reset token
├─ Create secure random token (32 bytes)
├─ Hash token (SHA-256)
├─ Store hash in database with 1-hour expiry
└─ Send email with reset link
3. Email sent:
Subject: Reset your CODITECT password
Link: https://coditect.ai/reset-password?token=abc123
4. User clicks link, enters new password
POST /api/v1/auth/reset-password
{
"token": "abc123",
"new_password": "NewSecurePass456!"
}
5. Backend validates token and updates password
├─ Hash submitted token → lookup in database
├─ Check expiry (< 1 hour old)
├─ Validate new password meets requirements
├─ Hash new password (bcrypt)
├─ Update user password
├─ Invalidate reset token
└─ Invalidate all existing sessions (force re-login)
6. Confirmation email sent
"Your CODITECT password was changed"
Multi-Factor Authentication (MFA)
TOTP (Time-Based One-Time Password)
Enrollment Flow
1. User enables MFA in account settings
POST /api/v1/auth/mfa/enroll
2. Backend generates TOTP secret
import pyotp
secret = pyotp.random_base32()
3. Response includes QR code
{
"secret": "JBSWY3DPEHPK3PXP",
"qr_code": "data:image/png;base64,iVBORw0KGgo...",
"backup_codes": [
"a7f3-e9d2-c4b1",
"8f2a-3d5c-7e1b",
...
]
}
4. User scans QR code with authenticator app
(Google Authenticator, Authy, 1Password)
5. User enters verification code
POST /api/v1/auth/mfa/verify
{
"code": "123456"
}
6. Backend validates code
totp = pyotp.TOTP(secret)
is_valid = totp.verify(code, valid_window=1)
7. MFA enabled
├─ Store encrypted secret in database
├─ Store backup codes (hashed)
└─ User receives confirmation
Login with MFA
1. User enters email/password
POST /api/v1/auth/login
{ "email": "...", "password": "..." }
2. Backend detects MFA enabled
{
"mfa_required": true,
"mfa_token": "temp_mfa_7f3e9d2c4b1"
}
3. User enters TOTP code or backup code
POST /api/v1/auth/mfa/challenge
{
"mfa_token": "temp_mfa_7f3e9d2c4b1",
"code": "123456"
}
4. Backend validates code
└─ If valid: Issue access/refresh tokens
└─ If invalid: Reject (rate limit after 5 failures)
5. User logged in
Session Management
Session Storage
Database Schema
CREATE TABLE user_sessions (
session_id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64) NOT NULL,
refresh_token_hash VARCHAR(256) NOT NULL,
device_id VARCHAR(256),
device_name VARCHAR(256),
ip_address INET,
user_agent TEXT,
created_at TIMESTAMP DEFAULT NOW(),
last_used_at TIMESTAMP DEFAULT NOW(),
expires_at TIMESTAMP NOT NULL,
revoked BOOLEAN DEFAULT FALSE,
revoked_at TIMESTAMP,
revoked_reason VARCHAR(256),
INDEX idx_user_sessions (user_id, revoked),
INDEX idx_expires_at (expires_at)
);
Session Lifecycle
Creation
- On login: Create session with 30-day expiry
- Store refresh token (hashed)
- Track device info (for "Active Sessions" list)
Usage
- On token refresh: Update last_used_at
- Extend expiry (sliding window)
Revocation
- On logout: Mark session as revoked
- On password change: Revoke all sessions
- On security event: Revoke compromised sessions
- Admin action: Revoke user's sessions
Cleanup
- Cron job: Delete expired sessions (>30 days old)
- Retention: Keep revoked sessions for 90 days (audit trail)
API Authentication
REST API Endpoints
Protected Endpoint Example
from fastapi import Depends, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
security = HTTPBearer()
async def get_current_user(
credentials: HTTPAuthorizationCredentials = Depends(security)
):
"""
Dependency to validate JWT and extract user.
"""
token = credentials.credentials
# Validate JWT
try:
payload = jwt.decode(
token,
PUBLIC_KEY,
algorithms=["RS256"],
audience="https://api.coditect.ai"
)
except jwt.ExpiredSignatureError:
raise HTTPException(401, "Token expired")
except jwt.InvalidTokenError:
raise HTTPException(401, "Invalid token")
# Extract user info
user_id = payload['sub']
tier = payload['tier']
scopes = payload['scopes']
return {
'user_id': user_id,
'tier': tier,
'scopes': scopes
}
@app.post("/api/v1/commands/execute")
async def execute_command(
request: CommandRequest,
user: dict = Depends(get_current_user)
):
"""
Execute command (requires authentication).
"""
# Check scope
if "commands:execute" not in user['scopes']:
raise HTTPException(403, "Insufficient permissions")
# Check quota (based on tier)
quota = get_quota(user['tier'])
if not check_quota(user['user_id'], quota):
raise HTTPException(429, "Quota exceeded")
# Execute command
result = await execute_slash_command(request.command, request.args)
return result
Authorization Header
POST /api/v1/commands/execute HTTP/1.1
Host: api.coditect.ai
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
"command": "/analyze",
"args": {"target": "src/main.rs"}
}
Security Best Practices
OWASP Top 10 Compliance
A01: Broken Access Control
- ✅ JWT validation on every API request
- ✅ Scope-based permissions
- ✅ Multi-tenant isolation (organization_id checks)
A02: Cryptographic Failures
- ✅ HTTPS only (TLS 1.3)
- ✅ bcrypt password hashing (12 rounds)
- ✅ JWT signed with RS256 (RSA keys)
- ✅ Secrets encrypted at rest (GCP KMS)
A03: Injection
- ✅ Parameterized SQL queries
- ✅ Input validation (Pydantic)
- ✅ Output encoding
A04: Insecure Design
- ✅ Rate limiting (per user, per IP)
- ✅ Account lockout (5 failed logins)
- ✅ Session fixation protection
- ✅ CSRF tokens for web forms
A05: Security Misconfiguration
- ✅ Secure defaults
- ✅ Minimal error details in production
- ✅ Security headers (HSTS, CSP, X-Frame-Options)
A06: Vulnerable Components
- ✅ Dependency scanning (Dependabot)
- ✅ Regular updates
- ✅ SCA (Software Composition Analysis)
A07: Authentication Failures
- ✅ Strong password policy
- ✅ MFA support
- ✅ Rate limiting on auth endpoints
- ✅ No default credentials
A08: Data Integrity Failures
- ✅ JWT signature validation
- ✅ HTTPS (TLS)
- ✅ Subresource Integrity (SRI)
A09: Logging Failures
- ✅ Audit logging (auth events)
- ✅ Failed login attempts logged
- ✅ Sensitive data redacted from logs
A10: SSRF
- ✅ URL validation
- ✅ Allowlist for external requests
- ✅ No user-controlled URLs
Implementation Checklist
Phase 1: Core Authentication (Week 1)
- Firebase Auth setup
- User registration API
- Email verification flow
- Login API (email/password)
- JWT generation and validation
- Refresh token flow
- Password reset flow
Phase 2: OAuth & Social Login (Week 2)
- Google OAuth integration
- GitHub OAuth integration
- Microsoft OAuth integration
- Social account linking
Phase 3: Local Engine Integration (Week 3)
- CLI login flow (browser-based)
- Token storage (~/.CODITECT/auth.json)
- Automatic token refresh
- Offline mode with grace period
Phase 4: Enterprise SSO (Week 4)
- SAML 2.0 integration
- OAuth 2.0/OIDC integration
- JIT provisioning
- Role mapping
- Admin portal for SSO configuration
Phase 5: Security Hardening (Week 5)
- MFA (TOTP) enrollment
- MFA login flow
- Session management
- Rate limiting
- Account lockout
- Security audit logging
Success Metrics
Security Metrics
- Password breach rate: <0.01% (strong password requirements)
- Account takeover rate: <0.001% (MFA, rate limiting)
- Invalid login attempts blocked: >99%
- Token validation latency: <10ms (p95)
User Experience Metrics
- Registration completion rate: >80%
- Email verification rate: >90% (within 24 hours)
- Social OAuth adoption: >60% (faster registration)
- MFA adoption (Pro+ users): >30%
Technical Metrics
- Auth API availability: 99.9%
- Auth API latency: <100ms (p95)
- Token refresh success rate: >99.9%
- Offline mode reliability: 100% (7-day grace period)
References
Standards
- OAuth 2.0: RFC 6749
- JWT: RFC 7519
- SAML 2.0: OASIS Standard
- TOTP: RFC 6238
Libraries
- Firebase Auth (identity provider)
- PyJWT (JWT handling)
- bcrypt (password hashing)
- Python-saml (SAML integration)
- pyotp (TOTP generation)
Related ADRs
- ADR-002: Hybrid Deployment Architecture
- ADR-004: Licensing and Entitlement System
- ADR-005: Multi-Tenancy Strategy
Author: Hal Casteel, Founder/CEO/CTO, AZ1.AI INC Approved By: Hal Casteel Date: 2025-11-23