I recently started a Django project that used
django-allauth to perform authentication based on Google accounts. One problem I encountered was how to limit who can actually log into the site. I didn’t want anyone with a Google account to be able to log in!
Google’s API does have provisions to limit only certain users from passing the authentication, but it only works during the testing phase of your API. The feature wasn’t meant for production, and is limited to 100 users. On top of that, I wanted my Google API to be a set-and-forget experience. I didn’t want the inconvenience of having to log into my Google API console just to allow a new user — there had to be a way to do it on the Django side.
The solution wasn’t that complicated at all, and I wanted to share it here in case it helps anyone else.
settings.py, add a line for
# ... all your other settings.py stuffALLOWED_EMAILS=[
Basically, all you want to do is check the
request.user.email against this list.
How I chose to implement it:
It’s probably easier to digest from bottom-to-top. The
@user_passes_test(email_check) decorator will only allow users whose emails match ALLOWED_EMAILS to view the
index view. Otherwise, it kicks the user back to the
login view (more on that in a second).
email_check function basically returns
true is the email is found in the list, and returns
false otherwise. The split up
false statements was just to make it more readable for myself. If the user is anonymous, then they won’t have
user.email and so I’m trying to catch that case before a “field does not exist” error is thrown. There are probably more Pythonic ways to do it — feel free to tell me yours in the comments!
login() view has to catch the user if they got bounced by another view (such as
index). If the user got bounced back to the
login view by the
@user_passes_test(email_check) decorator, then they are “authenticated” (as far as Google OAuth and Django session cookies are concerned), but they are not allowed based on their email — so we generate a
messages.error() to let them know. In any case (authenticated-but-bounced, or not authenticated at all), we render the
login.html page with a “Login with Google” button.
I hope this helps somebody! Feel free to share any improvements or corrections in the comments!