djangodjango-two-factor-auth

Django 2FA works locally but fails (silently) on server


The Problem

I need to implement two-factor authentication for a Django project. I am using Django Two-Factor Authentication which works just fine locally both with Google Authenticator and our SMS gateway. The issue occurs when I publish the app to the test server. The login works as normal but when I fill in the token it will simply redirect me back to the initial login step to fill in my credentials again. It does not give me any error messages in the UI and, as far as I can see, none in the logs either.

Don't know if it's relevant, but the app is running as a Docker Swarm service on the server.

What I have tried

Due to the lack of feedback and knowledge of the 2FA library as well as the OTP-library I don't really know where to start. I'm pretty sure the settings are as good as identical between my local machine and the test environment. The package versions are the same. I even made sure the time and time zones are identical between my machine and the server.

Looking in the database in the tables for the OTP library the failure count is 0 and last_t is incrementing every time I try to log in. This tells me that the token itself is verified, as per the Django-OTP documentation:

BigIntegerField: The time step of the last verified token. To avoid verifying the same token twice, this will be updated on each successful verification. Only tokens at a higher time step will be verified subsequently. (Default: -1)


Any suggestions are much appreciated. I know I haven't provided much concrete details of my exact implementation, but I am hoping that someone might have some general idea of what the problem might be. Anyway let me know if you need something more concrete.

Thanks,

niknoe

Edit 1

I was wrong, there was actually something in the logs I didn't see before:

Requested step 'token' is no longer valid, returning to last valid step in the wizard.

So maybe this can indicate that I have some drift causing token to be invalid?

Versions are

I'll try to include the relevant code

My settings.py is divided into environment settings that each settings.base.py. All the relevant code for 2FA is in settings.base.py:

ISTALLED_APPS = [
    ...
    'django_otp',
    'django_otp.plugins.otp_static',
    'django_otp.plugins.otp_totp',
    'two_factor'
]

MIDDLEWARE = [
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django_otp.middleware.OTPMiddleware',
    ...
]

LOGIN_URL = 'two_factor:login'

# Not sure if these are relevant
TIME_ZONE = 'Europe/Oslo'

USE_I18N = True

USE_L10N = True

USE_TZ = True

This is basically all I have added in order to make it work locally on my machine.


Solution

  • The discovery of the log line in my update gave me something to google and I found this: https://github.com/Bouke/django-two-factor-auth/issues/65#issuecomment-57931565

    So what happens is that browser asks for favicon.ico which was not listed in my login exempt urls so the request was redirected to the login page which invalidated the initial login that was on the actual screen.

    No idea why that didn't happen locally, but probably something with the dev server... Anyway it's working now!