How we built the candidate approval process in Laravel

This blog post goes over the technical implementation of the Employbl candidate approval process for candidates using Laravel and PHP.

By Connor Leech - Apr 9, 2020


This is the template that we’re sending to candidates introducing them to Employbl. The way the system is set up now is around an approval process. Candidates apply on the candidates page. This goes to a MySQL database hosted on Laravel Forge where a users table row gets created with users.active = 0 after the candidate successfully submits the form. For candidate login to work users.active must be set to 1 or true. This is to ensure that candidates work in the tech industry and are legitimate. We’re targeting candidates based in the United States that are looking for tech jobs or startup jobs in the Bay Area. Once approved, candidates can login, update their profile and upload their resume. (They should probably be able to upload their resume on first apply but one thing at a time...)

Approving users has been a bottleneck for me with the site. I was typing an intro email to every candidate and then adding them on LinkedIn. There was a SQL command where I filled it out to added the user to the database. The candidate apply form was initially a Google Form. This required manually adding the data from the Google Form backend into the MySQL database by copying and pasting. Once we moved the form to add users to the database directly we still need to go in and manually toggle the candidates to approved and write out or copy and paste a welcome email. There had to be a better way..

I’m all for no-code apps and I think there are great ways to build apps without coding (Get Silver Linings is a great example), but for us the Employbl site is built in Laravel and it makes sense to have features built in PHP.. call me a dinosaur lol.

Laravel Authentication with Auth0


Laravel has built in helpers to build authentication systems simply and easily. The power of the php artisan make:auth generating a fully baked authentication system for your web app was one of the reasons I wanted to learn the Laravel framework in the first place. The idea of having authentication be generated with a simple command was tantalizing. I could have an authentication system that “just worked” and move on to building other parts of the app.

As I’ve been building Employbl I’ve learned more about authentication systems and some inherent limits of boilerplate code when trying to build something custom. In the first iteration of Employbl, launched in July 2018 I deployed a Laravel app with the most basic system using php artisan make:auth. Things worked great for the ideal scenario where an honest person signs up with their real email address. But I soon learned that the internet is full of trolls, bots and people that really don’t care about making an account. I had users signing up with invalid emails like test@test.com or jksfnsdfjk@dsjnfkdsjf.com. Employbl is a recruiting platform where it matters that candidates who sign up are real.(In the future some laravel twilio phone validation would be 💯) I modified the system so upon registration me and my co-founder get an email every time a candidate signs up to join the community. Once we see that a candidates is a real person by checking their LinkedIn profile and email that they submit I toggle a flag on users.active. Only users with a users.active = 1 can successfully login to the system. It would be nice if they could upload their resume on initial submission instead of after logging in but that can come later!

Another aspect of the authentication system as it’s currently implemented is that there’s only social login. To have email and password account creation and sign in is an extra technical challenge. Not only would we need to manage the approval process (users.active = 1) but we would need to hash and store passwords and send verification emails with tokens for users to verify that their email is legitimate and that they have access to it. We’d also need to implement forgot password functionality. Another head stumper is reconciling email and password login with social login. For example if someone creates an email/password account and then tries to use login with Google for the same email address do they get access? Do we throw an error telling them to login with email and password? Social login seems more simple and to avoid many headaches while offering much of the same benefit. The team at Kapwing wrote a great post about the case against email sign in. Social login isn’t perfect but eliminating email and password sign in seems like the way to go.

In the future we’d also like to have a robust system in place for recruiters and hiring managers to login and view candidates. This entails more authentication logic and systems. There’s a whole nother table for employers separate from users. In this post I’d like to keep things simple and describe the authentication system we have on Employbl, improvements we can make and where we want to take it from here. Anyway made the decision to migrate to Auth0...

Why use Auth0 over other methods.

A) Great developer community

B) You don’t need to verify providers or store passwords.

Auth0 Laravel tutorial 1

Auth0 Laravel tutorial 2

Candidate apply form

The first step in the candidate onboarding process is that candidates apply on the website. It would be nice to have a user invitation system too. We can come to that later with an artisan command. For now, looking at the candidate apply form this is what it looks like. It’s structured with Bootstrap 4 and using SASS for the color variables.


The Laravel Blade for this form includes a Vue component to handle form Javascript things.

That link to view the Vue component is below. We hard code the states and the work authorization statuses. This form can totally be improved and probably needs to be a longer questionaire like a Typeform or the style of Jira customer support. Props to Atlassian for building that out 👍 Side note, started using Jira’s free plan to track the Employbl project and we’ve found it helpful :)

View the Vue component here. (Having trouble embedding the component into this webpage, the blog tries to execute the code 😂)

Submitting the form hits the CandidateController@store method. This will send and email using Laravel Mailables and save the user to the database using Laravel Eloquent. The function to save the user initially is below. We start off with an active = false state on the user.

Once the user has been created it’s time to approve the candidate. I will note that there is config to do for social providers and in the Auth0 dashboard.

The ApproveCandidate Artisan command

The ApproveCandidate artisan command automates the candidate approval process. Candidates apply on the candidates page creating an inactive user on the users table. This triggers an email to me and my cofounder that a new candidate applied on Employbl. The new flow will be once we see the email that a new candidate applied, SSH into the production server and run the ApproveCandidate artisan command for the user id that we want to approve. We’re using Laravel Nova on the backend so maybe in the future we could approve candidates through the Nova dashboard instead of SSHing into production.

This is the Blade (HTML) template for the approval email to send to candidates prompting them to login and upload their resume :)

As you can see from the comment we had some issue rendering the button color properly using the blade components so used the HTML directly. I added some custom CSS for the branded button color in resources/views/vendor/mail/html/themes/default.css.

.button-bittersweet {
   background-color: #F86D5F;
   border-top: 10px solid #F86D5F;
   border-right: 18px solid #F86D5F;
   border-bottom: 10px solid #F86D5F;
   border-left: 18px solid #F86D5F;
}

Below is the artisan command that sends the above email, written for Laravel 5.8. It takes a user id, approves the candidate (stored on the users table) and sends an email. We’re using Mailgun to send emails.

There is also a mailable that we generated with php artisan make:mail ApproveCandidate. It takes in an Eloquent user model and renders the email using $this->markdown.

Conclusion

The hiring space is crowded with a lot of amazing people looking to find the right match to great companies. There are many people looking to get their cut off candidates getting hired. I don’t think it’ll ever be a solved problem though because it’s all about people meeting people. This process is to build an open system where candidates can create profiles, upload their resume and search through company locations and find jobs. Building a reliable candidate registration system is an important part in this journey!