As of November 2022, Twilio no longer provides support for Authy SMS/Voice-only customers. Customers who were also using Authy TOTP or Push prior to March 1, 2023 are still supported. The Authy API is now closed to new customers and will be fully deprecated in the future.
For new development, we encourage you to use the Verify v2 API.
Existing customers will not be impacted at this time until Authy API has reached End of Life. For more information about migration, see Migrating from Authy to Verify for SMS.
Ready to implement user account verification in your application? Here's how it works at a high level:
To get this done, you'll be working with the following Twilio-powered APIs:
Authy REST API
Twilio REST API
1<?xml version="1.0" encoding="UTF-8"?>23<web-app xmlns="http://java.sun.com/xml/ns/javaee"4xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"5xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"6version="3.0">7<welcome-file-list>8<welcome-file>home.html</welcome-file>9</welcome-file-list>10<servlet>11<servlet-name>registration</servlet-name>12<servlet-class>com.twilio.verification.servlet.RegistrationServlet</servlet-class>13</servlet>14<servlet>15<servlet-name>verify-code</servlet-name>16<servlet-class>com.twilio.verification.servlet.VerifyCodeServlet</servlet-class>17</servlet>18<servlet>19<servlet-name>account</servlet-name>20<servlet-class>com.twilio.verification.servlet.AccountServlet</servlet-class>21</servlet>22<servlet>23<servlet-name>resend-token</servlet-name>24<servlet-class>com.twilio.verification.servlet.ResendTokenServlet</servlet-class>25</servlet>2627<servlet-mapping>28<servlet-name>registration</servlet-name>29<url-pattern>/registration</url-pattern>30</servlet-mapping>31<servlet-mapping>32<servlet-name>verify-code</servlet-name>33<url-pattern>/verify-code</url-pattern>34</servlet-mapping>35<servlet-mapping>36<servlet-name>account</servlet-name>37<url-pattern>/account</url-pattern>38</servlet-mapping>39<servlet-mapping>40<servlet-name>resend-token</servlet-name>41<url-pattern>/resend-token</url-pattern>42</servlet-mapping>4344<filter>45<filter-name>authentication</filter-name>46<filter-class>com.twilio.verification.filter.AuthenticationFilter</filter-class>47</filter>4849<filter-mapping>50<filter-name>authentication</filter-name>51<url-pattern>/account</url-pattern>52<url-pattern>/verify-code</url-pattern>53<url-pattern>/resend-token</url-pattern>54</filter-mapping>5556<filter>57<filter-name>TeeFilter</filter-name>58<filter-class>ch.qos.logback.access.servlet.TeeFilter</filter-class>59</filter>6061<filter-mapping>62<filter-name>TeeFilter</filter-name>63<url-pattern>/*</url-pattern>64</filter-mapping>6566<filter>67<filter-name>LoggingFilter</filter-name>68<filter-class>com.twilio.verification.logging.LoggingFilter</filter-class>69</filter>7071<filter-mapping>72<filter-name>LoggingFilter</filter-name>73<url-pattern>/*</url-pattern>74</filter-mapping>75</web-app>76
Let's get started!
If you have already read through the 2FA tutorial, this User Model probably looks very similar. We need to make sure that our User model contains a phone number, country code so that the user can be verified with Authy.
1package com.twilio.verification.model;23import javax.persistence.*;4import java.util.Date;56@SuppressWarnings("unused")7@Entity8@Table(name = "users")9public class User {10@Id11@GeneratedValue(strategy = GenerationType.IDENTITY)12@Column(name = "id")13private int id;1415@Column(name = "name")16private String name;1718@Column(name = "email")19private String email;2021@Column(name = "password")22private String password;2324@Column(name = "country_code")25private String countryCode;2627@Column(name = "phone_number")28private String phoneNumber;2930@Column(name = "authy_id")31private int authyId;3233@Column(name = "verified")34private boolean verified;3536@Column(name = "date")37private Date date;3839public User() {40}4142public User(String name, String email, String password, String countryCode, String phoneNumber, int authyId) {43this.name = name;44this.email = email;45this.password = password;46this.countryCode = countryCode;47this.phoneNumber = phoneNumber;48this.authyId = authyId;49this.verified = false;50this.date = new Date();51}5253public int getId() {54return id;55}5657public void setId(int id) {58this.id = id;59}6061public String getName() {62return name;63}6465public void setName(String name) {66this.name = name;67}6869public String getEmail() {70return email;71}7273public void setEmail(String email) {74this.email = email;75}7677public String getPassword() {78return password;79}8081public void setPassword(String password) {82this.password = password;83}8485public String getCountryCode() {86return countryCode;87}8889public void setCountryCode(String countryCode) {90this.countryCode = countryCode;91}9293public String getPhoneNumber() {94return phoneNumber;95}9697public void setPhoneNumber(String phoneNumber) {98this.phoneNumber = phoneNumber;99}100101public String getFullPhoneNumber() {102return countryCode + phoneNumber;103}104105public int getAuthyId() {106return authyId;107}108109public void setAuthyId(int authyId) {110this.authyId = authyId;111}112113public boolean isVerified() {114return verified;115}116117public void setVerified(boolean verified) {118this.verified = verified;119}120121public Date getDate() {122return date;123}124125public void setDate(Date date) {126this.date = date;127}128}129
Next we will see how to handle the new user form.
When we create a new user, we ask for a name, email address, and a password. In order to validate a new account we also ask the user for a mobile number with a country code. We will use Authy to send a one-time password via SMS to this phone number.
It is now the servlet's responsibility to verify that the user provides the necessary information to create a new user. If the user is created successfully, they will be logged into the system automatically.
1package com.twilio.verification.servlet;23import com.authy.AuthyApiClient;4import com.twilio.verification.lib.RequestParametersValidator;5import com.twilio.verification.lib.SessionManager;6import com.twilio.verification.model.User;7import com.twilio.verification.repository.UsersRepository;89import javax.servlet.ServletException;10import javax.servlet.http.HttpServlet;11import javax.servlet.http.HttpServletRequest;12import javax.servlet.http.HttpServletResponse;13import java.io.IOException;1415public class RegistrationServlet extends HttpServlet {1617private final UsersRepository usersRepository;18private final SessionManager sessionManager;19private final AuthyApiClient authyClient;2021@SuppressWarnings("unused")22public RegistrationServlet() {23this(24new UsersRepository(),25new SessionManager(),26new AuthyApiClient(System.getenv("AUTHY_API_KEY"))27);28}2930public RegistrationServlet(UsersRepository usersRepository, SessionManager sessionManager, AuthyApiClient authyClient) {31this.usersRepository = usersRepository;32this.sessionManager = sessionManager;33this.authyClient = authyClient;34}3536protected void doPost(HttpServletRequest request, HttpServletResponse response)37throws ServletException, IOException {3839String name = request.getParameter("name");40String email = request.getParameter("email");41String password = request.getParameter("password");42String countryCode = request.getParameter("countryCode");43String phoneNumber = request.getParameter("phoneNumber");4445if (validateRequest(request)) {4647com.authy.api.User authyUser = authyClient.getUsers().createUser(email, phoneNumber, countryCode);4849// Create user remotely50if (authyUser.isOk()) {51int authyUserId = authyUser.getId();52// Create user locally53User user = usersRepository.create(new User(name, email, password, countryCode, phoneNumber, authyUserId));5455// Request SMS authentication56authyClient.getUsers().requestSms(authyUserId);5758sessionManager.partialLogIn(request, user.getId());59response.sendRedirect("/verify-code");60}61} else {62preserveStatusRequest(request, name, email, countryCode, phoneNumber);63request.getRequestDispatcher("/registration.jsp").forward(request, response);64}65}6667private boolean validateRequest(HttpServletRequest request) {68RequestParametersValidator validator = new RequestParametersValidator(request);6970return validator.validatePresence("name", "email", "password", "countryCode", "phoneNumber")71&& validator.validateEmail("email");72}7374private void preserveStatusRequest(75HttpServletRequest request,76String name,77String email,78String countryCode,79String phoneNumber) {80request.setAttribute("name", name);81request.setAttribute("email", email);82request.setAttribute("countryCode", countryCode);83request.setAttribute("phoneNumber", phoneNumber);84}85}8687
Now the user is logged in but not verified. In the next steps we'll learn how to verify the user using Authy.
In .environment
we list configuration parameters for the application. These are pulled from system environment variables, which is a helpful way to access sensitive values (like API keys). This prevents us from accidentally checking them into source control. We use the System.getenv
method to load the key and inject the AuthyApiClient
into the RegistrationServlet class.
Now we need our Authy production key (sign up for Authy here). When you create an Authy application the production key is found on the dashboard.
1package com.twilio.verification.servlet;23import com.authy.AuthyApiClient;4import com.twilio.verification.lib.RequestParametersValidator;5import com.twilio.verification.lib.SessionManager;6import com.twilio.verification.model.User;7import com.twilio.verification.repository.UsersRepository;89import javax.servlet.ServletException;10import javax.servlet.http.HttpServlet;11import javax.servlet.http.HttpServletRequest;12import javax.servlet.http.HttpServletResponse;13import java.io.IOException;1415public class RegistrationServlet extends HttpServlet {1617private final UsersRepository usersRepository;18private final SessionManager sessionManager;19private final AuthyApiClient authyClient;2021@SuppressWarnings("unused")22public RegistrationServlet() {23this(24new UsersRepository(),25new SessionManager(),26new AuthyApiClient(System.getenv("AUTHY_API_KEY"))27);28}2930public RegistrationServlet(UsersRepository usersRepository, SessionManager sessionManager, AuthyApiClient authyClient) {31this.usersRepository = usersRepository;32this.sessionManager = sessionManager;33this.authyClient = authyClient;34}3536protected void doPost(HttpServletRequest request, HttpServletResponse response)37throws ServletException, IOException {3839String name = request.getParameter("name");40String email = request.getParameter("email");41String password = request.getParameter("password");42String countryCode = request.getParameter("countryCode");43String phoneNumber = request.getParameter("phoneNumber");4445if (validateRequest(request)) {4647com.authy.api.User authyUser = authyClient.getUsers().createUser(email, phoneNumber, countryCode);4849// Create user remotely50if (authyUser.isOk()) {51int authyUserId = authyUser.getId();52// Create user locally53User user = usersRepository.create(new User(name, email, password, countryCode, phoneNumber, authyUserId));5455// Request SMS authentication56authyClient.getUsers().requestSms(authyUserId);5758sessionManager.partialLogIn(request, user.getId());59response.sendRedirect("/verify-code");60}61} else {62preserveStatusRequest(request, name, email, countryCode, phoneNumber);63request.getRequestDispatcher("/registration.jsp").forward(request, response);64}65}6667private boolean validateRequest(HttpServletRequest request) {68RequestParametersValidator validator = new RequestParametersValidator(request);6970return validator.validatePresence("name", "email", "password", "countryCode", "phoneNumber")71&& validator.validateEmail("email");72}7374private void preserveStatusRequest(75HttpServletRequest request,76String name,77String email,78String countryCode,79String phoneNumber) {80request.setAttribute("name", name);81request.setAttribute("email", email);82request.setAttribute("countryCode", countryCode);83request.setAttribute("phoneNumber", phoneNumber);84}85}8687
Now let's check out the Servlet handling a new user registration and see how it sends a token upon account creation.
Once the user has an authyId
we can actually send a verification code to that user's mobile phone using the Java Client for Authy.
When our user is created successfully via the form we implemented, we send a token to the user's mobile phone to verify their account in our servlet.
1package com.twilio.verification.servlet;23import com.authy.AuthyApiClient;4import com.twilio.verification.lib.RequestParametersValidator;5import com.twilio.verification.lib.SessionManager;6import com.twilio.verification.model.User;7import com.twilio.verification.repository.UsersRepository;89import javax.servlet.ServletException;10import javax.servlet.http.HttpServlet;11import javax.servlet.http.HttpServletRequest;12import javax.servlet.http.HttpServletResponse;13import java.io.IOException;1415public class RegistrationServlet extends HttpServlet {1617private final UsersRepository usersRepository;18private final SessionManager sessionManager;19private final AuthyApiClient authyClient;2021@SuppressWarnings("unused")22public RegistrationServlet() {23this(24new UsersRepository(),25new SessionManager(),26new AuthyApiClient(System.getenv("AUTHY_API_KEY"))27);28}2930public RegistrationServlet(UsersRepository usersRepository, SessionManager sessionManager, AuthyApiClient authyClient) {31this.usersRepository = usersRepository;32this.sessionManager = sessionManager;33this.authyClient = authyClient;34}3536protected void doPost(HttpServletRequest request, HttpServletResponse response)37throws ServletException, IOException {3839String name = request.getParameter("name");40String email = request.getParameter("email");41String password = request.getParameter("password");42String countryCode = request.getParameter("countryCode");43String phoneNumber = request.getParameter("phoneNumber");4445if (validateRequest(request)) {4647com.authy.api.User authyUser = authyClient.getUsers().createUser(email, phoneNumber, countryCode);4849// Create user remotely50if (authyUser.isOk()) {51int authyUserId = authyUser.getId();52// Create user locally53User user = usersRepository.create(new User(name, email, password, countryCode, phoneNumber, authyUserId));5455// Request SMS authentication56authyClient.getUsers().requestSms(authyUserId);5758sessionManager.partialLogIn(request, user.getId());59response.sendRedirect("/verify-code");60}61} else {62preserveStatusRequest(request, name, email, countryCode, phoneNumber);63request.getRequestDispatcher("/registration.jsp").forward(request, response);64}65}6667private boolean validateRequest(HttpServletRequest request) {68RequestParametersValidator validator = new RequestParametersValidator(request);6970return validator.validatePresence("name", "email", "password", "countryCode", "phoneNumber")71&& validator.validateEmail("email");72}7374private void preserveStatusRequest(75HttpServletRequest request,76String name,77String email,78String countryCode,79String phoneNumber) {80request.setAttribute("name", name);81request.setAttribute("email", email);82request.setAttribute("countryCode", countryCode);83request.setAttribute("phoneNumber", phoneNumber);84}85}8687
When the code is sent we redirect to another page where the user can enter the token they received, therefore completing the verification process.
This servlet method handles the submission form. It needs to:
The Authy client provides us with a verify()
method that allows us to pass a user id
and a token
. In this case we just need to check that the API request was successful and, if so, set the User's verified
field to true.
1package com.twilio.verification.servlet;23import com.authy.AuthyApiClient;4import com.authy.api.Token;5import com.twilio.verification.lib.RequestParametersValidator;6import com.twilio.verification.lib.Sender;7import com.twilio.verification.lib.SessionManager;8import com.twilio.verification.model.User;9import com.twilio.verification.repository.UsersRepository;1011import javax.servlet.ServletException;12import javax.servlet.http.HttpServlet;13import javax.servlet.http.HttpServletRequest;14import javax.servlet.http.HttpServletResponse;15import java.io.IOException;1617public class VerifyCodeServlet extends HttpServlet {1819private final UsersRepository usersRepository;20private final SessionManager sessionManager;21private final AuthyApiClient authyClient;22private final Sender sender;2324@SuppressWarnings("unused")25public VerifyCodeServlet() {26this(27new UsersRepository(),28new SessionManager(),29new AuthyApiClient(System.getenv("AUTHY_API_KEY")),30new Sender()31);32}3334public VerifyCodeServlet(35UsersRepository usersRepository, SessionManager sessionManager, AuthyApiClient authyClient, Sender sender) {36this.usersRepository = usersRepository;37this.authyClient = authyClient;38this.sessionManager = sessionManager;39this.sender = sender;40}4142protected void doGet(HttpServletRequest request, HttpServletResponse response)43throws ServletException, IOException {4445request.getRequestDispatcher("/verifyCode.jsp").forward(request, response);46}4748protected void doPost(HttpServletRequest request, HttpServletResponse response)49throws ServletException, IOException {5051String code = request.getParameter("code");5253if (validateRequest(request)) {54int userId = sessionManager.getLoggedUserId(request);55User user = usersRepository.find(userId);5657Token token = authyClient.getTokens().verify(user.getAuthyId(), code);58if (token.isOk()) {59user.setVerified(true);60usersRepository.update(user);61// Send SMS confirmation62sender.send(user.getFullPhoneNumber(), "You did it! Sign up complete :3");6364sessionManager.logIn(request, userId);65response.sendRedirect("/account");66} else {67request.setAttribute("codeError", "Incorrect code, please try again");68request.getRequestDispatcher("/verifyCode.jsp").forward(request, response);69}70} else {71request.getRequestDispatcher("/verifyCode.jsp").forward(request, response);72}73}747576private boolean validateRequest(HttpServletRequest request) {77RequestParametersValidator validator = new RequestParametersValidator(request);7879return validator.validatePresence("code");80}81}82
That's all for token verification! However, our verification form wouldn't be very usable if there wasn't a way to resend a verification code if the message didn't arrive at the end user's handset.
Since the form for re-sending the code is very short, we're going to skip that for this tutorial. Let's just look at the servlet.
This method loads the user
associated with the request and then uses the same Authy API method we used earlier to resend the code.
1package com.twilio.verification.servlet;23import com.authy.AuthyApiClient;4import com.twilio.verification.lib.SessionManager;5import com.twilio.verification.model.User;6import com.twilio.verification.repository.UsersRepository;78import javax.servlet.ServletException;9import javax.servlet.http.HttpServlet;10import javax.servlet.http.HttpServletRequest;11import javax.servlet.http.HttpServletResponse;12import java.io.IOException;1314public class ResendTokenServlet extends HttpServlet {1516private final UsersRepository usersRepository;17private final SessionManager sessionManager;18private final AuthyApiClient authyClient;1920@SuppressWarnings("unused")21public ResendTokenServlet() {22this(23new UsersRepository(),24new SessionManager(),25new AuthyApiClient(System.getenv("AUTHY_API_KEY"))26);27}2829public ResendTokenServlet(30UsersRepository usersRepository, SessionManager sessionManager, AuthyApiClient authyClient) {31this.usersRepository = usersRepository;32this.sessionManager = sessionManager;33this.authyClient = authyClient;34}3536protected void doPost(HttpServletRequest request, HttpServletResponse response)37throws ServletException, IOException {3839int userId = sessionManager.getLoggedUserId(request);40User user = usersRepository.find(userId);4142// Request SMS authentication43authyClient.getUsers().requestSms(user.getAuthyId());4445response.sendRedirect("/verify-token");46}47}48
To wrap things up, let's implement the last step where we confirm that the user's account has been verified with a text message.
In this example, we create a single instance of the Twilio REST API helper, called client.
Then we need to get the account, the messageFactory,
and finally use its sendMessage
method in order to send an SMS to the user's phone.
1package com.twilio.verification.lib;23import com.twilio.http.TwilioRestClient;4import com.twilio.rest.api.v2010.account.MessageCreator;5import com.twilio.type.PhoneNumber;6import com.twilio.verification.lib.Twilio.Config;78public class Sender {910private final TwilioRestClient client;1112public Sender() {13client = new TwilioRestClient.Builder(Config.getAccountSid(), Config.getAuthToken()).build();14}1516public Sender(TwilioRestClient client) {17this.client = client;18}1920public void send(String to, String message) {21new MessageCreator(22new PhoneNumber(to),23new PhoneNumber(Config.getPhoneNumber()),24message25).create(client);26}2728}29
Congratulations! You've successfully verified new user accounts with Authy. Where can we take it from here?
If you're a Java developer working with Twilio, you might want to check out these other tutorials:
Put a button on your web page that connects visitors to live support or salespeople via telephone.
Instantly collect structured data from your users with a survey conducted over a voice call or SMS text messages.