Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Apogee's avatar

How to get users register over invitation link sent to email?

Hi, I want to implement possibility to send an email with invitation link to users I want to register to my app. I want to use new Laravel Notifications feature (https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/9), but don't actually know how to send link with unique token (something like the 'Forgot your password?').

That would have to work this way:

  1. Administrators have the access to certain form where they can type email address.

  2. That email address will be stored in users table in the database. ... I can handle these two steps :-)

  3. The email with invitation link (probably whith unique token) is set to potential user.

  4. Then, when the potential user clicks on the invitation link app should provide him only password and 'Confirm Password' input fields, something what is already implemented over the Forgot Password feature.

  5. After submiting password, the user is redirected to homepage of the app. Password is hashed and stored in the DB. I can also handle this step.

I'm currently between beginner and intermediate level in Laravel so please, help me implement this if it isn't that hard. I need help whith steps 3 and 4.

Thank you!

0 likes
9 replies
rsands's avatar

Hi

You could bcrypt the users email address and use that as the token in the email. The URL could have the users ID. You would lookup that ID, bcrypt the email in the table and check does it match the token in the link.

If not, then its assumed the user ID does not belong to them.

The page would have password fields and when saving to the database you would bcrypt the input and that would create the password.

jekinney's avatar

Obviously your password column would have to be nullable.

What I've done in the past is two ways:

First was down and dirty. I used the remember token column and generated str_random(10). Used that as the check. This worked well but was intended for launch only.

Second if you need something more viable for everyday use I created another Invite model and table. Holding only the email, random string token, accepted (Boolean), relationship to roles or permissions as applicable, and full URL (easier for when sending email with the token) also name if applicable.

A controller and I used the show method to process the request by the Token. Shows a form (basically modified registration) with email as read only. Submit to the registration store method as any other user. Create user and then check if email exists in invite. If so activate user and set invite to excepted and if needed apply roles/permissions.

That way you have a history of invited users, and when invited and when accepted (updated_at column or your own). This also insures you are not passing data that can be manipulated or using hidden inputs etc. I did it by firing an event in the created model event via Observer but you don't need to do that, and may cause a delay if your wanting to assign access (roles/permissions) if queued.

1 like
Apogee's avatar

@jekinney , can you explain a bit more aobut what you said "A controller and I used the show method to process the request by the Token. ". I don't get that part. I commented out registration routes, are you suggesting to make it GET and smth like: /register/{token}? What function have you used to generate unique string token and store it to database?

zahidgani's avatar

//In your controller get data fromdatabase and put whatever you want to make design in message variable and send

//First set Middleware/VerifyCsrfToken.php

class VerifyCsrfToken extends BaseVerifier { /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = ['verify']; }

//this work for remove token permission for submitting form

//in your controller page work following.

 use App\Mail\VerifyEmail;
 use Mail;

 $rs=DB::select("select * from users where id=1");
 $message="";
 $message.="<h2>HI ".$rs[0]->name."</h2>h2>";
 $message.="<h2>Please verify <a href='http://www.yourdomain.com/verify/".$rs[0]->email."'>Verify</a> </h2>h2>";
  $subj    = $mailer->subject;

   $data = 
   [
      'subject' => $subj,
      'from'    => '[email protected]',
      'to'      => '[email protected]',
   ];
    

    Mail::send(array(), $data, function ($msg) use ($message,$data) 
    {
      $msg->from($data['from'], 'Avya Tech');
      $msg->to($data['to'])->subject($data['subject'])
      ->setBody($message, 'text/html');
    });
Apogee's avatar

@jekkiney, maybe it's better to override ResetPasswords trait, it already has all methods I need for this purpose, but don't understand what method broker() does? Can someone explain it?

I just need to get customized email template for sending invitation link.

jekinney's avatar
jekinney
Best Answer
Level 47

@schwarzgepard

Schema::create('invites', function (Blueprint $table) {
            $table->increments('id');
            $table->string('token')->index();
            $table->string('name');
            $table->string('email');
            $table->boolean('accepted')->default(0);
            $table->timestamp('accepted_at')->nullable();
            $table->timestamps();
        });

The Model (abbreviated) Notice the get route key name method for route model binding on the create controller method. It accepts the token and returns the applicable row

<?php

namespace App\Site\Models;

use Illuminate\Database\Eloquent\Model;

class Invite extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'token',
        'name',
        'email',
        'accepted',
        'accepted_at',
    ];

    /**
     * Get the route key for the model.
     *
     * @return string
     */
    public function getRouteKeyName()
    {
        return 'token';
    }

    /**
     * Many to many relationship to Role model.
     *
     * @return object
     */
    public function roles()
    {
        return $this->belongsToMany(Roles::class)
    }

    /**
     * Add a new invite and attach role(s) if applicable.
     *
     * @param object $request
     * @return object $invite
     */
    public function addNew($request)
    {
        $invite = $this->create($request->all());
        if($request->has('roles')) {
            $invite->roles()->attach($request->roles);
            return $invite->load('roles');
        }
        return $invite;
    }

    /**
     * Process an invited request to sign up/register
     * Find the invite by email, update accepted st and accepted boolean
     * Create a new User on the user model
     * Add applicable roles and return user object
     *
     * @param object $request
     * @return User $user
     */
    public function processInvited($request)
    {
        $invited = $this->with('roles')->where('email', $request->email)->first();
        if($invited) {
            $invited->update(['accpeted' => 1, 'accpeted_at' => \Carbon\Carbon::now()->toDateTimeString()]);
            $user = User::create([
                'name' => $invite->name,
                'email' => $invite->email,
                'password' => $request->password,
                'active' => 1,
            ]);
            if($invited->roles) {
                $user->roles()->attach($invited->roles());
            }
            return $user;
        }
        return abort('404', 'No invite was found');

    }
}

Model Observer (abbreviated)

<?php

namespace App\Site\Observers

use App\Site\Models\Invite;

class Invites
{
    /**
     * Listen to the Invite creating event.
     *
     * @param  Invite  $invite
     * @return void
     */
    public function creating(Invite $invite)
    {
        $invite->token = $this->generateToken();
    }

    /**
     * Listen to the Invite created event.
     *
     * @param  Invite  $invite
     * @return void
     */
    public function created(Invite $invite)
    {
        event(new NewInviteWasCreated($invite));
    }

    /**
     * Generate random token, check if unique, if not regenerate.
     *
     * @return string $token
     */
    protected function generateToken()
    {
        $token = str_random(10);
        if(Invite::where('token', $token)->first()) {
            return $this->generateToken();
        }
        return $token;
    }
}

Notice the created method fires an event to send the email.

Front end controller, You don't NEED to use two controllers but in the app where I copied the code it had a separate backend controllers.

class InviteController extends Controller
{
    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('front.site.invite.create');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(InvitedForm $request, Invite $invite)
    {
        $user = $invite->addNew($request);

        return redirect()->route('account.show', $user);
    }

The newer mail in 5.3 is pretty stright forward (The above code is from a 5.2, so the mail is different).

https://laravel.com/docs/5.3/mail#generating-mailables

Basically send your data and it formats the email for you.

Check this out!!!! https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/6

Please or to participate in this conversation.