Skip to content

reCAPTCHA

The login, signup and password reset request forms are protected by Google reCAPTCHA v3 through django-recaptcha.

reCAPTCHA v3 is invisible: there is no checkbox and no challenge. On submit, a Google script attaches a single-use token to the form; the server asks Google for the token's score (0.0 = bot, 1.0 = human) and rejects the form with an error message when the score is below RECAPTCHA_REQUIRED_SCORE, or when the token is missing (script blocked or not loaded).

The captcha is disabled when RECAPTCHA_PUBLIC_KEY is empty: the field is not added to the forms, so local development and the test suite need neither keys nor network. The same holds in production - without keys, the forms work unprotected.

Not covered: the MFA step, the reset link received by email, the signup that follows a Google or Microsoft login, and the anonymous questionnaire.

Creating the key

  1. Open the Google Cloud Console and select the project that already holds the OAuth credentials (see Authentication and Google OAuth).
  2. Go to Security → reCAPTCHA (also labelled Fraud Defense), tab Keys, and click Create key.
  3. Fill in the form:
    • a display name, e.g. sad-pulm;
    • application type Web;
    • the domain list: sad-pulm.he-arc.ch, plus localhost to try the key locally;
    • key type Score-based (the default);
    • leave the testing purposes only toggle off.
  4. Click Create. The key ID shown is the site key (public).
  5. Open Key details → Integration → Use legacy key to get the secret key.

Configuring the project

On the server, in .envs/.production/.django:

RECAPTCHA_PUBLIC_KEY=the-site-key
RECAPTCHA_PRIVATE_KEY=the-legacy-secret-key
RECAPTCHA_REQUIRED_SCORE=0.5

Then redeploy. RECAPTCHA_REQUIRED_SCORE is optional and defaults to 0.5; raise it to be stricter, lower it if legitimate users get rejected.

Warning

.envs/.local/.django is tracked by git. To try the captcha locally, put the keys there, but never commit them. The test suite is unaffected: config/settings/test.py empties the keys.

Quota and monitoring

The first 10,000 verifications per month are free; billing only starts beyond that. The Google Cloud Console shows, per key, the number of verifications and the score distribution for each action (login, signup, password_reset) - look there before changing the threshold.

Admin login

The Django admin has its own login form, which carries no captcha. In production, set

DJANGO_ADMIN_FORCE_ALLAUTH=True

so that /<DJANGO_ADMIN_URL>/ redirects to the allauth login page and admins go through the same captcha, rate limits and MFA as everyone else.

Templates

  • sad_pulm/templates/account/snippets/recaptcha_notice.html - the "protected by reCAPTCHA" notice shown under the forms. Google requires it because the floating badge is hidden (.grecaptcha-badge in frontend/src/scss/styles.scss).
  • sad_pulm/templates/allauth/elements/form.html - allauth's form element, overridden to append the notice to every form that carries the captcha field.