Users log in with their @europython.eu Google Workspace accounts via django-allauth.
Only @europython.eu emails are allowed — other domains see a friendly error page. On first login a Django user is created with is_staff=False, so they can log in but can't access protected pages until an admin promotes them in Django admin.
Protected views use a @staff_required decorator (core/auth.py) that checks both authentication and staff status.
- In Google Cloud Console, create an OAuth client ID (Web application) with redirect URI:
https://internal.europython.eu/accounts/google/login/callback/ - Set env vars on the server:
GOOGLE_OAUTH_CLIENT_ID=<your-client-id> GOOGLE_OAUTH_CLIENT_SECRET=<your-client-secret> - Deploy and run migrations (
make deploy/apphandles this)
Create a separate OAuth client with redirect URI http://localhost:4672/accounts/google/login/callback/ and add credentials to intbot/.env. Then run make migrate.
You can also skip this entirely — for daily usage create users via Django admin (/admin/), and in tests use force_login():
def test_products_page(self, client):
user = User.objects.create_user(username="test", is_staff=True)
client.force_login(user)
response = client.get("/products/")
assert response.status_code == 200Use is_staff=True to access @staff_required views, or omit it to test the non-staff redirect to /no-access/.
- Go to Django admin (
/admin/> Users) - Find the user and set Staff status to checked
- Save — the user can now access protected pages
core/auth.py—EuroPythonSocialAccountAdapter(domain restriction) andstaff_requireddecoratortemplates/account/login.html— login page with Google buttontemplates/no_access.html— shown to logged-in non-staff userstemplates/socialaccount/authentication_error.html— shown for non-europython.eu emails
Allauth config in intbot/settings.py:
SOCIALACCOUNT_ONLY = True— only social login, no username/passwordACCOUNT_EMAIL_VERIFICATION = "none"— Google already verifies emailsSOCIALACCOUNT_ADAPTER— points to our adapter that restricts to@europython.eu- Google credentials configured via env vars, no
SocialAppdatabase entries needed