Identity

Secure Auth0 with cnspec

Scan Auth0 tenant settings, applications, connections, users, roles, and attack protection against security and compliance best practices with cnspec.

An Auth0 tenant decides who reaches your applications and on what terms, so the settings that govern sessions, second factors, and OAuth grants shape the blast radius of every stolen credential. cnspec reads an Auth0 tenant through its Management API and evaluates the tenant wide session and multi-factor policy, the applications registered in the tenant and the OAuth grants and redirect URLs they carry, the identity connections and the password strength they enforce, the APIs and whether role based access control gates their scopes, and the attack protection defenses that apply across the whole tenant.

cnspec reads configuration only. It never reads tenant logs, user passwords, or application secrets: it queries the Management API's configuration endpoints, and secret values are never returned by that API.

If you're new to cnspec, start with the Quickstart. For an overview of every identity provider cnspec can scan, see the identity scanning overview.

The Auth0 resources are experimental. Field names and behavior can change in a future cnspec release.

Prerequisites

To scan Auth0 with cnspec, you must have:

Authenticate

cnspec authenticates as a machine to machine (M2M) application rather than as a user. In the Auth0 dashboard, go to Applications > Applications, create an application of type Machine to Machine, and authorize it for the Auth0 Management API. Grant it the read scopes covering what you want to scan, such as read:clients, read:connections, read:users, read:roles, read:actions, read:log_streams, read:resource_servers, read:client_grants, read:organizations, read:attack_protection, and read:guardian_factors.

The tenant domain is the one shown on the application's Settings tab, such as lunalectric.us.auth0.com.

cnspec shell auth0 --domain lunalectric.us.auth0.com --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET

Environment variables

AUTH0_DOMAIN, AUTH0_CLIENT_ID, and AUTH0_CLIENT_SECRET supply the connection details:

export AUTH0_DOMAIN=lunalectric.us.auth0.com
export AUTH0_CLIENT_ID=YOUR_CLIENT_ID
export AUTH0_CLIENT_SECRET=YOUR_CLIENT_SECRET

When these are set, you can omit the matching flags from the commands below.

Connection options

OptionDescription
--domainAuth0 tenant domain, such as lunalectric.us.auth0.com
--client-idClient ID of the machine to machine application
--client-secretClient secret of the machine to machine application

Verify with a quick Auth0 check

Confirm that cnspec can reach your tenant by opening a cnspec shell:

cnspec shell auth0 --domain lunalectric.us.auth0.com --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET
cnspec> auth0.tenant { friendlyName sessionLifetime idleSessionLifetime }
auth0.tenant: {
  friendlyName: "Lunalectric"
  sessionLifetime: 168
  idleSessionLifetime: 72
}

If cnspec connects and reports your tenant, you're ready to scan.

Scan Auth0

cnspec scan auth0 --domain lunalectric.us.auth0.com --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET

The tenant is a single asset. There are no child assets to discover.

When a scan completes, cnspec prints a summary of all the checks it ran, grouped by policy, along with a risk score from 0 (no risk) to 100 (highest risk). Failed checks include remediation guidance to help you fix issues. To learn more about reading scan results, read Understand cnspec Results.

Mondoo doesn't yet ship an out-of-the-box Auth0 policy, so use the checks below as a starting point and create your own policies to meet your specific requirements.

Explore and test checks interactively

Open a cnspec shell to discover resources and try out checks:

cnspec shell auth0 --domain lunalectric.us.auth0.com --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET

Review the tenant session settings

sessionLifetime and idleSessionLifetime bound how long a session survives before Auth0 requires authentication again:

cnspec> auth0.tenant {
    friendlyName
    sessionLifetime
    idleSessionLifetime
    defaultAudience
    defaultDirectory
    allowedLogoutUrls
  }

Review the multi-factor authentication policy

policy decides when users are challenged, and the per factor flags decide what they may enroll:

cnspec> auth0.guardian {
    policy
    otpEnabled
    webAuthnPlatformEnabled
    webAuthnRoamingEnabled
    pushEnabled
    phoneEnabled
    emailEnabled
    recoveryCodeEnabled
  }

Review the tenant attack protection

Three defenses apply tenant wide, each flattened onto one resource:

cnspec> auth0.attackProtection {
    bruteForceEnabled
    bruteForceMode
    bruteForceMaxAttempts
    suspiciousIpThrottlingEnabled
    breachedPasswordDetectionEnabled
    breachedPasswordDetectionMethod
    breachedPasswordDetectionShields
  }

List the applications and how they authenticate

appType and tokenEndpointAuthMethod together tell you whether an application holds a secret at all:

cnspec> auth0.clients { name appType isFirstParty tokenEndpointAuthMethod grantTypes }

Review where an application may send users

callbacks, allowedOrigins, and webOrigins bound where authentication can land and which origins may call the tenant:

cnspec> auth0.clients { name callbacks allowedLogoutUrls allowedOrigins webOrigins }

Review refresh token handling

A refresh token that neither rotates nor expires is a credential with no natural end:

cnspec> auth0.clients {
    name
    refreshTokenRotationType
    refreshTokenExpirationType
    refreshTokenLifetime
    refreshTokenIdleLifetime
  }

Review the password rules each database connection enforces

passwordPolicy applies only to database connections. Social and enterprise connections leave it empty because the identity provider owns the credential:

cnspec> auth0.connections.where(strategy == "auth0") {
    name
    passwordPolicy
    passwordDictionaryEnabled
    passwordHistoryEnabled
    passwordHistorySize
    passwordNoPersonalInfo
    mfaActive
  }

Review the APIs and how their tokens are signed

cnspec> auth0.resourceServers { name identifier signingAlgorithm tokenLifetime enforcePolicies allowOfflineAccess }

Review the machine to machine grants

A client grant is standing authorization for one application to call one API, so its scopes are the permissions that application always holds:

cnspec> auth0.clientGrants { audience scopes allowAllScopes client { name appType } }

Review the actions running inside the authentication flow

An action runs custom code on every login it's bound to, so an undeployed or failed action and an unreviewed one are different kinds of problem:

cnspec> auth0.actions { name runtime status deployed supportedTriggers }

Review where tenant events are shipped

cnspec> auth0.logStreams { name type status sink }

Walk from a resource to its neighbors

Applications, connections, users, and roles reference each other, so a query can start from any of them and walk in either direction:

cnspec> auth0.clients { name enabledConnections { name strategy } }
cnspec> auth0.connections { name enabledClients { name appType } }
cnspec> auth0.roles { name users { email } }
cnspec> auth0.users { email roles { name } }

Example security checks

Ensure the tenant requires multi-factor authentication

A policy of never means no login is ever challenged for a second factor:

cnspec> auth0.guardian.policy != "never"
[ok] value: true

Ensure a phishing resistant second factor is available

SMS and email codes can be relayed to an attacker. WebAuthn factors are bound to the origin, so they can't be:

cnspec> auth0.guardian.webAuthnRoamingEnabled == true || auth0.guardian.webAuthnPlatformEnabled == true
[ok] value: true

Ensure brute-force protection is enabled

cnspec> auth0.attackProtection.bruteForceEnabled == true
[ok] value: true

Ensure suspicious IP throttling is enabled

Brute-force lockout counts attempts per account. Throttling catches the opposite shape of attack, a few addresses trying many accounts:

cnspec> auth0.attackProtection.suspiciousIpThrottlingEnabled == true
[ok] value: true

Ensure breached password detection blocks the login

Detection that only notifies still lets the login through:

cnspec> auth0.attackProtection.breachedPasswordDetectionEnabled == true && auth0.attackProtection.breachedPasswordDetectionShields.contains("block")
[ok] value: true

Ensure sessions expire within a week

cnspec> auth0.tenant.sessionLifetime <= 168
[ok] value: true

Ensure idle sessions expire sooner than active ones

cnspec> auth0.tenant.idleSessionLifetime < auth0.tenant.sessionLifetime
[ok] value: true

Ensure no application uses the implicit grant

The implicit grant returns tokens in the URL fragment, where they reach browser history and referrer headers:

cnspec> auth0.clients.none(grantTypes.contains("implicit"))
[ok] value: true

Ensure refresh tokens rotate

cnspec> auth0.clients.where(grantTypes.contains("refresh_token")).all(refreshTokenRotationType == "rotating")
[ok] value: true

Ensure no refresh token lives forever

cnspec> auth0.clients.none(refreshTokenExpirationType == "non-expiring")
[ok] value: true

Ensure database connections enforce a strong password policy

cnspec> auth0.connections.where(strategy == "auth0").all(passwordPolicy == "excellent")
[ok] value: true

Ensure database connections reject breached and reused passwords

cnspec> auth0.connections.where(strategy == "auth0").all(passwordDictionaryEnabled == true && passwordHistoryEnabled == true)
[ok] value: true

Ensure your APIs enforce role-based access control

Without enforcePolicies, a token carries whatever scopes the application asked for rather than what the user's roles allow:

cnspec> auth0.resourceServers.where(isSystem == false).all(enforcePolicies == true)
[ok] value: true

Ensure access tokens are signed with an asymmetric key

HS256 signs with a shared secret, so every party that validates a token could also mint one:

cnspec> auth0.resourceServers.where(isSystem == false).all(signingAlgorithm == "RS256")
[ok] value: true

Ensure no machine to machine grant takes every scope

allowAllScopes grants each scope the API defines, including the ones added after the grant was created:

cnspec> auth0.clientGrants.none(allowAllScopes == true)
[ok] value: true

Ensure tenant events reach a log stream

Without an active stream, no record of authentication events leaves the tenant:

cnspec> auth0.logStreams.where(status == "active").length > 0
[ok] value: true

Ensure every action in the login path is deployed

An action that failed to build isn't running, so the control it implements isn't either:

cnspec> auth0.actions.all(deployed == true)
[ok] value: true

Ensure no user is left blocked indefinitely

A blocked account is an unresolved incident or an offboarding nobody finished:

cnspec> auth0.users.none(blocked == true)
[ok] value: true

Review accounts that have never signed in

cnspec> auth0.users.where(loginsCount == 0) { email createdAt }

Learn more

On this page

PrerequisitesAuthenticateEnvironment variablesConnection optionsVerify with a quick Auth0 checkScan Auth0Explore and test checks interactivelyReview the tenant session settingsReview the multi-factor authentication policyReview the tenant attack protectionList the applications and how they authenticateReview where an application may send usersReview refresh token handlingReview the password rules each database connection enforcesReview the APIs and how their tokens are signedReview the machine to machine grantsReview the actions running inside the authentication flowReview where tenant events are shippedWalk from a resource to its neighborsExample security checksEnsure the tenant requires multi-factor authenticationEnsure a phishing resistant second factor is availableEnsure brute-force protection is enabledEnsure suspicious IP throttling is enabledEnsure breached password detection blocks the loginEnsure sessions expire within a weekEnsure idle sessions expire sooner than active onesEnsure no application uses the implicit grantEnsure refresh tokens rotateEnsure no refresh token lives foreverEnsure database connections enforce a strong password policyEnsure database connections reject breached and reused passwordsEnsure your APIs enforce role-based access controlEnsure access tokens are signed with an asymmetric keyEnsure no machine to machine grant takes every scopeEnsure tenant events reach a log streamEnsure every action in the login path is deployedEnsure no user is left blocked indefinitelyReview accounts that have never signed inLearn more