-
Notifications
You must be signed in to change notification settings - Fork 0
Setting Up Authentication
This guide covers configuring OAuth authentication for TMI with Google, GitHub, and Microsoft identity providers.
TMI uses OAuth 2.0 for authentication with support for:
- Google OAuth - Google accounts and Google Workspace
- GitHub OAuth - GitHub personal and organization accounts
- Microsoft OAuth - Microsoft accounts (personal, work, school)
The authentication flow:
- User clicks login button in web app
- Web app redirects to OAuth provider
- User authenticates with provider
- Provider redirects back to web app with authorization code
- Web app sends code to TMI server
- TMI server exchanges code for user info
- TMI server issues JWT tokens
- Web app uses JWT for API requests
[User Browser]
↓ (1) Click login
[TMI Web App]
↓ (2) Redirect to provider
[OAuth Provider (Google/GitHub/Microsoft)]
↓ (3) User authenticates
[OAuth Provider]
↓ (4) Redirect with auth code
[TMI Web App]
↓ (5) Send auth code
[TMI Server]
↓ (6) Exchange code for user info
[OAuth Provider]
↓ (7) Return JWT tokens
[TMI Web App]
↓ (8) Use JWT for API calls
[TMI Server]
- Web Application: Initiates OAuth flow, handles callback
- TMI Server: Exchanges authorization codes, issues JWT tokens
- OAuth Provider: Authenticates users, provides user information
Before setting up authentication:
- TMI server deployed and accessible
- TMI web application deployed (for production redirect URIs)
- Domain names configured (for production)
- SSL/TLS certificates (HTTPS required for OAuth in production)
-
Go to Google Cloud Console:
- Navigate to console.cloud.google.com
- Create a new project or select existing project
-
Enable APIs:
- Go to "APIs & Services" → "Library"
- Search for "Google+ API" and enable it
-
Create OAuth Credentials:
- Go to "APIs & Services" → "Credentials"
- Click "Create Credentials" → "OAuth client ID"
- Choose "Web application"
-
Configure OAuth Consent Screen (if not done):
- User Type: External (or Internal for Google Workspace)
- App name: TMI Threat Modeling
- User support email: [email protected]
- Developer contact: [email protected]
- Scopes:
openid,profile,email
-
Configure Application:
-
Name: TMI Production
-
Authorized JavaScript origins:
-
https://tmi.example.com(your web app domain) -
http://localhost:4200(for development)
-
-
Authorized redirect URIs:
-
https://tmi.example.com/oauth2/callback(production) -
http://localhost:4200/oauth2/callback(development)
-
-
-
Get Credentials:
- Copy Client ID and Client Secret
- Save for configuration
Environment Variables:
OAUTH_PROVIDERS_GOOGLE_ENABLED=true
OAUTH_PROVIDERS_GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
OAUTH_PROVIDERS_GOOGLE_CLIENT_SECRET=your-google-client-secretConfiguration File (config-production.yml):
auth:
oauth:
callback_url: "https://api.tmi.example.com/oauth2/callback"
providers:
google:
id: "google"
name: "Google"
enabled: true
icon: "fa-brands fa-google"
client_id: "${OAUTH_PROVIDERS_GOOGLE_CLIENT_ID}"
client_secret: "${OAUTH_PROVIDERS_GOOGLE_CLIENT_SECRET}"
authorization_url: "https://accounts.google.com/o/oauth2/auth"
token_url: "https://oauth2.googleapis.com/token"
userinfo:
- url: "https://www.googleapis.com/oauth2/v3/userinfo"
claims: {} # Uses defaults: sub, email, name
issuer: "https://accounts.google.com"
jwks_url: "https://www.googleapis.com/oauth2/v3/certs"
scopes: ["openid", "profile", "email"]Configure in src/environments/environment.prod.ts:
export const environment = {
production: true,
apiUrl: 'https://api.tmi.example.com',
// Google OAuth handled by TMI server
};# Check provider availability
curl https://api.tmi.example.com/oauth2/providers
# Should include:
{
"providers": [
{"id": "google", "name": "Google", "icon": "google"}
]
}-
Go to GitHub Settings:
- Navigate to github.com/settings/developers
- Click "OAuth Apps" → "New OAuth App"
-
Configure Application:
- Application name: TMI Threat Modeling
- Homepage URL:
https://tmi.example.com - Application description: Collaborative threat modeling platform
- Authorization callback URL:
https://tmi.example.com/oauth2/callback
-
Get Credentials:
- Copy Client ID
- Generate and copy Client Secret
Environment Variables:
OAUTH_PROVIDERS_GITHUB_ENABLED=true
OAUTH_PROVIDERS_GITHUB_CLIENT_ID=your-github-client-id
OAUTH_PROVIDERS_GITHUB_CLIENT_SECRET=your-github-client-secretConfiguration File (config-production.yml):
auth:
oauth:
providers:
github:
id: "github"
name: "GitHub"
enabled: true
icon: "fa-brands fa-github"
client_id: "${OAUTH_PROVIDERS_GITHUB_CLIENT_ID}"
client_secret: "${OAUTH_PROVIDERS_GITHUB_CLIENT_SECRET}"
authorization_url: "https://github.com/login/oauth/authorize"
token_url: "https://github.com/login/oauth/access_token"
auth_header_format: "token %s" # GitHub uses "token" not "Bearer"
accept_header: "application/json"
userinfo:
# Primary user info
- url: "https://api.github.com/user"
claims:
subject_claim: "id"
name_claim: "name"
picture_claim: "avatar_url"
# Email info (separate endpoint)
- url: "https://api.github.com/user/emails"
claims:
email_claim: "[0].email" # First email in array
email_verified_claim: "[0].verified"
scopes: ["user:email"]# Verify provider is configured
curl https://api.tmi.example.com/oauth2/providers | jq '.providers[] | select(.id=="github")'
# Should return GitHub provider detailsMicrosoft OAuth is more complex due to different account types. Choose the appropriate configuration based on your needs.
-
Go to Azure Portal:
- Navigate to portal.azure.com
- Go to "Azure Active Directory" → "App registrations"
- Click "New registration"
-
Configure Application:
- Name: TMI Threat Modeling
- Supported account types: Choose based on requirements:
- Personal Microsoft accounts only: For consumer accounts
- Accounts in any organizational directory: For work/school accounts
- Both personal and work/school accounts: For all Microsoft accounts
-
Set Redirect URI:
- Platform: Web
- Redirect URI:
https://tmi.example.com/oauth2/callback
-
Configure API Permissions:
- Add permissions:
- Microsoft Graph → Delegated permissions
User.Readopenidprofileemail
- Grant admin consent (if required by your organization)
- Add permissions:
-
Create Client Secret:
- Go to "Certificates & secrets"
- Click "New client secret"
- Description: TMI Server
- Expires: Choose expiration (recommended: 24 months)
- Copy the secret value (shown only once!)
-
Get Application ID:
- Copy the Application (client) ID from Overview page
Microsoft has different endpoints based on account types. Choose the appropriate configuration:
Environment Variables:
OAUTH_PROVIDERS_MICROSOFT_ENABLED=true
OAUTH_PROVIDERS_MICROSOFT_CLIENT_ID=your-microsoft-client-id
OAUTH_PROVIDERS_MICROSOFT_CLIENT_SECRET=your-microsoft-client-secretConfiguration File (config-production.yml):
auth:
oauth:
providers:
microsoft:
id: "microsoft"
name: "Microsoft"
enabled: true
icon: "fa-brands fa-microsoft"
client_id: "${OAUTH_PROVIDERS_MICROSOFT_CLIENT_ID}"
client_secret: "${OAUTH_PROVIDERS_MICROSOFT_CLIENT_SECRET}"
authorization_url: "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize"
token_url: "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"
userinfo:
- url: "https://graph.microsoft.com/v1.0/me"
claims:
subject_claim: "id"
email_claim: "mail" # Microsoft uses "mail" not "email"
name_claim: "displayName"
given_name_claim: "givenName"
family_name_claim: "surname"
email_verified_claim: "true" # Literal - always verified
issuer: "https://login.microsoftonline.com/consumers/v2.0"
jwks_url: "https://login.microsoftonline.com/common/discovery/v2.0/keys"
scopes: ["openid", "profile", "email", "User.Read"]Use /common/ endpoint:
authorization_url: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
token_url: "https://login.microsoftonline.com/common/oauth2/v2.0/token"
issuer: "https://login.microsoftonline.com/common/v2.0"Use /organizations/ endpoint:
authorization_url: "https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize"
token_url: "https://login.microsoftonline.com/organizations/oauth2/v2.0/token"
issuer: "https://login.microsoftonline.com/organizations/v2.0"Use tenant-specific endpoint:
authorization_url: "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize"
token_url: "https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token"
issuer: "https://login.microsoftonline.com/{tenant-id}/v2.0"Important: The endpoint type MUST match your Azure AD app's "Supported account types" setting.
# Verify provider is configured
curl https://api.tmi.example.com/oauth2/providers | jq '.providers[] | select(.id=="microsoft")'
# Test authentication (will return redirect URL)
curl -X POST https://api.tmi.example.com/oauth2/token?idp=microsoft \
-H "Content-Type: application/json" \
-d '{"code":"test"}'For local development:
TMI Server - config-development.yml:
auth:
oauth:
callback_url: "http://localhost:8080/oauth2/callback"
providers:
google:
enabled: true
client_id: "dev-client-id.apps.googleusercontent.com"
client_secret: "dev-client-secret"
# ... rest of configAuthorized Redirect URIs (in OAuth provider dashboards):
- Google:
http://localhost:4200/oauth2/callback - GitHub:
http://localhost:4200/oauth2/callback - Microsoft:
http://localhost:4200/oauth2/callback
TMI Server - config-production.yml:
auth:
oauth:
callback_url: "https://api.tmi.example.com/oauth2/callback"
providers:
# Use environment variables for secrets
google:
enabled: true
client_id: "${OAUTH_PROVIDERS_GOOGLE_CLIENT_ID}"
client_secret: "${OAUTH_PROVIDERS_GOOGLE_CLIENT_SECRET}"Authorized Redirect URIs (in OAuth provider dashboards):
- All providers:
https://tmi.example.com/oauth2/callback
# Generate 32-character random secret
openssl rand -base64 32
# Or use this command
python3 -c "import secrets; print(secrets.token_urlsafe(32))"Environment Variables:
JWT_SECRET=your-very-secure-random-secret-minimum-32-characters
JWT_EXPIRATION_SECONDS=3600 # 1 hour
JWT_SIGNING_METHOD=HS256Configuration File:
auth:
jwt:
secret: "${JWT_SECRET}"
expiration_seconds: 3600 # 1 hour for access token
signing_method: "HS256"TMI issues two types of tokens:
Access Token (short-lived, 1 hour):
{
"sub": "user-unique-id",
"email": "[email protected]",
"name": "User Name",
"iss": "tmi-server",
"aud": "tmi-api",
"exp": 1699999999,
"iat": 1699996399
}Refresh Token (long-lived, 30 days):
- Stored in database
- Used to obtain new access tokens
- Can be revoked
- Check available providers:
curl https://api.tmi.example.com/oauth2/providers- Start OAuth flow (in browser):
https://accounts.google.com/o/oauth2/auth?
client_id=YOUR_CLIENT_ID&
redirect_uri=https://tmi.example.com/oauth2/callback&
response_type=code&
scope=openid%20profile%20email&
state=random-state-value
- Exchange authorization code (from web app):
curl -X POST https://api.tmi.example.com/oauth2/token?idp=google \
-H "Content-Type: application/json" \
-d '{
"code": "authorization-code-from-callback",
"state": "random-state-value",
"redirect_uri": "https://tmi.example.com/oauth2/callback"
}'- Verify token:
curl https://api.tmi.example.com/oauth2/me \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Create a test script (test-auth.sh):
#!/bin/bash
API_URL="https://api.tmi.example.com"
echo "Testing OAuth providers..."
PROVIDERS=$(curl -s ${API_URL}/oauth2/providers)
echo $PROVIDERS | jq .
# Check each provider
for PROVIDER in google github microsoft; do
echo "Checking $PROVIDER..."
echo $PROVIDERS | jq ".providers[] | select(.id==\"$PROVIDER\")"
done
echo "Testing JWT endpoint..."
curl -s ${API_URL}/version | jq .Problem: TMI server can't find OAuth provider configuration.
Solutions:
- Verify provider is enabled in configuration
- Check environment variables are set
- Restart TMI server after configuration changes
- Check logs for configuration loading errors
Problem: OAuth provider rejects redirect URI.
Solutions:
- Verify redirect URI in OAuth provider dashboard matches exactly
- Check for trailing slash differences (
/callbackvs/callback/) - Ensure protocol matches (http vs https)
- Confirm domain matches exactly (including www if present)
Problem: TMI server cannot exchange authorization code for tokens.
Solutions:
- Verify client secret is correct
- Check callback URL configuration
- Ensure authorization code hasn't expired (use immediately)
- Verify OAuth provider credentials are active
Problem: Endpoint type doesn't match Azure AD app configuration.
Solution: Match endpoint to app's "Supported account types":
- Personal only →
/consumers/ - Work/school only →
/organizations/ - Both →
/common/ - Specific tenant →
/{tenant-id}/
Problem: State parameter doesn't match.
Solutions:
- Verify web app properly stores and retrieves state
- Check for session storage issues
- Ensure state is generated randomly and securely
- Verify no URL encoding issues with state parameter
Enable detailed OAuth logging:
logging:
level: "debug"
log_api_requests: true
log_api_responses: trueCheck logs for:
# TMI server logs
journalctl -u tmi -f | grep -i oauth
# Look for:
# - Provider configuration loading
# - OAuth token exchange requests
# - User info API calls
# - JWT token generationGoogle:
# Test Google userinfo endpoint manually
curl https://www.googleapis.com/oauth2/v3/userinfo \
-H "Authorization: Bearer GOOGLE_ACCESS_TOKEN"GitHub:
# Test GitHub user endpoint
curl https://api.github.com/user \
-H "Authorization: token GITHUB_ACCESS_TOKEN"
# Test GitHub emails endpoint
curl https://api.github.com/user/emails \
-H "Authorization: token GITHUB_ACCESS_TOKEN"Microsoft:
# Test Microsoft Graph endpoint
curl https://graph.microsoft.com/v1.0/me \
-H "Authorization: Bearer MICROSOFT_ACCESS_TOKEN"- HTTPS Only: Always use HTTPS for OAuth callbacks in production
- Secure Secrets: Never commit client secrets to git
- State Parameter: Always validate state for CSRF protection
- Token Storage: Store tokens securely (httpOnly cookies preferred)
- Token Expiration: Use short expiration for access tokens (1 hour)
- Refresh Tokens: Implement refresh token rotation
- Scope Minimization: Request only necessary OAuth scopes
- Regular Rotation: Rotate OAuth client secrets periodically
- Monitor Access: Log authentication events
- Revocation: Implement token revocation for logout
Create separate OAuth applications for each environment:
| Environment | Google App | GitHub App | Microsoft App |
|---|---|---|---|
| Development | TMI Dev | tmi-dev | TMI Development |
| Staging | TMI Staging | tmi-staging | TMI Staging |
| Production | TMI Production | tmi-prod | TMI Production |
Benefits:
- Separate credentials per environment
- Different redirect URIs
- Independent monitoring
- Safer testing
Use environment-specific configurations:
# Development
export CONFIG_ENV=development
./tmiserver --config=config-${CONFIG_ENV}.yml
# Production
export CONFIG_ENV=production
./tmiserver --config=config-${CONFIG_ENV}.yml- Component Integration - Connect web app to authentication
- Database Setup - Configure user storage
- Post-Deployment - Test authentication flow
- Security Best Practices - Additional security hardening
- Using TMI for Threat Modeling
- Accessing TMI
- Creating Your First Threat Model
- Understanding the User Interface
- Working with Data Flow Diagrams
- Managing Threats
- Collaborative Threat Modeling
- Using Notes and Documentation
- Metadata and Extensions
- Planning Your Deployment
- Deploying TMI Server
- Deploying TMI Web Application
- Setting Up Authentication
- Database Setup
- Component Integration
- Post-Deployment
- Monitoring and Health
- Database Operations
- Security Operations
- Performance and Scaling
- Maintenance Tasks