Mobile Passwordless SMS Authentication: Part 1 – Building the API with Laravel and Twilio
Time to read: 8 minutes
Lately there’s been a lot of discussion about the future of passwords – some have even declared that the password is obsolete. When I saw that one of my favorite apps, Cover, decided to launch passwordless authentication I was intrigued. I realized what a great experience passwordless auth provided after using it for the first time. Users don’t have to worry about remembering an overly complex password and since the SMS is delivered to their phone number they know it’s secure. In this series, I’ll show you how to build your own basic mobile passwordless authentication system for both iOS and Android using Laravel and Twilio SMS. Today, we’ll kick the series off by building the API that will power our system.
See It In Action
If you truly want to experience the passwordless authentication experience I’d recommend downloading the Cover app and seeing how they do it:
In parts 2 and 3 of this series we’ll build a basic version of this flow for iOS and Android. It won’t look nearly as nice but it’ll give you a technical foundation for building passwordless authentication in your own mobile apps.
Our Tools
Our app will consist of two components:
- A client-side mobile experience built with Swift for iOS and Java for Android
- A server-side API built using Laravel
For now, we’re focusing on our backend which will have the following dependencies:
- PHP >= 5.4
- MySQL
- Laravel 4.2.*
- Twilio Account and Phone Number – sign up for free!
- Twilio PHP library
Laying Our Foundation
We’re going to build our API as a basic Laravel app that will allow us to determine which user is trying to authenticate, send them a one-time use token via SMS and validate that token. I decided to build the API using Laravel because it’s a framework I’ve been really enjoying recently but you can take these concepts and apply them to your language or framework of choice.
First we need to set up a new Laravel project that connects to a MySQL database. Let’s start by creating a new boilerplate Laravel project.
Visit http://localhost:8000 and you’ll see the beautiful Laravel welcome page.
For our application we’ll create a very basic user object and we’ll store that user data in a MySQL database. In order to properly connect to our database we need to update our database config files with the proper credentials. Open up app/config/database.php and look for the following section:
This array configures the details for our MySQL connection. Make sure to update your host, database, username and password to the correct info for your database. You’ll need to create your database in MySQL for this code to work.
Now that we’ve properly configured our database we need to write the code that updates our schema with the data we want to capture. First we’ll create a migration that will create our user table:
When you run this command Laravel will generate a new file in app/database/migrations/ with that will look something like this: [current_date]_create_users_table.php
. This file will allow us to define specific schema changes we want to apply. Open up this file and modify the up function to contain the following code:
Next we’re going to seed our database by configuring our DatabaseSeeder to preload a single user into our users table. In our final application we’d want to have users signing up for our application but this single user will work for our prototype. Let’s open up /app/database/seeds/DatabaseSeeder.php and replace it with this code that will properly seed things for us:
This code will delete our users table (in case we have any pre-existing data there for some reason) and insert a single user with the data in our array. Our user is very simple. It only contains an e-mail address and phone number. Make sure to update this information in the code to have your own info.
We’re almost ready to populate our database but let’s update our User model first. Open up app/models/User.php and add the highlighted line after the hidden properties are defined:
Now that we have all our pieces in place, let’s run our database migration (this will apply our schema changes) and seed our data:
Knock Knock! Who’s There?
Now that we have our database in place, let’s update our User model to generate, send and validate our authentication token. We’ll be using Twilio to send our tokens so we need to require the Twilio PHP library using composer:
We’ll store the token in a session and we should generate a random key to make sure our sessions are secure:
One last piece of setup: let’s create an .env.php file to store our Twilio credentials and our Twilio number:
Make sure to update this information with the credentials in your Twilio Dashboard. We want this information to stay private so if you’re managing this project with git be sure to add this file to your .gitignore file as well.
Now let’s create a new method on our User model that generates and sends our token. We’ll add this function in app/models/User.php:
First, we generate a random six digit number and store it in our session. This will be our authentication token. Then we instantiate our Twilio PHP library. We use the sendMessage method to send a new message from our twilio number, to the users phone number and with a body notifying them of their token.
Next we can create new method on our User model that validates that a token is correct. We’ll add this code in app/models/User.php too:
In this code we’re pulling the valid token from our session and validating it against the token that was provided. If they match then we’re removing the the token from our session, authenticating the user for this app and returning true. Otherwise, we’re returning false.
Now that we’ve added the proper methods to our User model we can build the API endpoints that interact with these methods. Our API will have two endpoints:
- /user/validate – This endpoint will accept a phone number and send an authentication token to the user with that phone number.
- /user/auth – This endpoint will accept the authorization token for a user and log them in
In app/routes.php add the following two lines at the end of the file:
We’ve defined our two routes that will be accessed when someone makes a POST request to our server. Now we need to create a new file (app/controllers/UserController.php) that will serve as our controller for these two routes. We can start by making our base class and adding a method for our /user/validate route:
First we’re pulling the phone_num that is POSTed to this endpoint. Then we do a database lookup to determine if that user exists. If it does we’ll store our phoneNum in the session so we can access it later, call our sendToken function and return a simple JSON success response. If the user doesn’t exist we’ll send an unsuccessful JSON response. In the real world, we’d want to provide a more detailed reason for the failure but right now we’re just keeping things simple.
Now we can add the method for our /user/auth route inside the UserController:
First, we’re getting the token that is POSTed to our endpoint and the phoneNum from our session. Next, we’ll check our database for a user with that phone number. If the user exists and the token is valid we’ll send back a successful json response. Otherwise we’ll send back back an unsuccessful response. Again, in the real world we’d want to provide a more detailed error from our API but this will work as a proof of concept.
Would You Like To Save Your Game?
Let’s create a checkpoint for ourselves and make sure everything works. On Halloween I showed you how to use Postman to debug your Twilio apps. Today we’re going to use it to test the endpoints we just built and make sure they’re working correctly. If you haven’t used Postman before, it’s is a really great tool for building and executing custom HTTP requests.
If you shut down your app to make these changes make sure to start it back up:
Now let’s create a request to our /user/validate endpoint to trigger sending our SMS token:
If you haven’t used Postman before, you need to fill in url, phone_num and switch the method dropdown from GET to POST. Remember that we set up our app to only send a code if there’s a user in the database so make sure to use the phone number you configured when you seeded your database. Shortly after you make the request you should get your verification token.
Once you have your token we can make our user/auth request using postman:
This should return our success json and that means we’re all set on our API for now. If you experiencing any issues feel free to compare your code with the final version of this code in the github repo.
Accessing Secure Data
Our API is basic but hopefully you’re seeing the potential. There’s one last thing I want to show you how to do. We’re currently authenticating a user, but what about making a request to get data that only an authenticated user can receive? Luckily for us Laravel makes this really easy. Open up your app/routes.php file and add the following route:
Restart your app and try to access the /profile route. If you’ve been following along with this tutorial, you’re already authenticated and you’ll notice you’re seeing our super secret data. We can quickly add a /user/logout route to allow us to see what happens when we access the /profile route when we’re not authenticated. Add the following method to your app/routes.php file:
By default Laravel will redirect any unauthenticated requests we make for /profile to /login, let’s add a route to avoid receiving a 404 error when this occurs. Add your route in app/routes.php:
Restart your server to make sure all our new routes are loaded. Now visit /user/logout and then try /profile. You’ll notice you’ve been redirected to /login and see our error JSON. Run through the authentication process in Postman one more time and once again you’ll get access to our super secret data.
What’s Next?
Whether or not you think passwords are obsolete, I hope this code helps serve as inspiration to think about passwords differently and perhaps even implement passwordless authentication in your own app. In part 2 of this series I’ll show you how to integrate this API into your iOS apps with Swift. Have questions or what to show off what you’ve built? Holler at me on twitter (@rickyrobinett) or e-mail (ricky@twilio.com)
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.