How to handle errors when using PasswordResetConfirmView - django

I am using django.auth.contrib as my session based authentication framework.
I have successfully implemented a reset password feature via PasswordResetConfirmView which requires a valid token sent to a user's email to set a new password.
path('password_reset/confirm/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(
template_name='accounts/password_reset/password_reset_confirm.html'),
name='password_reset_confirm'),
This works fine if the token is valid. However, if the token is not valid (e.g. incorrect or expired), then I predictably get an error:
Reverse for 'password_reset_confirm' with arguments '('', '')' not
found. 1 pattern(s) tried:
['accounts/password_reset/confirm/(?P[^/]+)/(?P[^/]+)/$']
What's the best practice to handle this exception for the user? Ideally I want to catch it and intercept it with "Sorry, your token is invalid." Is there an existing way to do this within the django.contrib.auth framework? Looking for the best DRY approach.
Edit I am already using the validlink context in the template. The error appears to be prior to this:
{% block content %}
<h1>{{ title }}</h1>
{% if validlink %}
<p>Please enter your new password twice so we can verify you typed it in correctly.</p>
<form method="post">{% csrf_token %}
<fieldset>
<div>
{{ form.new_password1.errors }}
<label for="id_new_password1">New password:</label>
{{ form.new_password1 }}
</div>
<div>
{{ form.new_password2.errors }}
<label for="id_new_password2">Confirm password:</label>
{{ form.new_password2 }}
</div>
<input type="submit" value="Change my password">
</fieldset>
</form>
{% else %}
<p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
{% endif %}
{% endblock %}

Related

Can't create DJANGO login form, that accepts either username or email

I am trying to create a login form in django that accepts either username or email. I made custom authentication backend and it does work. Problem is in HTML input type. The form method is POST and i did write csrf_token tag, but if i set input type to text, than when i try to login with username everything works, but when i put email in it, i get an error: CSRF verification failed. Request aborted. And if i set type to email, than i can't put username in. My django version is 4.0.6 and python version is 3.10.4
Add this in urls.py file
path('', include('django.contrib.auth.urls')),
Add this in your HTML template
{% extends 'registration/base.html' %}
{% block title %} Login {% endblock title %}
{% load crispy_forms_tags %}
{% block body %}
<h4>Hello! let's get started</h4>
<h6 class="font-weight-light">Sign in to continue.</h6>
<form class="pt-3" method="post">
{% csrf_token %}
{{ form|crispy }}
<div class="mt-3">
<button class="btn btn-block btn-primary btn-lg font-weight-medium auth-form-btn">SIGN IN</button>
</div>
<div class="my-2 d-flex justify-content-between align-items-center">
<div class="form-check">
<label class="form-check-label text-muted">
<input type="checkbox" class="form-check-input"> Keep me signed in </label>
</div>
Forgot password?
</div>
<div class="text-center mt-4 font-weight-light">
</div>
</form>

link to django password reset not displaying

the link to password reset is not showing
console output of password reset
Hi there, Someone asked for a password reset for the email
address root#gmail.com, Follow the link below: http://127.0.0.1:8000 {% url
'password_reset_confirm' uidb64=uid token=token %}
HTML FILES
password_reset.html
<form action="" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="send password reset email" name="submit" />
</form>
password_reset_email.html
Hi there, Someone asked for a password reset for the email
address {{ email }}, Follow the link below: {{ protocol }}://
{{ domain}} {% url'password_reset_confirm' uidb64=uid token=token %}
password_reset_confirm.html
<div>
{% if validlink %}
<h2>change password for 0{{ form.user.username }}</h2>
<form action="" method="POST" novalidate>
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="changepassword" name="submit" />
</form>
{% else %}
<h3>Reset your password</h3>
<p>it looks like you clicked on an invalid passowrd reset link try again</p>
Request
{% endif %}
</div>
settings.py
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
acoounts/urls.py
path("accounts/", include("django.contrib.auth.urls")),
Please check the following things.
{{ protocol }}://{{ domain}} {% url'password_reset_confirm' uidb64=uid token=token %}
Remove the space between {{ domain}} {% url''}
Check that your email template is getting value for protocol and domain
Inspect in the email and check what is the final link is.
I faced the same problem, all I had to do was put the code on the same line.
{{ protocol }}://{{ domain }}{% url "password_reset_confirm" uidb64=uid token=token %}
Make sure the code is not broken into a new line.
http://127.0.0.1:8000/accounts/password_reset/
Try this
you just have to add the URL which is link to login .

django password change completion fails

I have almost implemented the password reset process, but when I validate the password change I don't end up on the reset complete template and get the template says:
The password reset link was invalid...
However, the password change has been made and can log in with the new password. It looks the redirection is wrong but I can't figure out why.
Here is my urls.py:
path('reset/<uidb64>/<token>', auth_views.PasswordResetConfirmView.as_view(
template_name='news/user/password_reset_confirm.html',
success_url='../password-change/done'), name='password_reset_confirm'),
path('password-change/done', auth_views.PasswordResetCompleteView.as_view(template_name='news/user/password_reset_complete.html'), name='password_change_done'),
Here is my template:
{% block content %}
{% if validlink %}
<p>Please enter your new password twice so we can verify you typed it in correctly.</p>
<form method="post">{% csrf_token %}
<fieldset class="module aligned">
<div class="form-row field-password1">
{{ form.new_password1.errors }}
<label for="id_new_password1">New password:</label>
{{ form.new_password1 }}
</div>
<div class="form-row field-password2">
{{ form.new_password2.errors }}
<label for="id_new_password2">Confirm password:</label>
{{ form.new_password2 }}
</div>
<input type="submit" value="Change my password">
</fieldset>
</form>
{% else %}
<p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
{% endif %}
{% endblock %}
You're missing a final slash on the password_reset_confirm path, which is causing your POST to go to the wrong place. It should be:
path('reset/<uidb64>/<token>/', ...
Note that your success_url is also probably wrong, I doubt that .. will work the way you think it will.

Django login not showing errors

I know there are multiple questions like this around, but none of them contain a clear answer. I am using the default authentication from Django, but have trouble displaying something like 'Your username/password combination is incorrect'. Is it possible to fix this without making a custom view function?
My urls.py looks like this:
url(r'^login/$', auth_views.login, {'template_name': 'login.html'},
name='mysite_login')
Then my login.html has the following code:
{% block content %}
<section class="content">
<div class="container block">
<div class="row">
<div class="col-md-12"></div>
<form action="{% url 'mysite_login' %}" class="form-control" method="post" accept-charset="utf-8">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field|addcss:'form-control' }}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text|safe }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit" class="btn btn-dark">Login</button>
<input class="form-control" type="hidden" name="next" value="{{ next }}"><br>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
So this all works, except for displaying the error messages. I've seen answers where you can write a custom view function and form to fix this, but I assume it should be also possible while using the build-in login functionality right? Thanks a lot.
The built-in login form doesn't display errors at an individual field level; it's a security risk to say that just the password is wrong, because it confirms the existence of a particular username. So the errors are raised in the general clean() method and are displayed in the template via {{ form.non_field_errors }}.

NoReverseMatch on django generated views

I'm trying to create the views for all the authentication process in Django, but I have an issue with the reverse url tag in the views.
I have :
urls.py
url('^v1/back/', include('django.contrib.auth.urls'))
login.html
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<form method="post" action=".">
{{ form.as_p }}
<input type="submit" value="{% trans 'Log in' %}" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
<p>{% trans "Forgot password" %}? {% trans "Reset it" %}!</p>
<p>{% trans "Not member" %}? {% trans "Register" %}!</p>
{% endblock %}
And when I access localhost:8000/v1/back/login/ i have:
NoReverseMatch at /v1/back/login/
Reverse for 'django.contrib.auth.views.auth_password_reset' with
arguments '()' and keyword arguments '{}' not found. 0 pattern(s)
tried: []
The thing is, as, you can see, i try putting the complete path, it still does not work.
When I try to access another view like password change, it redirects me to :
http://192.168.56.103:8000/accounts/login/?next=/v1/back/password_change/
Which obviously does not work, and when i access password reset :
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<form method="post" action=".">
{{ form.as_p }}
<input type="submit" value="{% trans 'Submit' %}" />
</form>
{% endblock %}
It has the django admin look and feel instead on my base.html.
I'm guessing there are lots of problem here, I'm trying to solve them one by one, but i don't know what i've done wrong on the url part.
Don't know if this is relevant, but a part of my application is served by Django Rest Framework, and i'm trying to put in place oAuth2.
The correct name for password reset is just password_reset, to reverse it use:
{% url 'password_reset' %}
To fix the login redirect, you have to adjust the LOGIN_URL in your settings.py
I suggest you remove the part regarding the template and post it as a separate question.