I am trying to implement a password reset on my Laravel 5.1 app. I have followed the docs (http://laravel.com/docs/5.1/authentication#resetting-passwords) to get this working. However whenever I click on my 'reset password' button on my /password/email/ no email is ever sent.
I have intentionally entered incorrect emails and I am getting the appropriate error however when I enter a correct email no email is sent and I get no type of message or any emails.
I have looked at my database and it does looks as though a password reset token being created, just no email is sent.
My email configuration is working properly as other parts of my application sends email properly, only this one section is not sending the emails. Any help will be appreciated as I do not what else to check.
Michael
routes.php:
`
// Password reset link request routes...
Route::get('password/email', ['as' => 'password/email', 'uses' => 'Auth\PasswordController#getEmail']);
Route::post('password/email', 'Auth\PasswordController#postEmail');
// Password reset routes...
Route::get('password/reset/{token}', 'Auth\PasswordController#getReset');
Route::post('password/reset', 'Auth\PasswordController#postReset');
password.blade.php:
<form id="contact-form" class="contact-section" method="POST" action="/password/email">
<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
<span class="pre-input"><i class="fa fa-envelope-o"></i></span>
<input class="name plain buffer" type="email" name="email" placeholder="Email" value="{{ old('email') }}">
<input id="send" class="plain button yellow" type="submit" value="Reset Password">
#foreach($errors->all() as $error)
<font size="3" color="red">{{ $error }}</font>
#endforeach
</form>
resources/views/emails/password.blade.php:
Click here to reset your password: {{ url('password/reset/'.$token) }}
Update
I have added a Log to the postEmail function.
public function postEmail(Request $request)
{
$this->validate($request, ['email' => 'required|email']);
$response = Password::sendResetLink($request->only('email'), function (Message $message) {
$message->subject($this->getEmailSubject());
Log::info('Password Reset Execute -1 '); //Does work here
});
switch ($response) {
case Password::RESET_LINK_SENT:
return redirect()->back()->with('status', trans($response));
case Password::INVALID_USER:
return redirect()->back()->withErrors(['email' => trans($response)]);
}
Log::info('Password Reset Execute - 2'); //Will not work here
}
I added those in .env and password reseting is working again
MAIL_FROM_ADDRESS=xx#xx.xx
MAIL_FROM_NAME=xxxx
If the issue is invalid sender, make sure you pass the correct sender
$message->from('hello#app.com', 'Your Application');
Related
I have this function for registering users which is pretty much the default one but i added a token to be sent to an email so the user can activate the account, otherwise the user cant log in. So i tried to add a resend function so if the first time the email is not send they can resend manually, but that causes the 419 error Page Expired.
Register function
protected function create(array $data)
{
$user = Account::create([
'login' => $data['login'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
'verifyToken'=> Str::random(40),
'active' => (env('CONFIRM_EMAIL', true)) ? 0 : 1
]);
$thisUser = Account::findOrFail($user->id);
$this->sendEmail($thisUser);
return $user;
}
This is the function for resend
protected function resend(Request $request)
{
$user = Account::where('email', $request->input('email'))->first();
$user->verifyToken = Str::random(40);
$user->save();
$this->sendEmail($user);
return $user;
}
And i call it with this form
<form action=" {!! route('resendEmail') !!}" method="POST">
<fieldset class="youplay-input">
<input id="email" type="email" class="#error('email') is-invalid #enderror" placeholder="E-
mail" name="email" value="{{ old('email') }}" required autocomplete="email">
</fieldset>
<button class="btn btn-default db" type="submit" value="Submit">
Resend Verification Link
</button>
</form>
I have discussed this with a guy but we couldnt find a good solution: How to make resend email link function in Laravel
You are missing your csrf token in the form. After <form> tag add #csrf.
Example:
<form method="POST" action="/profile">
#csrf
</form>
https://laravel.com/docs/7.x/csrf
I am using laravel 6. I am trying to implement forgot password for my laravel project for the first time. I have customize the default design for login, forgot password, reset password pages. I have integrated mailtrap for sending email. I have successfully implemented flow like -
click forgot password link
get page on which user enters email and click to send reset link
gets the email of resetting link and data like email, token , created_at stores in password_reset table
on click of reset link page with token and email url gets open in new tab(open the page of reset password having email, new password, confirm password)
Further when I type new password and confirm password and click on Reset Password, nothing happens.
my reset.blade.php
<form id="sign_in" name="sign_in" method="POST" action="{{ route('password.update') }}" data-parsley-validate >
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<h1>Reset Password</h1>
<div class="col-md-12 col-sm-12 form-group has-feedback">
{{-- <label for="login_id"><span style="color:red;">*</span>Login ID</label> --}}
<input id="email" type="email" class="form-control has-feedback-left #error('email') is-invalid #enderror" placeholder="Email" name="email" value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus/>
<span class="fa fa-envelope form-control-feedback left" aria-hidden="true"></span>
#error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
<div class="col-md-12 col-sm-12 form-group has-feedback">
<input id="password" type="password" class="form-control has-feedback-left #error('password') is-invalid #enderror" placeholder="Password" name="password" required autocomplete="new-password" />
<span class="fa fa-pencil form-control-feedback left" aria-hidden="true"></span>
</div>
<div class="col-md-12 col-sm-12 form-group has-feedback">
<input id="password-confirm" type="password" class="form-control has-feedback-left" placeholder="Confirm Password" name="password_confirmation" required autocomplete="new-password" />
<span class="fa fa-pencil form-control-feedback left" aria-hidden="true"></span>
</div>
<button type="submit" class="btn btn-success">Reset Password</button>
</div>
<div class="clearfix"></div>
</form>
I have default controllers generated for auth like 'ConfirmPasswordController, ForgotPasswordController, ResetPasswordController, VerificationController'
ResetPasswordController
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Where to redirect users after resetting their password.
*
* #var string
*/
protected $redirectTo = '/dashboard';
}
I have used default route of auth like Auth::routes();
how the passwords reset in database in users table for email and token generated in password_reset table and how the message gets displayed that 'Password reset successfully? This is not working in my case.userstable not changing with new password and entry not gets removed frompassword_reset` table once the reset done successfully.
where and what changes I have to make to make this work? please guide. thanks in advance.
Password Reset in Laravel
Step 1 — Create a Route and a Controller
Create two routes, a controller, and methods through which the email address that requires a password reset will be submitted via the password reset form. The name of these routes, controllers, and methods is totally up to you.
Route::post('reset_password_without_token', 'AccountsController#validatePasswordRequest');
Route::post('reset_password_with_token', 'AccountsController#resetPassword');
Step 2— Change the action property on the default password reset form
<form method="POST" action="{{ url('/reset_password_without_token') }}">
The default password reset form can be found here:
resources/views/auth/passwords/email.blade.php
Step 3 — Create a token and Send Password Reset Link via email
Then add the validatePasswordRequest method in the AccountsController and use or modify the code below.
//You can add validation login here
$user = DB::table('users')->where('email', '=', $request->email)
->first();
//Check if the user exists
if (count($user) < 1) {
return redirect()->back()->withErrors(['email' => trans('User does not exist')]);
}
//Create Password Reset Token
DB::table('password_resets')->insert([
'email' => $request->email,
'token' => str_random(60),
'created_at' => Carbon::now()
]);
//Get the token just created above
$tokenData = DB::table('password_resets')
->where('email', $request->email)->first();
if ($this->sendResetEmail($request->email, $tokenData->token)) {
return redirect()->back()->with('status', trans('A reset link has been sent to your email address.'));
} else {
return redirect()->back()->withErrors(['error' => trans('A Network Error occurred. Please try again.')]);
}
The sendResetEmail method is a private method that sends an email with the reset link to the user. Here you can use whatever email app you choose to use. Maybe, you have a custom email service for your organization, you can use it here, not relying on the options Laravel has by default.
private function sendResetEmail($email, $token)
{
//Retrieve the user from the database
$user = DB::table('users')->where('email', $email)->select('firstname', 'email')->first();
//Generate, the password reset link. The token generated is embedded in the link
$link = config('base_url') . 'password/reset/' . $token . '?email=' . urlencode($user->email);
try {
//Here send the link with CURL with an external email API
return true;
} catch (\Exception $e) {
return false;
}
}
The link generated and sent to the user when clicked will direct the user to your domain.com/password/reset/token?email=’user#email.com’. You can find the view here: resources/views/auth/passwords/reset.blade.php
Step 4 - Reset the User's password
Add this method to the AccountsController. Go through the comments, they explain each step.
public function resetPassword(Request $request)
{
//Validate input
$validator = Validator::make($request->all(), [
'email' => 'required|email|exists:users,email',
'password' => 'required|confirmed'
'token' => 'required' ]);
//check if payload is valid before moving on
if ($validator->fails()) {
return redirect()->back()->withErrors(['email' => 'Please complete the form']);
}
$password = $request->password;
// Validate the token
$tokenData = DB::table('password_resets')
->where('token', $request->token)->first();
// Redirect the user back to the password reset request form if the token is invalid
if (!$tokenData) return view('auth.passwords.email');
$user = User::where('email', $tokenData->email)->first();
// Redirect the user back if the email is invalid
if (!$user) return redirect()->back()->withErrors(['email' => 'Email not found']);
//Hash and update the new password
$user->password = \Hash::make($password);
$user->update(); //or $user->save();
//login the user immediately they change password successfully
Auth::login($user);
//Delete the token
DB::table('password_resets')->where('email', $user->email)
->delete();
//Send Email Reset Success Email
if ($this->sendSuccessEmail($tokenData->email)) {
return view('index');
} else {
return redirect()->back()->withErrors(['email' => trans('A Network Error occurred. Please try again.')]);
}
}
There you have it. This should be enough to get things working.
I had the same problem, I was able to solve it this way,
first i add a route:
Route::get('password/reset/{token}', [App\Http\Controllers\Auth\ResetPasswordController::class, 'showResetForm'])->name('password.reset');
next i add in reset.blade.php
<input type="hidden" name="token" value="{{$token}}">
that's it, it works for me. Maybe someone will also need it
I have a registration form which works to register and login user.
I use $this->middleware('auth'); in the controllers on protected routes to prompt users to login. The login form passes a POST request to Laravel's AuthController w/ username and password:
<input type="hidden" name="_token" value="XXXXXXXXXX">
<div class="widget-content">
<input type="text" placeholder="Username" name="username">
<input type="password" placeholder="Password" name="password">
<input class="btn btn-blue pull-right" type="submit" />
</div>
</form>
Routes:
//authentication routes
Route::get('auth/login', 'Auth\AuthController#getLogin');
Route::post('auth/login', 'Auth\AuthController#postLogin');
Route::get('auth/logout', 'Auth\AuthController#getLogout');
// Registration routes...
Route::get('auth/register', 'Auth\AuthController#getRegister');
Route::post('auth/register', 'Auth\AuthController#postRegister');
I've tried using the authentication system's off-the-shelf postLogin() functionality, tried passing username, name, email to it without any luck. I tried overriding the parent method like this:
public function postLogin(Request $request)
{
$username = $request->input('username');
$password = $request->input('password');
if (Auth::attempt(['name' => $username, 'password' => $password])) {
// Authentication passed...
return redirect('dashboard');
} else {
return redirect()->intended('auth/login');
}
}
EDIT:
(This is old, For anyone having this issue.) The correct use of the hash function is
$password = Hash::make('yourPasswordString');
$result = Hash::check('yourPasswordString', $password); //returns true
Laravel also hashes your password if you are using inbuilt login functionality so check your model if in-case you're hashing your password.
can this be the CSFR token? Since you are not using a facade to call the form you may need to add in the token call just after opening the form tag.
Here is the call:
{!! csrf_field() !!}
{!! Form::hidden('token', $token) !!}
I am working on laravel 5 eCommerce web portal.
I am having an issue when the user updates the password using the ready made scripts.
The issue is that I can send the link to the customer perfectly without any issue and the customer can change his password also. But when logged out and re-logging in, I get the error as Invalid credentials.
In my routes.php, I have this:
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]);
This is the login page:
<form class="form-horizontal" role="form" method="POST" action="{{ url('/login') }}">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="form-group">
<label class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" value="{{ old('email') }}">
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password">
</div>
</div>
<div class="form-group">
<div class="col-md-4"></div>
<div class="col-md-4">
Forgot Password
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary btn-block">Login</button>
</div>
</div>
</form>
I cannot login again after I am logged out once the password has been reset.
EDIT 1:
When the login button is clicked on the login form page, the postLogin method is called. Here's the code
public function postLogin( Request $request ) {
$this->validate( $request, [
'email' => ['required', 'exists:users,email,role,customer'],
'password' => 'required'
]);
$credentials = $request->only('email', 'password');
if ( \Auth::attempt($credentials) ) {
\Session::flash('logged_in', 'You have successfully logged in.');
return redirect('/');
}
return redirect('/login')->withInput($request->all())->withErrors(['email' => 'Invalid Email Address Or Password']);
}
EDIT 2:
I just realize that login is not checking for the hash and hence returning false, on doing dd(\Hash::check($request->password, $user->password)), after updating the password and re-logging in. What could be the issue with this ?
Where have I made mistake ? Kindly guide me.
Thanks in advance.
P.S.: I am using the defaults only to update the password, rest all, I have made the controllers and models which are all working fine without any issue.
I stumbled upon this as well and found the answer here, just adding this for future reference..
The reason is that as soon as you add the setPasswordAttribute method on your User model, the password is hashed twice when using the built-in password reset functionality of Laravel. As explained on the Laracast page, all it needs is a check for an already hashed password, eg:
// Add Hash facade
use Illuminate\Support\Facades\Hash;
class User extends Authenticatable
{
// ...
/**
* Automatically hash password
*
* #param String $value The password, maybe hashed already
*
* #return string|null
*/
public function setPasswordAttribute($value)
{
if ($value) {
$this->attributes['password'] = Hash::needsRehash($value) ? Hash::make($value) : $value;
}
}
}
If the new password does not work after changing then something goes wrong when changing the password.
Most likely suspect is the encryption. It can be possible that you are not using the Hash::make($password) and saving it in plaintext format.
You can doublecheck if the hash is saved correctly to DB with function Hash::check($password, $hash);
During the login you can check the password as
public function postLogin( Request $request ) {
$user=User::where('email', $request->email);
Log::debug("Testing $request->password $user->password ". Hash::check($request->password, $user->password));
}
If the Hash::check is false then something went wrong when saving new password. $user->password must be in hashed form.
i am currently working on a project where the login/register is handled through modal boxes (so i click the login button and a nice modal reveals with a form in).
Im using foundation 5's reveal modal to house my login form but when the form is submitted and theres a validation error the modal closes. The reason this is happening is because i am redirecting back to the route where the login form is and in that route a button needs to be clicked to fire the modal.
What i was wondering is, is there something i can set so that modal stays open if there is a validation error or exception (account not found etc.) So if there is a validation error the modal stays open.
looking for any type of solution. my code is shown below.
Login function
public function postLogin()
{
// Declare the rules for the form validation
$rules = array(
'email' => 'required|email',
'password' => 'required|between:3,32',
);
// Create a new validator instance from our validation rules
$validator = Validator::make(Input::all(), $rules);
// If validation fails, we'll exit the operation now.
if ($validator->fails())
{
// Ooops.. something went wrong
return Redirect::back()->withInput()->withErrors($validator);
}
try
{
// Try to log the user in
Sentry::authenticate(Input::only('email', 'password'), Input::get('remember-me', 0));
// Get the page we were before
$redirect = Session::get('loginRedirect', 'dashboard');
// Unset the page we were before from the session
Session::forget('loginRedirect');
// Redirect to the users page
return Redirect::to($redirect)->with('success', Lang::get('auth/message.signin.success'));
}
catch (Cartalyst\Sentry\Users\UserNotFoundException $e)
{
$this->messageBag->add('email', Lang::get('auth/message.account_not_found'));
}
catch (Cartalyst\Sentry\Users\UserNotActivatedException $e)
{
$this->messageBag->add('email', Lang::get('auth/message.account_not_activated'));
}
catch (Cartalyst\Sentry\Throttling\UserSuspendedException $e)
{
$this->messageBag->add('email', Lang::get('auth/message.account_suspended'));
}
catch (Cartalyst\Sentry\Throttling\UserBannedException $e)
{
$this->messageBag->add('email', Lang::get('auth/message.account_banned'));
}
// Ooops.. something went wrong
return Redirect::back()->withInput()->withErrors($this->messageBag);
}
Login modal
<div id="myModalLogin" class="reveal-modal small" data-reveal>
<h2>Login</h2>
<form method="post" action="{{ route('login') }}">
{{-- CSRF Token --}}
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
{{-- Email --}}
<label for="email"> Email
<input type="text" name="email" id="email" value="{{ Input::old('email') }}" />
</label>
{{ $errors->first('email', '<label class="error">:message</label>') }}
{{-- Password --}}
<label for="password"> Email
<input type="password" name="password" id="password" value=""/>
</label>
{{ $errors->first('password', '<label class="error">:message</label>') }}
{{-- Remember me --}}
<input name="remember-me" value="1" id="remember-me" type="checkbox"><label for="remember-me">Remember me</label>
<hr>
{{-- Form Actions --}}
<button type="submit" class="button">Sign in</button>
I forgot my password
<a class="close-reveal-modal">×</a>
</div>
You need to create a flag variable that you will pass to your view and set it true if you want the modal to auto open and set it false if you don't want to open it:
The problem with this is that ->with() doesn't work with Redirect::back() so we need a workaround: lets pass our flag variable as an input. For this you have to get all the old input and add the new flag variable to them. Make sure that the key (your flag variable name) doesn't already exist. You can check this with a var_dump(Input::all()).
$input = Input::all();//Get all the old input.
$input['autoOpenModal'] = 'true';//Add the auto open indicator flag as an input.
return Redirect::back()
->withErrors($this->messageBag)
->withInput($input);//Passing the old input and the flag.
Now in your view you have to print this "old" input into your JavaScript condition. If it exists it will print its value: true, otherwise it will print the second argument: false.
<script>
$(document).ready(function () {
if ({{ Input::old('autoOpenModal', 'false') }}) {
//JavaScript code that open up your modal.
}
});
</script>
You can return false; when you return the validations results.