We couldn’t sign you in. Too many failed login attempts. Try again later

I’m reposting this from the original that i posted on 8-April-2024 as it went unanswered, and i semi-regularly run into this issue on new installations.

Following a fresh installation of Redwood I’m unable to sign-in, and it appears that this might be due to more than one configuration error on my part, hence this post. I get the response, “We couldn’t sign you in. Too many failed login attempts. Try again later.” on any and all attempts to sign-in.

More diagnostics:

  1. I see this message in the javascript console for the default mfe sign-in page:
Module configuration error: SESSION_COOKIE_DOMAIN is required by ProcessEnvConfigService.

I’ve verified that SESSION_COOKIE_DOMAIN is correctly set in the lms/cms settings, so apparently i’m supposed to be passing this value from there to somewhere else?

  1. http GET requests to ´/authn/login´ result in a pair of 401 responses from /login_refresh/
  2. I see a POST to login_session that returns a 403. However, i can navigate to this page in my browswer, which returns a JSON-formatted dump of benign user configuration information (see below)

Here’s the complete js console output that I see when i navigate to the sign-in page.

And this is the page output for /login_session/

Hi @lpm0073!
Have you checked the ENABLE_MAX_FAILED_LOGIN_ATTEMPTS, MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED and MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS settings? They control the number of failed login attempts in the backend.

I had this issue once, and it turned out Redis was unreachable which caused it. Many other factors could cause the login attempt count to be incorrect.

Thanks for the suggestion. Interestingly, third party oauth works fine, so the problem seems specific to the email/password fields in the auth mfe reactapp.

I ran into this same problem again, this time on a Redwood upgrade for a platform that previously had not been using the auth MFE, which I’m only mentioning because the login page is the first (but not necessarily the only) place where this problem surfaces. I see the following two log entries on each attempt:

2025-03-06 12:01:06,865 INFO 10 [tracking] [user None] [ip 189.203.193.201] logger.py:41 - {"name": "/api/user/v2/account/login_session/", "context": {"user_id": null, "path": "/api/user/v2/account/login_session/", "course_id": "", "org_id": "", "enterprise_uuid": ""}, "username": "", "session": "7353a9aa40dd95b8cac01972924fada0", "ip": "189.203.193.201", "agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", "host": "staging.madrasafree.com", "referer": "https://apps.staging.madrasafree.com/", "accept_language": "es-MX,es;q=0.9,en-US;q=0.8,en;q=0.7,es-US;q=0.6,es-419;q=0.5", "event": "{\"GET\": {}, \"POST\": {\"email_or_username\": [\"lpm0073@gmail.com\"], \"next\": [\"/\"], \"password\": \"********\"}}", "time": "2025-03-06T12:01:06.864890+00:00", "event_type": "/api/user/v2/account/login_session/", "event_source": "server", "page": null}
2025-03-06 12:01:07,013 WARNING 10 [django.security.csrf] [user None] [ip 189.203.193.201] log.py:241 - Forbidden (CSRF token from the 'X-Csrftoken' HTTP header incorrect.): /api/user/v2/account/login_session/

RESOLUTION. The following two tutor settings changes solved this problem for me.

tutor config save --set OPENEDX_CSRF_COOKIE_DOMAIN=.example.com
tutor config save --set OPENEDX_CSRF_COOKIE_NAME=native-csrf-cookie

This is based on the following Django documentation,

If the CSRF_COOKIE_DOMAIN setting is set, the referer is compared against it. You can allow cross-subdomain requests by including a leading dot. For example, CSRF_COOKIE_DOMAIN = '.example.com' will allow POST requests from www.example.com and api.example.com. If the setting is not set, then the referer must match the HTTP Host header.

Additionally, they mention that,

Expanding the accepted referers beyond the current host or cookie domain can be done with the CSRF_TRUSTED_ORIGINS setting.

tutor (or openedx) set defaults for this, but this setting alone does not appear to be sufficient in all cases:

CSRF_TRUSTED_ORIGINS = ['https://example.com', 'apps.example.com']