Ben
Ben

Reputation: 4120

Django Rest Auth custom reset password confirm url

With django-rest-framework, when you post a reset password (rest-auth/password/reset/), there is an email send to the user email. This email contains a confirmation URL. I would like to change this url because I'm on a REST app case, I want this email to point on my frontend instead of the django backend.

With the confirmation email case, I had to override get_email_confirmation_url method from the AccountAdapter. But with the reset password case, I have no clue how to do it (there is no method in the adapter about reseting password).

Any idea?

Upvotes: 5

Views: 2567

Answers (3)

Zain Tanveer
Zain Tanveer

Reputation: 79

You can leverage the PASSWORD_RESET_USE_SITES_DOMAIN setting in your dj_rest_auth configuration.

REST_AUTH = {
    "PASSWORD_RESET_USE_SITES_DOMAIN": True,
}

By default, this option is set to False. However, when set to True, the password_reset_url is generated from the Site model within django.contrib.sites, fetching the domain from the SITE_ID setting defined in your project root settings.

You can create a new Site object with the domain pointing to your frontend domain. Ensure to set SITE_ID=<your-id> in your project root settings accordingly.

SITE_ID = 2

Note: Additionally, it's imperative to set SITES_ENABLED = True. Failure to do so while PASSWORD_RESET_USE_SITES_DOMAIN is enabled will result in the following error:

ImproperlyConfigured(
    "Passing `request=None` requires `sites` to be enabled."
)

To fully utilize dj_rest_auth with minimal customization and relying on its configuration, follow these steps:

  1. Define Password Reset URL in urls.py: Ensure your project's urls.py includes a password reset URL with a specific path pattern <URL>/<uidb64>/<token>/. You can name the URL whatever you want, but the name argument of the path must be set exactly to "password_reset_confim`.
   path(
     "password/reset/confirm/<uidb64>/<token>/",
     PasswordResetConfirmView.as_view(),
     name="password_reset_confirm",
   )

Here, URL represents your desired route, typically used by your frontend. The password_reset_confirm in the path is crucial for reversing this URL.

  1. Example URL Structure: Assuming password/reset/confirm is your URL, your final password_reset_url will resemble:
http://frontend.com/password/reset/confirm/7/uye27829398298/

frontend.com is site domain fetched from Site model. It added the protocol all by itself.

With this setup, you are good. You can set these settings in production environment.

For streamlining this process, consider automating the creation of the site object using a custom app command. Assuming you have an environment variable FRONTEND_URL='http://myfrontend.com', you can create a command like so

from django.core.management.base import BaseCommand
from django.contrib.sites.models import Site
from django.conf import settings
from urllib.parse import urlparse

class Command(BaseCommand):
    help = "Creates a new site with the specified domain"

    def handle(self, *args, **options):
        domain = urlparse(settings.FRONTEND_URL).netloc
        site, _ = Site.objects.get_or_create(id=settings.SITE_ID)
        site.domain = domain
        site.name = domain
        site.save()
        self.stdout.write(self.style.SUCCESS(f'Site "{domain}" created successfully.'))

.netloc method will get you domain along with. Its good for developemnt if you have port in FRONTEND_URL. http://localhost:3000 will resolve to localhost:3000

Assuming you created this command in your accounts/management/commands/create_site.py. Here accounts is the application name. You can run the following command.

python manage.py create_site

Upvotes: 0

cRim
cRim

Reputation: 31

I found that If you are using the dj-rest-auth and you want your reset password link to point to the frontend you can use the following setting

In the settings file.

REST_AUTH = {
    'PASSWORD_RESET_USE_SITES_DOMAIN': True,
}

Based on https://dj-rest-auth.readthedocs.io/en/latest/configuration.html

Upvotes: 3

Ben
Ben

Reputation: 4120

I did it with templatetags: https://docs.djangoproject.com/fr/1.10/howto/custom-template-tags/

My templatetags file (e.g. settings_vars.py):

from django import template
from django.conf import settings

register = template.Library()

@register.simple_tag
def get_settings_var(name):
    return getattr(settings, name)

My variable in my settings.py:

FRONTEND_URL = 'http://localhost:4200/'
ACCOUNT_EMAIL_CONFIRMATION_URL = FRONTEND_URL + 'verify-email/{}'
ACCOUNT_PASSWORD_RESET_CONFIRM = FRONTEND_URL + 'password-reset/confirm/'

Usage in my password_reset_email.html:

{% load settings_vars %}

{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{% get_settings_var 'ACCOUNT_PASSWORD_RESET_CONFIRM' %}?uidb64={{ uid }}&token={{ token }}
{% endblock %}

If someone know a better solution feel free to comment.

Hope it can helps someone.

Upvotes: 4

Related Questions