Enterprises are increasingly challenged to keep sensitive information from falling into the wrong hands. This means that we can no longer trust old online authentication systems that rely solely on usernames and passwords, especially as security breaches grow in frequency, severity, and sophistication.
With the MessageBird Verify API, you can implement two factor authentication (2FA) solutions to provide an additional layer of account security by verifying the user's password with a second authentication token and in turn, secure customer data, block fraudulent accounts, and safeguard key transactions in a matter of minutes. The most common use case involves the application of one-time passwords (OTP) generated by hardware tokens or authenticator apps or directly sent to the user's mobile phone via SMS text messaging.
In this MessageBird Developer Guide, we'll introduce the MessageBird Verify API and show you how to build a runnable application in Java. The application is a prototype for a two factor authentication system deployed by our fictitious online banking application called BirdBank.
We'll walk you through the following steps:
- Asking for the phone number
- Sending a verification code
- Verifying the code
Pro-tip: Follow this tutorial to build the whole application from scratch or, if you want to see it in action right away, you can download, clone or fork the sample application from the MessageBird Developer Guides GitHub repository.
We'll use Java 1.8, the Spark framework with Mustache templates as well as the MessageBird SDK to build our sample application.
Before we get started, make sure that the Java package manager Maven is installed. If not, you can easily install it for free.
First, create a new directory to store the sample application. Within this new directory, create a file called pom.xml
with the following dependencies:
<dependencies>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-template-mustache</artifactId>
<version>2.7.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>java-dotenv</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>com.messagebird</groupId>
<artifactId>messagebird-api</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
This file defines all of the dependencies necessary for your sample application, including Spark and the MessageBird SDK.
Your editor--such as IntelliJ--should ask you whether you want to import these Maven dependencies into your project. You should do so!
To use the MessageBird SDK, we need to provide an access key for the API. MessageBird provides keys in live and test modes. To get this application running, we will need to create and use a live API access key. Read more about the difference between test and live API keys here.
Let's create your live API access key. First, go to the MessageBird Dashboard; if you have already created an API key it will be shown right there. If you do not see any key on the dashboard or if you're unsure whether this key is in live mode, go to the Developers section and open the API access (REST) tab. Here, you can create new API keys and manage your existing ones.
If you are having any issues creating your API key, please reach out to our Customer Support team at support@messagebird.com.
Pro-tip: Hardcoding your credentials is a risky practice that should never be used in production applications. A better method, also recommended by the Twelve-Factor App Definition, is to use environment variables.
We've added dotenv to the sample application, so you can supply your API key in a file named .env
. You can copy the provided file env.example
to .env
and add your API key like this:
MESSAGEBIRD_API_KEY=YOUR-API-KEY
You now have your API key, so let's get started with the main file. First, create a TwoFA.java
file in the src
directory of your project. This file starts off by importing dependencies:
import spark.ModelAndView;
import spark.template.mustache.MustacheTemplateEngine;
import static spark.Spark.get;
import io.github.cdimascio.dotenv.Dotenv;
The first line in the class file loads any required environment variables:
Dotenv dotenv = Dotenv.load();
Next, we're creating a new MessageBird client. This will be used to access the API.
// Create a MessageBirdService
final MessageBirdService messageBirdService = new MessageBirdServiceImpl(dotenv.get("MESSAGEBIRD_API_KEY"));
// Add the service to the client
final MessageBirdClient messageBirdClient = new MessageBirdClient(messageBirdService);
And finally, we will set up an endpoint which we can access:
get '/' do
'Hello!'
end
If you run the server, you should see a message similar to the following:
[Thread-0] INFO spark.embeddedserver.jetty.EmbeddedJettyServer - == Spark has ignited ...
[Thread-0] INFO spark.embeddedserver.jetty.EmbeddedJettyServer - >> Listening on 0.0.0.0:4567
Head to localhost:4567
in your browser, and you should be greeted with a message! This shows that the basics of the app are working.
We use Mustache to separate the logic of our code from the HTML pages. To do this, create a directory named templates
inside of resources
. Inside templates
we will create two files. First, create a file called header.mustache
with the following content:
<!doctype html>
<html>
<head>
<title>MessageBird Verify Example</title>
</head>
<body>
<h1>MessageBird Verify Example</h1>
Then, create a file called footer.mustache
with this content:
</body>
</html>
These represent the main layout which acts as a container for all pages of our application. We'll create the views for each page next.
The first step in verifying a user's phone number is asking them to provide their phone number. Let's do exactly this by creating an HTML form and storing it as step1.mustache
inside the views
directory:
{{> header}}
{{#errors}}
<p>{{errors}}</p>
{{/errors}}
<p>Please enter your phone number (in international format, starting with +) to receive a verification code:</p>
<form method="post" action="/step2">
<input type="tel" name="number"/>
<input type="submit" value="Send code"/>
</form>
{{> footer}}
The form is simple, having just one input field and one submit button. Providing tel
as the type
attribute of our input field allows some browsers, especially on mobile devices, to optimize for telephone number input, for example by displaying a numberpad-style keyboard. The section starting with {{#errors}}
is needed to display errors. We'll come back to this in a minute.
Now, it's time to change the initial route in app.rb
to display the page:
get("/",
(req, res) ->
{
return new ModelAndView(null, "step1.mustache");
},
new MustacheTemplateEngine()
);
Running the application should display the form.
Once we've collected the number, we can send a verification message to a user's mobile device. MessageBird's Verify API takes care of generating a random token, so you don't have to do this yourself. Codes are numeric and six digits by default. If you want to customize the length of the code or configure other options, you can refer to the Verify API documentation.
The form we created in the last step submits the phone number via HTTP POST to /step2
, so let's define this route in our TwoFA.java
file:
post("/step2",
(req, res) ->
{
String number = req.queryParams("number");
Map<String, Object> model = new HashMap<>();
try {
VerifyRequest verifyRequest = new VerifyRequest(number);
verifyRequest.setTimeout(120);
final Verify verify = messageBirdClient.sendVerifyToken(verifyRequest);
model.put("otpId", verify.getId());
return new ModelAndView(model, "step2.mustache");
} catch (UnauthorizedException | GeneralException ex) {
model.put("errors", ex.toString());
return new ModelAndView(model, "step2.mustache");
}
},
new MustacheTemplateEngine()
);
Let's quickly dive into what happens here:
First, the number is passed along from the request. We instantiate a new object, VerifyRequest
, with the number as the first parameter. Then, using the MessageBird client, we send a verification token using sendVerifyToken
.
If this call fails, the MessageBird client throws one of two exceptions. A typical error could be that the user has entered an invalid phone number. For our application, we simply re-render the page from our first step and pass the description of the error into the template - remember the {{#errors}}
section from the first step? In production applications, you'd most likely not expose the raw API error. Instead, you could consider different possible problems and return an appropriate message in your own words. You might also want to prevent some errors from occurring by doing some input validation on the phone number yourself.
In case the request was successful, we'll render a new page. Our API response contains an ID, otpId
, which we'll need for the next step, so we'll just add it to the form. Since the ID is meaningless without your API access key there are no security implications of doing so; however, in practice, you'd be more likely to store this ID in a session object on the server. Just as before, we're logging the whole response to the console for debugging purposes. We still need to build the new page, so create a file called step2.mustache
in your views
directory:
{{> header}}
{{#errors}}
<p>{{errors}}</p>
{{/errors}}
<p>We have sent you a verification code!</p>
<p>Please enter the code here:</p>
<form method="post" action="/step3">
<input type="hidden" name="id" value="{{otpId}}}"/>
<input type="text" name="token"/>
<input type="submit" value="Check code"/>
</form>
{{> footer}}
The form is very similar to the first step. Note that we include a hidden field with our verification ID and, once again, have a conditional error section.
The user will check their phone and enter the code into our form. What we need to do next is send the user's input along with the ID of the verification request to MessageBird's API and see whether the verification was successful or not. Let's declare this third step as a new route in our app:
post("/step3",
(req, res) ->
{
String id = req.queryParams("id");
String token = req.queryParams("token");
Map<String, Object> model = new HashMap<>();
try {
final Verify verify = messageBirdClient.verifyToken(id, token);
return new ModelAndView(model, "step3.mustache");
} catch (UnauthorizedException | GeneralException ex) {
model.put("errors", ex.toString());
return new ModelAndView(model, "step2.mustache");
}
},
new MustacheTemplateEngine()
);
This code looks very similar to the one in the second step. First, we're reading the input and then make a call to MessageBird's API. This time, it's the verifyToken
method, which accepts id
and token
as its parameters.
In case of an error, such as an invalid or expired token, we're showing that error on our page from the second step.
In the success case, we simply show a new page. Create this page in your views
directory and call it step3.mustache
:
{{> header}}
<p>You have successfully verified your phone number.</p>
{{> footer}}
Build and run the application through your IDE.
Point your browser to http://localhost:4567/ and try to verify your own phone number.
You now have a running integration of MessageBird's Verify API!
You can now leverage the flow, code snippets and UI examples from this tutorial to build your own two factor authentication system. Don't forget to download the code from the MessageBird Developer Guides GitHub repository.
Want to build something similar but not quite sure how to get started? Please feel free to let us know at support@messagebird.com, we'd love to help!