Voice OTP Authenticator With WSO2 Identity Server
What is WSO2 Identity Server ?
WSO2 Identity Server (WSO2 IS) simplifies your organization’s Customer Identity and Access Management (CIAM) needs. It ensures seamless integration with various applications, enabling single sign-on (SSO), social login, identity federation, API security, strong authentication, account management, privacy compliance, and much more.
What is Voice OTP Authenticator ?
The Voice OTP authenticator is a local authenticator that can be used for multi-factor authentication with WSO2 Identity Server. It was released with WSO2 Identity Server version 6.1.0.
The Voice OTP authenticator is designed to connect with any external third-party voice OTP provider through a REST API.
You can add this authenticator as an extra security step (e.g., as a second authentication step).
Also, this authenticator is available in the Identity Server Connector store.
https://store-v2.wso2.com/connector/identity-outbound-auth-voice-otp
How to Setup the Voice OTP Authenticator with IS 6.1.0 ?
In this article, I will show you how to set up the Voice OTP authenticator with WSO2 IS version 6.1.0 to send the OTP via the Twilio OTP provider.
- Download the WSO2 IS 6.1.0 version. If you are a subscribed customer , you can update the IS distribution to the latest update level to get all bug fixes, security fixes and product improvements.
- Download the voice otp connector jar file(org.wso2.carbon.extension.identity.authenticator.voiceotp.connector-<version>.jar) and place it in the <IS_HOME>/repository/components/dropins directory.
- Download the voiceOtp.jsp , voiceOtpError.jsp , voiceMobile.jsp files and place them in the <IS_HOME>/repository/deployment/server/webapps/authenticationendpoint webapp.
- Add the below configurations to the <IS_HOME>/repository/conf/deployment.toml file.
[authentication.authenticator.voice_otp]
name="VoiceOTP"
enable=true
parameters.VoiceOTPAuthenticationEndpointURL="authenticationendpoint/voiceOtp.jsp"
parameters.VoiceOTPAuthenticationEndpointErrorPage="authenticationendpoint/voiceOtpError.jsp"
parameters.MobileNumberRegPage="authenticationendpoint/voiceMobile.jsp"
parameters.RetryEnable=true
parameters.ResendEnable=true
parameters.BackupCode=true
parameters.VoiceOTPEnableByUserClaim=true
parameters.VoiceOTPMandatory=false
parameters.CaptureAndUpdateMobileNumber=true
parameters.SendOTPDirectlyToMobile=false
parameters.redirectToMultiOptionPageOnFailure=false
parameters.enable_payload_encoding_for_voice_otp=true
parameters.screenUserAttributeMaskRegex="^\\+(\\d{8})"
[[servlet]]
name="voice_otp.do"
jsp="/voiceOtp.jsp"
url="/voice_otp.do"
[[servlet]]
name="voice_otp_error.do"
jsp="/voiceOtpError.jsp"
url="/voice_otp_error.do"
[[servlet]]
name="voice_mobile.do"
jsp="/voiceMobile.jsp"
url="/voice_mobile.do"
5. Add the below keyword mappings to the <IS_HOME>/repository/deployment/server/webapps/authenticationendpoint/WEB-INF/classes/org/wso2/carbon/identity/application/authentication/endpoint/i18n/Resources.properties file. These will give the correct description for the specific word mapping at run time.
# SMS OTP
enter.code.sent.smsotp=Enter the code sent to your mobile phone:
auth.with.smsotp=Authenticating with SMSOTP
error.send.smsotp=Unable to send code to your phone number
error.failed.with.smsotp=Failed Authentication with SMSOTP
error.smsotp.disabled=Enable the SMS OTP in your Profile. Cannot proceed further without SMS OTP authentication.
error.user.not.found.smsotp=User not found in the directory. Cannot proceed further without SMS OTP authentication.
# Voice OTP
enter.code.sent.voiceotp=Enter the code sent to your mobile phone:
auth.with.voiceotp=Authenticating with VoiceOTP
error.send.voiceotp=Unable to send code to your phone number
error.failed.with.voiceotp=Failed Authentication with VoiceOTP
error.voiceotp.disabled=Enable the Voice OTP in your Profile. Cannot proceed further without Voice OTP authentication.
error.user.not.found.voiceotp=User not found in the directory. Cannot proceed further without Voice OTP authentication.
# SMS OTP & Voice OTP
error.code.expired.resend=The code entered is expired. Click Resend Code to continue.
error.wrong.code=The code entered is incorrect. Authentication Failed!
error.token.expired=The code entered is expired. Authentication Failed!
error.token.expired.email.sent=The code entered is expired. Please check inbox for a new OTP.
authenticate.button=Authenticate
please.enter.code=Please enter the code!
enter.phone.number=Enter Your Mobile Phone Number
6. Start the Identity Server(sh <IS_HOME>/bin/wso2server.sh).
7. Create the below claims if they are not already available.
1. Create "http://wso2.org/claims/identity/voiceotp_disabled" claim.
* Go to management console -> claims -> Add -> Add Local Claim.
* Enter "http://wso2.org/claims/identity/voiceotp_disabled" as the claim URI.
* Enter "voiceotp_disabled" as the Display Name and Description.
* Add correct attribute mapping for this claim for the Primary userstore.
2. Create "http://wso2.org/claims/identity/failedVoiceOtpAttempts" claim similarly.
3. Create "http://wso2.org/claims/otpbackupcodes" claim similarly if it is not exists.
4. Create "http://wso2.org/claims/identity/failedLoginLockoutCount" claim similarly if it is not exists.
5. Create "http://wso2.org/claims/identity/accountLocked" claim similarly if it is not exists.
6. Create "http://wso2.org/claims/identity/unlockTime" claim similarly if it is not exists.
7. Create "http://wso2.org/claims/identity/lockedReason" claim similarly if it is not exists.
8. Then we need to Create a Identity Provider with the Voice OTP authenticator where we can configure the external voice otp provider(in this case Twillio).
Go to management console -> identity providers -> Add.
- Provide the IdP name as “Voice OTP” . Then go to Federated Authenticators -> Voice OTP Authenticator .
- Description for each of the field can be found below.
1. Tick "Enable" checkbox.
2. Enter the API endpoint URL of the voice otp provider as the "Voice URL"(Mandatory).The placeholders are $ctx.num which will be replaced with the user's mobile number and $ctx.otp which will replace with the otp .
3. Enter the REST API method name of the endpoint as the "Http Method"(Mandatory)
4. Enter the headers required(eg : Authorization header) to invoke the endpoint as the "HTTP Headers". The placeholders are $ctx.num which will be replaced with the user's mobile number and $ctx.otp which will replace with the otp .
5. Enter the payload with the placeholders if required for the endpoint as the "Http Payload". The placeholders are $ctx.num which will be replaced with the user's mobile number and $ctx.otp which will replace with the otp .
6. Enter the successful response code which will return from the Voice otp provider(eg : 200 , 201) as the "HTTP Response code". If nothing specifies in here, connector will check whether the response code is either 201,202,200 and consider all three as successful scenario.
7. If the "Enable OTP Separation" is enabled, the otp will be separated with the character that enters to the "Separate OTP Digits" section. Enabling this required if it is necessary to split and speak the numbers.
8. The "Separate OTP Digits" section represents the character which needs to be added between the otp numbers before sending to the Voice OTP provider. For example, by default it will have "%2B" which represents URL encoded + character.
9. The "Divisor value" represents how the otp number separation should be handled. For example the default value is 1 and it will add the separation character explains in 6th point between every number. Eg: 1%2B2%2B3%2B4%2B5%2B6. If the divisor value is two it will be like 12%2B34%2B56. And it will speak like "TWELVE THIRTYFOUR FIFTYSIX" during the call.
10. Enter true for the "Show Detailed Error Information" section if you need detailed error message.
11. Enter any comma separated values to the "Mask values in Error Info " section, if you need some error text needs to be masked with asterisk character(*).
12. Enter the regex pattern in the "Mobile Number Regex Pattern" section, if it is required to validate the mobile number pattern when capturing and updating the mobile number during the authentication(When user doesn't have a mobile number configured in the user profile).
13. Enter error message for invalid mobile number pattern in the "Regex Violation Error Message" section.
Since we are planing to use Twillio as our voice otp provider during this tutorial, we need to do the below steps from the Twillio side.
- Create a twillio account and register a number which we can use for outgoing calls in your project.
- The Voice should be enabled for the number that you have registered.
- Create a Twiml bin to have the message that we want to read during the call . Here the {{verification_code}} will be replaced by the verification code which will be passed from the identity server.
Below is the sample twiml bin logic.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Hello , Your Verification Code IS {{verification_code}}</Say>
</Response>
The configurations needed to set up the Voice OTP authenticator on the management console with Twilio can be found here.
The {{verification_code}} will be passed in the payload of the API call.
Voice URL https://api.twilio.com/2010-04-01/Accounts/{Account_ID}/Calls.json
HTTP Method : POST
HTTP Headers : Authorization: Basic base64encode(Account SID : Auth Token)
HTTP Payload: Url=https%3A%2F%2Fhandler.twilio.com%2Ftwiml%2F{handler_id}%3Fverification_code%3D$ctx.otp&To=$ctx.num&From=%2B{twillio_registered_mobile_without_plus_character}
HTTP Response Code: 201
Enable OTP Separation : true
Separate OTP Digits : %2B
Divisor value : 2
There are a few pieces of information needed from Twilio console to configure the above fields, such as Account ID, Account SID, Auth Token, TWIML Handler ID, and Twilio Registered Mobile Number.
After entering this information, you can save the IdP configurations.
9. Create a service provider to setup “Voice OTP” IdP as the second step authenticator.
- Go to Management Console -> Service Providers -> Add
- Name the application as “Test App” .
- For this app, we will use “OAuth/OpenID Connect” protocol as the inbound protocol.
- Configure the callback URL as
https://localhost:5000
- Go to “Local & Outbound Authentication Configuration” and then click on “Advanced Configuration”.
- Add the “Voice OTP” as the second step . The “Voice OTP” IdP will be listed under “Federated Authenticators” section.
- Save the configurations.
10. Create a User and configure mobile number. We will use this user for testing. Make sure to configure the number with country code.
11. Let’s test the flow.
- Initiate the login flow for the serivce provider that created.
https://localhost:9443/oauth2/authorize?scope=openid&response_type=code&redirect_uri=https://localhost:5000&client_id=<client_id_of_the_application>
- Since we have configured the basic authenticator(username & password), you will get the login page to enter the username & password of the user.
- After entering the user credentials correctly, you will be directed to a page to enter the OTP, and at the same time, you will receive the OTP via a phone call if everything is configured correctly. If the mobile number is not configured in the user profile, the user will be prompted to enter it after successfully completing the first step.
- When you answer the call , you will be able to hear the message that you have configured in the twiml bin.
- After you enter the otp code correctly, user will be redirected to the callback URL configured.
Hope you were able to setup the Voice OTP Authenticator with Identity Server 6.1.0 successfully.
If you encounter any issues or have any concerns, please respond to this story. I’m happy to help! :)
Thanks for reading ! You can read my other articles from here.
Feel free to connect with me on GitHub or LinkedIn!