Authentication & Access Control
TradeAnon uses Azure AD B2C for secure authentication and role-based access control.
Azure AD B2C Overview
Azure Active Directory B2C (Business to Consumer) provides:
- Secure Authentication: Industry-standard OAuth 2.0 and OpenID Connect
- Multi-Factor Authentication: Optional SMS or authenticator app verification
- Social Login: Sign in with Microsoft, Google, or GitHub accounts
- Password Reset: Self-service password recovery
- Profile Management: Update email, password, and profile information
User Roles
TradeAnon implements role-based access control with four tiers:
Anonymous (Public)
- View public documentation
- Access landing pages and pricing information
- No data access
Authenticated (Free)
- Dark Pool data (30 days)
- Macro indicators (30 days)
- Basic sector rotation
- Community Discord access
Pro
- Full historical data access (10+ years)
- Episodic Pivots scanner
- Webster Power Trend signals
- COT watchlist and backtests
- Portfolio risk analysis
- Real-time scanner
- API access (100 requests/day)
Admin
- All Pro features
- User management
- ETL pipeline controls
- System monitoring
- Analytics dashboard
- Unlimited API access
Login Flow
Web Application
- Navigate to dev.tradeanon.com
- Click Log In
- Enter your email and password
- Complete MFA if enabled
- Redirected to dashboard with access token
API Authentication
API requests require a Bearer token:
# 1. Get access token (via web login or API)
TOKEN="your-access-token"
# 2. Make authenticated request
curl -H "Authorization: Bearer $TOKEN" \
https://api.dev.tradeanon.com/api/b2c/bootstrap
Token Management
Access tokens expire after 1 hour. The frontend automatically refreshes tokens using MSAL.js.
For API access:
- Tokens are JWT (JSON Web Tokens)
- Include
aud(audience) claim for API scope - Include
rolesclaim for access control
Access Control
Page-Level Access
Routes are protected based on user role:
| Route | Required Role |
|---|---|
/ | Anonymous |
/pricing | Anonymous |
/dark-pools | Authenticated |
/ep-trades | Pro |
/webster | Pro |
/admin | Admin |
Feature-Level Access
Individual features check permissions:
// Frontend permission check
import { hasAccess } from '@/lib/permissions';
if (hasAccess(user, 'episodic-pivots')) {
// Show EP scanner
}
API-Level Access
Backend routes validate tokens and roles:
# Backend permission decorator
from api.auth_deps import require_role
@router.get("/ep/candidates")
@require_role(["pro", "enterprise", "admin"])
async def get_ep_candidates():
# Only accessible to Pro+ users
pass
Security Best Practices
For Users
- Use Strong Passwords: Minimum 12 characters with mixed case, numbers, symbols
- Enable MFA: Add authenticator app or SMS verification
- Secure API Keys: Never commit API keys to version control
- Rotate Keys: Generate new API keys every 90 days
- Monitor Sessions: Review active sessions in Settings → Security
For Developers
- Never Hardcode Secrets: Use environment variables or Azure Key Vault
- Validate Tokens: Always verify JWT signature and expiration
- Check Roles: Enforce role-based access on every protected route
- Log Access: Track authentication attempts and authorization failures
- Rate Limiting: Implement rate limits on API endpoints
Troubleshooting
"Unauthorized" Error
Symptom: 401 Unauthorized when accessing protected routes
Solutions:
- Verify you're logged in (check for access token in browser storage)
- Check token expiration (tokens expire after 1 hour)
- Clear browser cache and re-login
- Verify your account has the required role
"Forbidden" Error
Symptom: 403 Forbidden when accessing Pro features
Solutions:
- Verify your subscription tier in Settings → Account
- Contact support to upgrade to Pro
- Check if your trial has expired
Token Refresh Failures
Symptom: Repeatedly logged out or "Session expired" messages
Solutions:
- Clear browser cookies and local storage
- Disable browser extensions that block cookies
- Check if your account is active (not suspended)
- Try incognito/private browsing mode
API Authentication Issues
Symptom: API requests return 401 even with valid token
Solutions:
- Verify token format:
Authorization: Bearer <token> - Check token hasn't expired (decode JWT at jwt.io)
- Ensure token includes correct
audclaim for API - Verify API key is active in Settings → API Keys