dj-rest-auth limit social sign up to a specific email address domain

I’m getting started with dj-rest-auth and I have an app which allows user to only sign in via google. However, I want users to only be able to access my service with a specific google apps email domain.

I’m using dj-rest-auth in conjunction with django-allauth.

This is what I tried: I created allauth adapters like this:

class CustomAccountAdapter(DefaultAccountAdapter):
    def is_open_for_signup(self, request):
        return False  # No email/password signups allowed


class CustomSocialAccountAdapter(DefaultSocialAccountAdapter):
    def is_open_for_signup(self, request, socialaccount):
        u = socialaccount.user
        return u.email.split("@")[1] == "mydomain.com"

and in my settings I have

ACCOUNT_ADAPTER = "users.adapters.CustomAccountAdapter"
SOCIALACCOUNT_ADAPTER = "users.adapters.CustomSocialAccountAdapter"

With this solution, if the user tries to sign in with a valid email, everything works, whereas if they use a non-allowed email domain, I get this error in my console:

Traceback (most recent call last):
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/views/decorators/debug.py", line 89, in sensitive_post_parameters_wrapper
    return view(request, *args, **kwargs)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/dj_rest_auth/views.py", line 48, in dispatch
    return super(LoginView, self).dispatch(*args, **kwargs)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/rest_framework/views.py", line 505, in dispatch
    response = self.handle_exception(exc)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/rest_framework/views.py", line 465, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
    raise exc
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/rest_framework/views.py", line 502, in dispatch
    response = handler(request, *args, **kwargs)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/dj_rest_auth/views.py", line 138, in post
    self.serializer.is_valid(raise_exception=True)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/rest_framework/serializers.py", line 234, in is_valid
    self._validated_data = self.run_validation(self.initial_data)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/rest_framework/serializers.py", line 436, in run_validation
    value = self.validate(value)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/dj_rest_auth/registration/serializers.py", line 134, in validate
    complete_social_login(request, login)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/allauth/socialaccount/helpers.py", line 151, in complete_social_login
    return _complete_social_login(request, sociallogin)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/allauth/socialaccount/helpers.py", line 172, in _complete_social_login
    ret = _process_signup(request, sociallogin)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/allauth/socialaccount/helpers.py", line 38, in _process_signup
    return render(
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/shortcuts.py", line 19, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/base.py", line 170, in render
    return self._render(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/test/utils.py", line 96, in instrumented_test_render
    return self.nodelist.render(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/loader_tags.py", line 150, in render
    return compiled_parent._render(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/test/utils.py", line 96, in instrumented_test_render
    return self.nodelist.render(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/loader_tags.py", line 62, in render
    result = block.nodelist.render(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/defaulttags.py", line 312, in render
    return nodelist.render(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/base.py", line 938, in render
    bit = node.render_annotated(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/base.py", line 905, in render_annotated
    return self.render(context)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/template/defaulttags.py", line 446, in render
    url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/urls/base.py", line 87, in reverse
    return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
  File "/home/my_user/.local/share/virtualenvs/my_project-mzTAT1MS/lib/python3.8/site-packages/django/urls/resolvers.py", line 685, in _reverse_with_prefix
    raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'account_login' not found. 'account_login' is not a valid view function or pattern name.
[17/Mar/2021 18:49:42] "POST /dj-rest-auth/google HTTP/1.1" 500 246781

What I would like to do is for my django app to send a 403 response to the user (or similar) with a message like “You can only access this service with an [at] whatever email address”. I’m trying to figure out at which point the dj-rest-auth views call the user adapters and what to do to handle the failure and achieve what I’m after.

I appreciate any guidance.

Answer

When you return is_open_for_signup==False, internally django-allauth returns a template:

if not get_adapter(request).is_open_for_signup(request, sociallogin):
        return render(
            request,
            "account/signup_closed." + account_settings.TEMPLATE_EXTENSION,
        )

That template extends a template account/base.html (inside django-allauth project) and in this template you have the problematic URL defined <li><a href="{% url 'account_login' %}">Sign In</a></li>

You can override your signup_closed.html template and solve this error, but if you need to return a Json (because of the API), you should use your own implementation of django-allauth.

Leave a Reply

Your email address will not be published. Required fields are marked *