1
votes

I'm trying to modify the default Laravel 5.6 Auth in a way to email new users a link to create their password, since this is an invite only system and I don't want to email created users their password as plaintext.

In 5.3 what I was able to do was grab the reset token from the password_resets table and send them a Notification with a "Create Password" button.

In 5.6 (not sure when this changed) it seems to be an encrypted version of their password reset token in the database. How would I then call the correct url in a custom notification for users to be able to create a password?

Here's what I had in 5.3:

controller

......

$token = strtolower(str_random(64));

DB::table('password_resets')->insert([
    'email'      => $request->email,
    'token'      => $token,
    'created_at' => Carbon::now()
]);

$user->notify(new UserCreated($user));

......

password create email

.....

$token = DB::table('password_resets')->where('email', $user_email)->pluck('token')->first();

$url = url('/password/reset/' . $token);

......

Copying the same code over to 5.6, it tells me my reset tokens are invalid. It appears the tokens in the database no longer match the token in the url when doing a normal password reset. Now they appear to be encrypted or something?

I've made sure in the email the url and the token match exactly whats in the database, with the valid period set to like a week (to test), and every token created this way it says is invalid.

How then do you do auth for an invite only system, or how do you just manually create a reset token and then send it in a custom email? The docs mentions being able to replace the password reset email, but I don't want that, I want to supplement it.

2
Can you show your code for how you were doing this originally?Rwd

2 Answers

1
votes

Creating and saving the token can be done in a single line using the built-in functionality. Took me an hour and prodigious use of dd() to figure it out, but I added this to my User model:

<?php

namespace App;

use App\Notifications\AccountCreated;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;

class User extends Authenticatable
{
    use Notifiable;

    public function generatePassword()
    {
        $this->password = Hash::make(str_random(32));
    }

    public function sendWelcomeEmail()
    {
        // Generate a new reset password token and save it to the database
        $token = app("Password")::getRepository()->create($this);

        // Send notification
        $this->notify(new AccountCreated($this, $token));
    }
}

The notification gets the user and the token, same as your code, so that they can be included in the email text. Then in UserController::store() I can just do:

    $user = new User($request->all());
    $user->generatePassword();
    $user->save();
    $user->sendWelcomeEmail();

In the email notification, you can use this to get the actual URL:

$url = route("password.reset", $token)
-1
votes

Solved it!

Here's my new controller and notification in 5.6 for manually sending a different password create email. All I really had to do was encrypt the token before storing it in the database! Then you pass the unencrypted token to the email for the url, which checks against the encrypted one in the DB.

controller

.....

$random_token    = strtolower(str_random(60));
$encrypted_token = bcrypt($random_token);

DB::table('password_resets')->insert([
    'email'      => $request->email,
    'token'      => $encrypted_token,
    'created_at' => Carbon::now()
]);

$user->notify(new AccountCreated($user, $random_token));

.....

In the email I'm just importing the user and the token...

.....

public $user;
public $token;

public function __construct(User $user, $token)
{
    $this->user  = $user;
    $this->token = $token;
}

.....