Auth0 Hardening Guide
Identity platform hardening for Auth0 tenant security, MFA, and attack protection
Overview
Auth0, now part of Okta, is a leading identity platform powering authentication for thousands of applications and billions of logins monthly. As the authentication layer for web and mobile applications, Auth0 tenant security directly impacts application security posture. Misconfigurations or weak security controls can expose applications to credential stuffing, brute force attacks, and account takeover.
Intended Audience
- Security engineers managing Auth0 deployments
- Application developers implementing authentication
- GRC professionals assessing IAM controls
- Third-party risk managers evaluating identity providers
How to Use This Guide
- L1 (Baseline): Essential controls for all organizations
- L2 (Hardened): Enhanced controls for security-sensitive environments
- L3 (Maximum Security): Strictest controls for regulated industries
Scope
This guide covers Auth0 tenant security configurations including attack protection, MFA policies, application security, and monitoring.
Table of Contents
- Attack Protection
- Authentication & MFA
- Tenant Security
- Application Security
- Monitoring & Detection
- Compliance Quick Reference
1. Attack Protection
1.1 Enable Brute Force Protection
Profile Level: L1 (Baseline)
| Framework | Control |
|---|---|
| CIS Controls | 4.10 |
| NIST 800-53 | AC-7, SI-4 |
Description
Brute force protection blocks IP addresses that repeatedly fail to authenticate to a single user account. This is enabled by default but should be verified and configured appropriately.
Rationale
Why This Matters:
- Blocks credential stuffing attacks targeting specific accounts
- Prevents automated password guessing
- Notifies affected users of suspicious activity
- Default threshold of 10 may be too high for sensitive applications
Prerequisites
- Auth0 Dashboard access with admin privileges
- Secondary admin account (for recovery)
ClickOps Implementation
Step 1: Access Attack Protection Settings
- Navigate to: Auth0 Dashboard → Security → Attack Protection
- Click Brute-force Protection
Step 2: Configure Protection Settings
- Verify Brute-force Protection is enabled
- Configure threshold:
- Default: 10 failed attempts (click Default)
- Custom: Set to 5 for higher security (click Custom)
- Configure actions:
- Block suspicious IP: Enabled
- Send email notification: Enabled
Step 3: Configure Shields
- Enable available shields:
- Shield 1: Block traffic after threshold
- Shield 2: Block traffic from known bad IPs
Time to Complete: ~15 minutes
Validation & Testing
- Verify protection is enabled in Dashboard
- Test by exceeding threshold (in test environment)
- Confirm block occurs and notification sent
- Verify admin can unblock accounts
Code Pack: Terraform
resource "auth0_attack_protection" "brute_force" {
brute_force_protection {
enabled = true
max_attempts = 5
mode = "count_per_identifier_and_ip"
shields = ["block", "user_notification"]
allowlist = []
}
}
Code Pack: API Script
# Enable brute force protection with hardened thresholds
info "1.1 Enabling brute force protection..."
RESPONSE=$(a0_patch "/attack-protection/brute-force-protection" '{
"enabled": true,
"shields": ["block", "user_notification"],
"mode": "count_per_identifier_and_ip",
"max_attempts": 5
}') || {
fail "1.1 Failed to enable brute force protection"
increment_failed; summary; exit 0
}
Code Pack: Sigma Detection Rule
detection:
selection:
type: 'sapi'
description|contains: 'brute-force-protection'
filter_disable:
details.request.body|contains: '"enabled":false'
condition: selection and filter_disable
fields:
- date
- type
- description
- user_name
- ip
1.2 Enable Suspicious IP Throttling
Profile Level: L1 (Baseline)
| Framework | Control |
|---|---|
| CIS Controls | 4.10 |
| NIST 800-53 | SI-4 |
Description
Suspicious IP throttling monitors and limits requests from IP addresses exhibiting suspicious behavior across multiple accounts.
Rationale
Why This Matters:
- Detects distributed attacks targeting multiple accounts
- Rate limits suspicious IPs before they can cause damage
- Complements brute force protection
ClickOps Implementation
Step 1: Enable Suspicious IP Throttling
- Navigate to: Security → Attack Protection → Suspicious IP Throttling
- Enable Suspicious IP Throttling
- Configure thresholds:
- Max attempts per IP: 100 (default) or lower
- Throttle rate: Configure based on expected traffic
Time to Complete: ~10 minutes
Code Pack: Terraform
resource "auth0_attack_protection" "suspicious_ip" {
suspicious_ip_throttling {
enabled = true
shields = ["admin_notification", "block"]
allowlist = []
pre_login {
max_attempts = 100
rate = 864000
}
pre_user_registration {
max_attempts = 50
rate = 1200000
}
}
}
Code Pack: API Script
# Enable suspicious IP throttling
info "1.2 Enabling suspicious IP throttling..."
RESPONSE=$(a0_patch "/attack-protection/suspicious-ip-throttling" '{
"enabled": true,
"shields": ["admin_notification", "block"],
"stage": {
"pre-login": { "max_attempts": 100, "rate": 864000 },
"pre-user-registration": { "max_attempts": 50, "rate": 1200000 }
}
}') || {
fail "1.2 Failed to enable suspicious IP throttling"
increment_failed; summary; exit 0
}
1.3 Enable Breached Password Detection
Profile Level: L1 (Baseline)
| Framework | Control |
|---|---|
| CIS Controls | 5.2 |
| NIST 800-53 | IA-5 |
Description
Breached Password Detection checks user passwords against known breached credential databases and prevents use of compromised passwords.
Rationale
Why This Matters:
- Prevents credential reuse from breached databases
- Blocks accounts using known compromised passwords
- Minimal friction for legitimate users
ClickOps Implementation
Step 1: Enable Breached Password Detection
- Navigate to: Security → Attack Protection → Breached Password Detection
- Enable the feature
- Configure response:
- At Sign-up: Block registration with breached passwords
- At Login: Notify user or block access
- Configure notifications
Time to Complete: ~15 minutes
Code Pack: Terraform
resource "auth0_attack_protection" "breached_password" {
breached_password_detection {
enabled = true
method = "standard"
shields = ["admin_notification", "block"]
admin_notification_frequency = ["immediately"]
pre_user_registration {
shields = ["block"]
}
}
}
Code Pack: API Script
# Enable breached password detection
info "1.3 Enabling breached password detection..."
RESPONSE=$(a0_patch "/attack-protection/breached-password-detection" '{
"enabled": true,
"method": "standard",
"shields": ["admin_notification", "block"],
"admin_notification_frequency": ["immediately"],
"stage": {
"pre-user-registration": { "shields": ["block"] }
}
}') || {
fail "1.3 Failed to enable breached password detection (may require Professional plan)"
increment_failed; summary; exit 0
}
1.4 Configure Bot Detection
Profile Level: L2 (Hardened)
| Framework | Control |
|---|---|
| CIS Controls | 4.10 |
| NIST 800-53 | SI-4 |
Description
Configure CAPTCHA and bot detection to prevent automated attacks against authentication flows.
ClickOps Implementation
Step 1: Enable Bot Detection
- Navigate to: Security → Attack Protection → Bot Detection
- Enable Bot Detection
- Configure triggers:
- Login
- Sign-up
- Password reset
Step 2: Configure CAPTCHA Provider
- Select CAPTCHA provider:
- reCAPTCHA (Google)
- Arkose Labs (enterprise)
- Configure provider settings
- Set challenge frequency
Code Pack: Terraform
resource "auth0_attack_protection" "bot_detection" {
bot_detection {
bot_detection_level = "medium"
challenge_password_policy = "when_risky"
challenge_passwordless_policy = "when_risky"
challenge_password_reset_policy = "when_risky"
monitoring_mode_enabled = false
allowlist = []
}
}
Code Pack: API Script
# Configure bot detection with risk-based challenges
info "1.4 Configuring bot detection..."
RESPONSE=$(a0_patch "/attack-protection/bot-detection" '{
"bot_detection_level": "medium",
"challenge_password_policy": "when_risky",
"challenge_passwordless_policy": "when_risky",
"challenge_password_reset_policy": "when_risky",
"monitoring_mode_enabled": false
}') || {
fail "1.4 Failed to configure bot detection"
increment_failed; summary; exit 0
}
2. Authentication & MFA
2.1 Enforce Strong Password Policies
Profile Level: L1 (Baseline)
| Framework | Control |
|---|---|
| CIS Controls | 5.2 |
| NIST 800-53 | IA-5 |
Description
Configure password policies that enforce complexity requirements while balancing usability.
ClickOps Implementation
Step 1: Access Password Policy
- Navigate to: Authentication → Database → Select your connection
- Click Password Policy
Step 2: Configure Policy
- Select policy level:
- None: No restrictions (not recommended)
- Low: 6+ characters
- Fair: 8+ characters, lowercase/uppercase/numbers
- Good: 8+ characters, mixed case, numbers, symbols (recommended)
- Excellent: 10+ characters, all requirements
- Enable additional options:
- Password history: Prevent reuse (last 5)
- Password dictionary: Block common passwords
Time to Complete: ~10 minutes
Code Pack: Terraform
resource "auth0_connection" "database" {
name = "Username-Password-Authentication"
strategy = "auth0"
options {
password_policy = "excellent"
brute_force_protection = true
password_complexity_options {
min_length = 14
}
password_history {
enable = true
size = 5
}
password_dictionary {
enable = true
}
password_no_personal_info {
enable = true
}
}
}
Code Pack: API Script
# Set strong password policy on database connection
info "2.1 Setting password policy to 'excellent' with history and dictionary..."
RESPONSE=$(a0_patch "/connections/${CONNECTION_ID}" '{
"options": {
"password_policy": "excellent",
"brute_force_protection": true,
"password_complexity_options": { "min_length": 14 },
"password_history": { "enable": true, "size": 5 },
"password_dictionary": { "enable": true },
"password_no_personal_info": { "enable": true }
}
}') || {
fail "2.1 Failed to update password policy"
increment_failed; summary; exit 0
}
2.2 Enable Multi-Factor Authentication
Profile Level: L1 (Baseline)
| Framework | Control |
|---|---|
| CIS Controls | 6.5 |
| NIST 800-53 | IA-2(1) |
Description
Require MFA for user authentication. Configure phishing-resistant options like WebAuthn where possible.
Rationale
Why This Matters:
- MFA prevents 99.9% of automated attacks
- TOTP-based MFA is more secure than SMS
- WebAuthn provides phishing resistance
ClickOps Implementation
Step 1: Enable MFA Factors
- Navigate to: Security → Multi-factor Authentication
- Enable desired factors:
- One-time Password (OTP): Recommended
- WebAuthn with Security Keys: Highly recommended
- WebAuthn with Device Biometrics: Recommended
- SMS: Discouraged (SIM swapping risk)
- Voice: Discouraged
Step 2: Configure MFA Policy
- Set Always for applications requiring MFA
- Or use Adaptive MFA for risk-based enforcement
- Configure MFA trigger points
Step 3: Require MFA for Dashboard Access
- Navigate to: Settings → Tenant Settings
- Enable Require MFA for all Dashboard users
Time to Complete: ~30 minutes
Code Pack: Terraform
resource "auth0_guardian" "mfa" {
policy = "all-applications"
otp = true
recovery_code = true
webauthn_roaming {
user_verification = "required"
}
webauthn_platform {}
}
Code Pack: API Script
# Set MFA policy to all-applications and enable OTP + WebAuthn
info "2.2 Setting MFA policy to 'all-applications'..."
a0_put "/guardian/policies" '["all-applications"]' || {
fail "2.2 Failed to set MFA policy"
increment_failed; summary; exit 0
}
info "2.2 Enabling OTP factor..."
a0_put "/guardian/factors/otp" '{"enabled": true}' || warn "2.2 Failed to enable OTP"
info "2.2 Enabling WebAuthn (security keys)..."
a0_put "/guardian/factors/webauthn-roaming" '{"enabled": true}' || warn "2.2 Failed to enable WebAuthn roaming"
info "2.2 Enabling WebAuthn (biometrics)..."
a0_put "/guardian/factors/webauthn-platform" '{"enabled": true}' || warn "2.2 Failed to enable WebAuthn platform"
info "2.2 Enabling recovery codes..."
a0_put "/guardian/factors/recovery-code" '{"enabled": true}' || warn "2.2 Failed to enable recovery codes"
Code Pack: Sigma Detection Rule
detection:
selection:
type: 'sapi'
description|contains: 'guardian/policies'
filter_weaken:
details.request.body|contains:
- '"never"'
- '"confidence-score"'
condition: selection and filter_weaken
fields:
- date
- type
- description
- user_name
- ip
2.3 Configure Adaptive MFA
Profile Level: L2 (Hardened)
| Framework | Control |
|---|---|
| CIS Controls | 6.5 |
| NIST 800-53 | IA-2(6) |
Description
Configure Adaptive MFA to trigger additional authentication based on risk signals like new device, location, or suspicious behavior.
ClickOps Implementation
Step 1: Enable Adaptive MFA
- Navigate to: Security → Multi-factor Authentication
- Set policy to Adaptive
- Configure risk factors:
- New device
- Impossible travel
- High-risk IP
Step 2: Configure Actions
- Define MFA trigger conditions
- Configure step-up authentication for high-risk scenarios
3. Tenant Security
3.1 Restrict Dashboard Admin Access
Profile Level: L1 (Baseline)
| Framework | Control |
|---|---|
| CIS Controls | 5.4 |
| NIST 800-53 | AC-6(1) |
Description
Limit Dashboard admin access to essential personnel and require MFA for all admins.
ClickOps Implementation
Step 1: Audit Admin Users
- Navigate to: Settings → Tenant Members
- Review all admin users
- Remove unnecessary access
Step 2: Implement Least Privilege
- Use role-based access:
- Admin: Full tenant access
- Editor: Manage applications, connections
- Viewer: Read-only access
- Assign minimum required roles
Step 3: Require Admin MFA
- Navigate to: Settings → Tenant Settings
- Enable Require MFA for all Dashboard users
- Admins must enroll in MFA on next login
Code Pack: Terraform
resource "auth0_tenant" "hardened" {
friendly_name = var.tenant_name
session_lifetime = 8
idle_session_lifetime = 1
flags {
disable_clickjack_protection_headers = false
enable_public_signup_user_exists_error = false
revoke_refresh_token_grant = true
enable_sso = true
}
session_cookie {
mode = "non-persistent"
}
}
Code Pack: API Script
# Harden tenant session and security settings
info "3.1 Applying hardened tenant settings..."
RESPONSE=$(a0_patch "/tenants/settings" '{
"session_lifetime": 8,
"idle_session_lifetime": 1,
"flags": {
"disable_clickjack_protection_headers": false,
"enable_public_signup_user_exists_error": false,
"revoke_refresh_token_grant": true,
"enable_sso": true
},
"session_cookie": { "mode": "non-persistent" }
}') || {
fail "3.1 Failed to update tenant settings"
increment_failed; summary; exit 0
}
Code Pack: Sigma Detection Rule
detection:
selection:
type: 'sapi'
description|contains: 'tenants/settings'
condition: selection
fields:
- date
- type
- description
- user_name
- ip
3.2 Configure Tenant Isolation
Profile Level: L2 (Hardened)
| Framework | Control |
|---|---|
| CIS Controls | 3.12 |
| NIST 800-53 | SC-7 |
Description
Use separate tenants for production and non-production environments to isolate security configurations and data.
Rationale
Why This Matters:
- Prevents test configurations from affecting production
- Isolates development credentials from production
- Enables different security policies per environment
Implementation
- Create separate tenants for each environment:
yourcompany-dev.auth0.comyourcompany-staging.auth0.comyourcompany.auth0.com(production)
- Apply strictest security to production tenant
- Use tenant-specific credentials
3.3 Secure Tenant Credentials
Profile Level: L1 (Baseline)
| Framework | Control |
|---|---|
| CIS Controls | 3.11 |
| NIST 800-53 | SC-12 |
Description
Protect Auth0 API credentials (Client ID, Client Secret, Management API tokens) as sensitive secrets.
Implementation
- Store secrets in secure vault (HashiCorp Vault, AWS Secrets Manager)
- Never commit secrets to source control
- Rotate credentials regularly
- Use different credentials per environment
4. Application Security
4.1 Configure Secure Connections
Profile Level: L1 (Baseline)
| Framework | Control |
|---|---|
| CIS Controls | 3.10 |
| NIST 800-53 | SC-8 |
Description
Configure database and social connections with security best practices.
ClickOps Implementation
Step 1: Review Database Connections
- Navigate to: Authentication → Database
- For each connection:
- Enable password policy (Good or Excellent)
- Enable brute force protection
- Disable sign-ups if registration is controlled
Step 2: Review Social Connections
- Navigate to: Authentication → Social
- For each social provider:
- Use dedicated OAuth applications
- Request minimum required scopes
- Verify redirect URIs
4.2 Secure Application Configurations
Profile Level: L1 (Baseline)
| Framework | Control |
|---|---|
| CIS Controls | 4.1 |
| NIST 800-53 | CM-7 |
Description
Configure Auth0 applications with security best practices.
ClickOps Implementation
Step 1: Review Application Settings
- Navigate to: Applications → Select application
- Configure:
- Application Type: Select correct type (SPA, Regular Web, etc.)
- Token Endpoint Authentication: Use Private Key JWT where possible
- Allowed Callback URLs: Specific URLs only (no wildcards)
- Allowed Logout URLs: Specific URLs only
Step 2: Configure Token Settings
- Set appropriate token expiration:
- Access Token: 3600 seconds or less
- Refresh Token: Based on session requirements
- Configure rotation for refresh tokens
Code Pack: Terraform
resource "auth0_client" "secure_app" {
name = var.app_name
app_type = "regular_web"
oidc_conformant = true
jwt_configuration {
lifetime_in_seconds = 300
alg = "RS256"
}
refresh_token {
rotation_type = "rotating"
expiration_type = "expiring"
token_lifetime = 2592000
idle_token_lifetime = 1296000
leeway = 0
}
}
Code Pack: API Script
# Audit application token settings and OIDC conformance
CLIENTS=$(a0_get "/clients?fields=name,client_id,app_type,oidc_conformant,jwt_configuration,refresh_token&include_fields=true") || {
fail "4.2 Unable to retrieve applications"
increment_failed; summary; exit 0
}
CLIENT_COUNT=$(echo "${CLIENTS}" | jq 'length')
info "4.2 Found ${CLIENT_COUNT} application(s)"
ISSUES=0
while IFS= read -r client; do
NAME=$(echo "${client}" | jq -r '.name')
OIDC=$(echo "${client}" | jq -r '.oidc_conformant // false')
TOKEN_TTL=$(echo "${client}" | jq -r '.jwt_configuration.lifetime_in_seconds // 36000')
ROTATION=$(echo "${client}" | jq -r '.refresh_token.rotation_type // "non-rotating"')
[ "${OIDC}" != "true" ] && { warn "4.2 '${NAME}' is not OIDC conformant"; ISSUES=$((ISSUES + 1)); }
[ "${TOKEN_TTL}" -gt 3600 ] && { warn "4.2 '${NAME}' access token TTL (${TOKEN_TTL}s) exceeds 1 hour"; ISSUES=$((ISSUES + 1)); }
[ "${ROTATION}" != "rotating" ] && { warn "4.2 '${NAME}' refresh tokens are not rotating"; ISSUES=$((ISSUES + 1)); }
done < <(echo "${CLIENTS}" | jq -c '.[]')
4.3 Secure Rules and Actions
Profile Level: L2 (Hardened)
| Framework | Control |
|---|---|
| CIS Controls | 16.1 |
| NIST 800-53 | SA-15 |
Description
Secure Auth0 Rules and Actions to prevent injection and ensure proper error handling.
Security Best Practices
- Never bypass MFA conditionally based on:
- Silent authentication
- Device fingerprinting
- Geographic location alone
- Use allowRememberBrowser or context.authentication for contextual bypass
- Validate all inputs in Rules and Actions
- Handle errors gracefully without exposing details
- Log security events appropriately
5. Monitoring & Detection
5.1 Enable Logging and Monitoring
Profile Level: L1 (Baseline)
| Framework | Control |
|---|---|
| CIS Controls | 8.2 |
| NIST 800-53 | AU-2, AU-6 |
Description
Configure Auth0 logging and integrate with SIEM for security monitoring.
ClickOps Implementation
Step 1: Access Logs
- Navigate to: Monitoring → Logs
- Review log types:
- Success and failure logins
- Token exchanges
- Admin actions
Step 2: Configure Log Streaming
- Navigate to: Monitoring → Streams
- Click Create Stream
- Select destination:
- Amazon EventBridge
- Azure Event Hub
- Datadog
- Splunk
- Custom webhook
- Configure stream settings
Time to Complete: ~30 minutes
Code Pack: Terraform
resource "auth0_log_stream" "siem" {
name = "SIEM Log Stream"
type = "http"
status = "active"
sink {
http_endpoint = var.siem_webhook_url
http_content_type = "application/json"
http_content_format = "JSONOBJECT"
http_authorization = "Bearer ${var.siem_token}"
}
}
Code Pack: API Script
# Audit log stream configuration
STREAMS=$(a0_get "/log-streams") || {
fail "5.1 Unable to retrieve log streams"
increment_failed; summary; exit 0
}
STREAM_COUNT=$(echo "${STREAMS}" | jq 'length')
ACTIVE_COUNT=$(echo "${STREAMS}" | jq '[.[] | select(.status == "active")] | length')
info "5.1 Found ${STREAM_COUNT} log stream(s), ${ACTIVE_COUNT} active"
if [ "${ACTIVE_COUNT}" -gt 0 ]; then
pass "5.1 Active log stream(s) configured"
echo "${STREAMS}" | jq -r '.[] | " - \(.name) (\(.type)): \(.status)"'
else
warn "5.1 No active log streams -- configure SIEM integration (requires Professional plan)"
fi
Code Pack: Sigma Detection Rule
detection:
selection:
type: 'sapi'
description|contains: 'log-streams'
filter_action:
details.request.method|contains:
- 'delete'
- 'patch'
condition: selection and filter_action
fields:
- date
- type
- description
- user_name
- ip
5.2 Key Events to Monitor
| Event Code | Event Type | Detection Use Case |
|---|---|---|
f |
Failed Login | Brute force attempts |
fu |
Failed Login (user blocked) | Account lockout |
fp |
Failed Login (wrong password) | Credential stuffing |
sepft |
Suspicious Email Prevented | Fraud attempt |
fcoa |
Failed Cross-Origin Auth | XSS attempt |
sapi |
Management API Success | Admin activity |
fapi |
Management API Failure | Unauthorized admin access |
6. Compliance Quick Reference
SOC 2 Trust Services Criteria Mapping
| Control ID | Auth0 Control | Guide Section |
|---|---|---|
| CC6.1 | MFA enforcement | 2.2 |
| CC6.1 | Admin access control | 3.1 |
| CC6.2 | Attack protection | 1.1 |
| CC7.2 | Logging | 5.1 |
NIST 800-53 Rev 5 Mapping
| Control | Auth0 Control | Guide Section |
|---|---|---|
| IA-2(1) | MFA | 2.2 |
| AC-7 | Brute force protection | 1.1 |
| IA-5 | Password policy | 2.1 |
| AU-2 | Logging | 5.1 |
Appendix A: Plan Compatibility
| Feature | Free | Essential | Professional | Enterprise |
|---|---|---|---|---|
| Brute Force Protection | ✅ | ✅ | ✅ | ✅ |
| Suspicious IP Throttling | ❌ | ✅ | ✅ | ✅ |
| Breached Password Detection | ❌ | ❌ | ✅ | ✅ |
| Adaptive MFA | ❌ | ❌ | ✅ | ✅ |
| Log Streaming | ❌ | ❌ | ✅ | ✅ |
| Custom Domains | ❌ | ❌ | ✅ | ✅ |
Appendix B: References
Official Auth0 Documentation:
Security Best Practices:
Changelog
| Date | Version | Maturity | Changes | Author |
|---|---|---|---|---|
| 2025-02-05 | 0.1.0 | draft | Initial guide with attack protection, MFA, and tenant security | Claude Code (Opus 4.5) |
Contributing
Found an issue or want to improve this guide?
- Report outdated information: Open an issue with tag
content-outdated - Propose new controls: Open an issue with tag
new-control - Submit improvements: See Contributing Guide