birdy
birdy

Reputation: 9646

NoReverseMatch at /rest-auth/password/reset/

I have a django application with an angular front-end. When from the front-end I try to send a request for passwordReset, I get the following error:

Reverse for 'password_reset_confirm' with arguments '()' and keyword arguments '{u'uidb64': 'MTE', u'token': u'3z4-eadc7ab3866d7d9436cb'}' not found. 0 pattern(s) tried: []

Its a POST request going to http://127.0.0.1:8080/rest-auth/password/reset/

Following is what my urls.py looks like:

from django.conf.urls import patterns, include, url
from django.contrib import admin

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^rest-auth/', include('rest_auth.urls')),
    url(r'^rest-auth/registration/', include('rest_auth.registration.urls')),
    url(r'^account/', include('allauth.urls'))
)

Upvotes: 32

Views: 16525

Answers (12)

Dibya Darshan Khanal
Dibya Darshan Khanal

Reputation: 65

In your views.py, if you have set a token, pass it along with the path similar to:

path('resetpassword_validate/<uidb64>/<token>/', views.resetpassword_validate, name='resetpassword_validate'),

Upvotes: 0

ur0dead
ur0dead

Reputation: 11

Well I was also facing this problem. Every time I entered my email and pressed the button it took me to NoReverseMatch url, and I am using:

re_path(r'^password-reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
TemplateView.as_view(template_name="password_reset_confirm.html"),name='password_reset_confirm')

(url is not used to match regex in django anymore re_path is used)

My solution is to change the regex a little bit because the "csrf token" is longer than 20 words – that's why I was getting an error and you should try the same.

re_path(r'^password-reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,40})/$',
TemplateView.as_view(template_name="password_reset_confirm.html"),
name='password_reset_confirm')

You can either use + (in regex it means one or more) or {1,40} (in regex it means match from 1 to 40)

Upvotes: 1

educolo
educolo

Reputation: 894

I have a headless backend, so adding or renaming URLs only for this was not a good option. The issue is on the email template, you can override it. Just take care that you have the correct path on the settings. In my case I have all this logic inside users app. So I have something like this.

users/templates/registration/password_reset_email.html

Inside this template I have a new custom message without the reverse URL call. If you need more than just override the template, or maybe you need to send additional data to the template. You must override the serializer also. To do that you have to create your new serializer

from dj_rest_auth.serializers import PasswordResetSerializer as RestPasswordResetSerializer


class PasswordResetSerializer(RestPasswordResetSerializer):

    def get_email_options(self):
        return {
            'html_email_template_name': 'registration/password_reset_email_html.html',  # if you want to use an HTML template you can declare here
            'extra_email_context': {'custom_key': 'custom value for my template',}
        }

and add to settings.

REST_AUTH_SERIALIZERS = {
    'PASSWORD_RESET_SERIALIZER':'path.to.PasswordResetSerializer'
}

On the serializer you can add custom validation if needed also.

Upvotes: 0

Hatim
Hatim

Reputation: 447

I resolved this issue by moving these:

path('reset_password/', auth_views.PasswordResetView.as_view(), name='password_reset'),
path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
path('reset_password_sent/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
path('reset_password_complete/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),

from accounts/urls.py to yourProjectName/urls.py.

I guess that path('', include("accounts.urls")), was causing the problem.

Upvotes: 0

Sureshbabu E
Sureshbabu E

Reputation: 91

For those who are still struggling with this issue, I found that the reverse look up internal view looks for reverse lookup within the core project urls and not within any application. It could work within application with some tweak, but I am not sure. But it works creating the reset urls directly on core project urls.py

{
    path(r'password_reset/', PasswordResetView.as_view(template_name='password_reset_form.html'), name='password_reset'),
    path(r'password_reset_done/', PasswordResetDoneView.as_view(template_name='password_reset_done.html'), name='password_reset_done'),
    path(r'password_reset_confirm/<uidb64>/<token>/', PasswordResetConfirmView.as_view(template_name='password_reset_confirm.html'), name='password_reset_confirm'),
    path(r'password_reset_complete/', PasswordResetCompleteView.as_view(template_name='password_reset_complete.html'), name='password_reset_complete'),
}

Upvotes: 1

yrekkehs
yrekkehs

Reputation: 797

My solution was to override the email template that calls the reverse of "password_reset_confirm". Make sure email template sends a URL to your frontend app with the UID and Token in the URL (instead of trying to reverse "password_reset_confirm").

Your frontend's route should take the URL, parse it and then with the updated user's password and send it back as an API call to your backend to confirm.

Upvotes: 0

Diesel
Diesel

Reputation: 5375

Check out the FAQ: It explains this error and how to fix it. It references you to the demo program which contains:

# this url is used to generate email content
url(r'^password-reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
    TemplateView.as_view(template_name="password_reset_confirm.html"),
    name='password_reset_confirm'),

Upvotes: 0

Vitali Kaspler
Vitali Kaspler

Reputation: 1420

As Roar Skullestad pointed out, the problem is with the default email template, which tries to resolve URL by reversing viewname "password_reset_confirm", which is undefined.

It is enough to register a viewname "password_reset_confirm" with a custom route and then default email template rendering will work fine.

You can register viewname with custom route by adding a path to urls.py:

urlpatterns = [
    ...,
    path('password-reset/<uidb64>/<token>/', empty_view, name='password_reset_confirm'),
]

password-reset - custom route that password reset confirmation view. If you have SPA (Angular) - it will be the URL of your SPA view (such as the route to Angular component) that will handle the password reset.

This is the URL that will be resolved and embedded in the email. For this example it will be something like:

http://my-spa.com/app-name/password-reset/Nw/51v-490d4b372ec930e49049/

empty_view - in case of SPA (Angular), you don't really need server-side implementation, because the front end will actually handle this route. I used this implementation of a view, but it can be anything else:

from django.http import HttpResponse

def empty_view(request):
    return HttpResponse('')

And since I'm using Angular, this is the route for my Angular component:

{
    path: 'password-reset/:uid/:token',
    component: PasswordRecoveryComponent
}

Upvotes: 20

bahmsto
bahmsto

Reputation: 43

@AbimaelCarrasquillo's solutions works but you probably do not want to expose those endpoints as @dpstart mentioned in the comments.

I solved this by overriding the PasswordResetSerializer of rest-auth and simply replacing the reset form:

password_reset_form_class = PasswordResetForm

from the internal django.contrib.auth.forms.PasswordResetForm to allauth.account.forms.ResetPasswordForm

Make sure to add the following to your settings:

REST_AUTH_SERIALIZERS = {
    'PASSWORD_RESET_SERIALIZER':'path.to.PasswordResetSerializer'
}

Upvotes: 3

Add this to your project url.py file

url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
url('', include('social.apps.django_app.urls', namespace='social')),

Upvotes: 0

Abimael Carrasquillo
Abimael Carrasquillo

Reputation: 547

I also was having this problem, and found this github issue it said we need to add

url(r'^', include('django.contrib.auth.urls')),

on the urlpatterns.

As stated there it says that The PasswordReset view depends on django.contrib.auth.views.password_reset_confirm view.

Upvotes: 49

Roar Skullestad
Roar Skullestad

Reputation: 2437

For me the problem was this line in site-packages/django/contrib/admin/templates/registration/password_reset_email.html:

{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

From what I understand the problem is caused by reverse lookup not working for this line in contrib/auth/urls.py:

    url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
    'django.contrib.auth.views.password_reset_confirm',
    name='password_reset_confirm'),

My (at least temporarily) solution was to override the template and hardcode the reverse lookup part of the url for the link in the email.

The path to the new template is specified in settings.py:

TEMPLATE_DIRS =(
    "/absolute/path/to/my/templates/directory",
)

Since I am using angular front end, I also changed the link so that it triggers password reset confirmation via the angular client:

{{ protocol }}://{{ domain }}/#/passwordResetConfirm/{{ uid }}/{{ token }}

Upvotes: 6

Related Questions