4. Configuration

Minimal Axes configuration is done with just settings.py updates.

More advanced configuration and integrations might require updates on source code level depending on your project implementation.

Configuring project settings

The following settings.py options are available for customizing Axes behaviour.

Variable

Default

Explanation

AXES_ENABLED

True

Enable or disable Axes plugin functionality, for example in test runner setup

AXES_FAILURE_LIMIT

3

The integer number of login attempts allowed before a record is created for the failed logins. This can also be a callable or a dotted path to callable that returns an integer and all of the following are valid: AXES_FAILURE_LIMIT = 42, AXES_FAILURE_LIMIT = lambda *args: 42, and AXES_FAILURE_LIMIT = 'project.app.get_login_failure_limit'.

AXES_LOCK_OUT_AT_FAILURE

True

After the number of allowed login attempts are exceeded, should we lock out this IP (and optional user agent)?

AXES_COOLOFF_TIME

None

If set, defines a period of inactivity after which old failed login attempts will be cleared. Can be set to a Python timedelta object, an integer, a float, a callable, or a string path to a callable which takes no arguments. If an integer or float, will be interpreted as a number of hours: AXES_COOLOFF_TIME = 2 2 hours, AXES_COOLOFF_TIME = 2.0 2 hours, 120 minutes, AXES_COOLOFF_TIME = 1.7 1.7 hours, 102 minutes, 6120 seconds

AXES_ONLY_ADMIN_SITE

False

If True, lock is only enabled for admin site. Admin site is determined by checking request path against the path of "admin:index" view. If admin urls are not registered in current urlconf, all requests will not be locked.

AXES_ONLY_USER_FAILURES

False

DEPRECATED: USE AXES_LOCKOUT_PARAMETERS INSTEAD. If True, only lock based on username, and never lock based on IP if attempts exceed the limit. Otherwise utilize the existing IP and user locking logic.

AXES_ENABLE_ADMIN

True

If True, admin views for access attempts and logins are shown in Django admin interface.

AXES_LOCK_OUT_BY_COMBINATION_USER_AND_IP

False

DEPRECATED: USE AXES_LOCKOUT_PARAMETERS INSTEAD. If True, prevent login from IP under a particular username if the attempt limit has been exceeded, otherwise lock out based on IP.

AXES_LOCK_OUT_BY_USER_OR_IP

False

DEPRECATED: USE AXES_LOCKOUT_PARAMETERS INSTEAD. If True, prevent login from if the attempt limit has been exceeded for IP or username.

AXES_USE_USER_AGENT

False

DEPRECATED: USE AXES_LOCKOUT_PARAMETERS INSTEAD. If True, lock out and log based on the IP address and the user agent. This means requests from different user agents but from the same IP are treated differently. This settings has no effect if the AXES_ONLY_USER_FAILURES setting is active.

AXES_HANDLER

‘axes.handlers.database.AxesDatabaseHandler’

The path to the handler class to use. If set, overrides the default signal handler backend. Default: 'axes.handlers.database.AxesDatabaseHandler'

AXES_CACHE

‘default’

The name of the cache for Axes to use.

AXES_LOCKOUT_TEMPLATE

None

If set, specifies a template to render when a user is locked out. Template receives cooloff_timedelta, cooloff_time, username and failure_limit as context variables.

AXES_LOCKOUT_URL

None

If set, specifies a URL to redirect to on lockout. If both AXES_LOCKOUT_TEMPLATE and AXES_LOCKOUT_URL are set, the template will be used.

AXES_VERBOSE

True

If True, you’ll see slightly more logging for Axes.

AXES_USERNAME_FORM_FIELD

‘username’

The name of the form field that contains your users usernames.

AXES_USERNAME_CALLABLE

None

A callable or a string path to callable that takes two arguments for user lookups: def get_username(request: HttpRequest, credentials: dict) -> str: .... This can be any callable such as AXES_USERNAME_CALLABLE = lambda request, credentials: 'username' or a full Python module path to callable such as AXES_USERNAME_CALLABLE = 'example.get_username. The request is a HttpRequest like object and the credentials is a dictionary like object. credentials are the ones that were passed to Django authenticate() in the login flow. If no function is supplied, Axes fetches the username from the credentials or request.POST dictionaries based on AXES_USERNAME_FORM_FIELD.

AXES_WHITELIST_CALLABLE

None

A callable or a string path to callable that takes two arguments for whitelisting determination and returns True, if user should be whitelisted: def is_whitelisted(request: HttpRequest, credentials: dict) -> bool: .... This can be any callable similarly to AXES_USERNAME_CALLABLE.

AXES_LOCKOUT_CALLABLE

None

A callable or a string path to callable that takes two arguments returns a response. For example: def generate_lockout_response(request: HttpRequest, credentials: dict) -> HttpResponse: .... This can be any callable similarly to AXES_USERNAME_CALLABLE. If not callable is defined, then the default implementation in axes.helpers.get_lockout_response is used for determining the correct lockout response that is sent to the requesting client.

AXES_CLIENT_IP_CALLABLE

None

A callable or a string path to callable that takes two arguments returns a response. For example: def get_ip(request: HttpRequest) -> str: .... This can be any callable similarly to AXES_USERNAME_CALLABLE. If not callable is defined, then the default implementation in axes.helpers.get_client_ip_address is used.

AXES_PASSWORD_FORM_FIELD

‘password’

The name of the form or credentials field that contains your users password.

AXES_SENSITIVE_PARAMETERS

[“username”, “ip_address”]

Configures POST and GET parameter values (in addition to the value of AXES_PASSWORD_FORM_FIELD) to mask in login attempt logging. Defaults enable privacy-by-design.

AXES_NEVER_LOCKOUT_GET

False

If True, Axes will never lock out HTTP GET requests.

AXES_NEVER_LOCKOUT_WHITELIST

False

If True, users can always login from whitelisted IP addresses.

AXES_IP_BLACKLIST

None

An iterable of IPs to be blacklisted. Takes precedence over whitelists. For example: AXES_IP_BLACKLIST = ['0.0.0.0'].

AXES_IP_WHITELIST

None

An iterable of IPs to be whitelisted. For example: AXES_IP_WHITELIST = ['0.0.0.0'].

AXES_DISABLE_ACCESS_LOG

False

If True, disable writing login and logout access logs to database, so the admin interface will not have user login trail for successful user authentication.

AXES_ENABLE_ACCESS_FAILURE_LOG

False

If True, enable writing login failure logs to database, so you will have every user login trail for unsuccessful user authentication.

AXES_ACCESS_FAILURE_LOG_PER_USER_LIMIT

1000

Sets the number of failures to trail for each user. When the access failure log reach this number of records, an automatic removal is ran.

AXES_RESET_ON_SUCCESS

False

If True, a successful login will reset the number of failed logins.

AXES_ALLOWED_CORS_ORIGINS

“*”

Configures lockout response CORS headers for XHR requests.

AXES_HTTP_RESPONSE_CODE

429

Sets the http response code returned when AXES_FAILURE_LIMIT is reached. For example: AXES_HTTP_RESPONSE_CODE = 403

AXES_RESET_COOL_OFF_ON_FAILURE_DURING_LOCKOUT

True

If True, a failed login attempt during lockout will reset the cool off period.

AXES_LOCKOUT_PARAMETERS

[“ip_address”]

A list of parameters that Axes uses to lock out users. It can also be callable, which takes an http request or AccesAttempt object and credentials and returns a list of parameters. Each parameter can be a string (a single parameter) or a list of strings (a combined parameter). For example, if you configure AXES_LOCKOUT_PARAMETERS = ["ip_address", ["username", "user_agent"]], axes will block clients by ip and/or username and user agent combination. See Customizing lockout parameters for more details.

The configuration option precedences for the access attempt monitoring are:

  1. Default: only use IP address.

  2. AXES_ONLY_USER_FAILURES: only user username (AXES_USE_USER_AGENT has no effect).

  3. AXES_LOCK_OUT_BY_COMBINATION_USER_AND_IP: use username and IP address.

The AXES_USE_USER_AGENT setting can be used with username and IP address or just IP address monitoring, but does nothing when the AXES_ONLY_USER_FAILURES setting is set.

Configuring reverse proxies

Axes makes use of django-ipware package to detect the IP address of the client and uses some conservative configuration parameters by default for security.

If you are using reverse proxies, you will need to configure one or more of the following settings to suit your set up to correctly resolve client IP addresses:

  • AXES_IPWARE_PROXY_COUNT: The number of reverse proxies in front of Django as an integer. Default: None

  • AXES_IPWARE_META_PRECEDENCE_ORDER: The names of request.META attributes as a tuple of strings to check to get the client IP address. Check the Django documentation for header naming conventions. Default: IPWARE_META_PRECEDENCE_ORDER setting if set, else ('REMOTE_ADDR', )

Note

For reverse proxies or e.g. Heroku, you might also want to fetch IP addresses from a HTTP header such as X-Forwarded-For. To configure this, you can fetch IPs through the HTTP_X_FORWARDED_FOR key from the request.META property which contains all the HTTP headers in Django:

# refer to the Django request and response objects documentation
AXES_IPWARE_META_PRECEDENCE_ORDER = [
    'HTTP_X_FORWARDED_FOR',
    'REMOTE_ADDR',
]

Please note that proxies have different behaviours with the HTTP headers. Make sure that your proxy either strips the incoming value or otherwise makes sure of the validity of the header that is used because any header values used in application configuration must be secure and trusted. Otherwise the client can spoof IP addresses by just setting the header in their request and circumvent the IP address monitoring. Normal proxy server behaviours include overriding and appending the header value depending on the platform. Different platforms and gateway services utilize different headers, please refer to your deployment target documentation for up-to-date information on correct configuration.

Configuring handlers

Axes uses handlers for processing signals and events from Django authentication and login attempts.

The following handlers are implemented by Axes and can be configured with the AXES_HANDLER setting in project configuration:

  • axes.handlers.database.AxesDatabaseHandler logs attempts to database and creates AccessAttempt and AccessLog records that persist until removed from the database manually or automatically after their cool offs expire (checked on each login event).

  • axes.handlers.cache.AxesCacheHandler only uses the cache for monitoring attempts and does not persist data other than in the cache backend; this data can be purged automatically depending on your cache configuration, so the cache handler is by design less secure than the database backend but offers higher throughput and can perform better with less bottlenecks. The cache backend should ideally be used with a central cache system such as a Memcached cache and should not rely on individual server state such as the local memory or file based cache does.

  • axes.handlers.dummy.AxesDummyHandler does nothing with attempts and can be used to disable Axes handlers if the user does not wish Axes to execute any logic on login signals. Please note that this effectively disables any Axes security features, and is meant to be used on e.g. local development setups and testing deployments where login monitoring is not wanted.

To switch to cache based attempt tracking you can do the following:

AXES_HANDLER = 'axes.handlers.cache.AxesCacheHandler'

See the cache configuration section for suitable cache backends.

Configuring caches

If you are running Axes with the cache based handler on a deployment with a local Django cache, the Axes lockout and reset functionality might not work predictably if the cache in use is not the same for all the Django processes.

Axes needs to cache access attempts application-wide, and e.g. the in-memory cache only caches access attempts per Django process, so for example resets made in the command line might not remove lock-outs that are in a separate process’s in-memory cache such as the web server serving your login or admin page.

To circumvent this problem, please use somethings else than django.core.cache.backends.dummy.DummyCache, django.core.cache.backends.locmem.LocMemCache, or django.core.cache.backends.filebased.FileBasedCache as your cache backend in Django cache BACKEND setting.

If changing the 'default' cache is not an option, you can add a cache specifically for use with Axes. This is a two step process. First you need to add an extra cache to CACHES with a name of your choice:

CACHES = {
    'axes': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    }
}

The next step is to tell Axes to use this cache through adding AXES_CACHE to your settings.py file:

AXES_CACHE = 'axes'

There are no known problems in e.g. MemcachedCache or Redis based caches.

Configuring authentication backends

Axes requires authentication backends to pass request objects with the authentication requests for performing monitoring.

If you get AxesBackendRequestParameterRequired exceptions, make sure any libraries and middleware you use pass the request object.

Please check the integration documentation for further information.

Configuring 3rd party apps

Refer to the integration documentation for Axes configuration with third party applications and plugins such as

  • Django REST Framework

  • Django Allauth

  • Django Simple Captcha