DEV Community

Cover image for How to auto verify OTP on the web using the new Web OTP API?
Jyotishman Saikia
Jyotishman Saikia

Posted on

How to auto verify OTP on the web using the new Web OTP API?

Alt Text

WebOTP is an important API to verify OTP on the phone web browser automatically without having to manually type your OTP.
Chrome recently released this feature and it will work only with version 84 or above.

So, this tutorial will explain to you step by step how to implement WebOTP with javascript-

  1. The first step before starting is we should know the SMS rules for the API to work correctly.
    A valid verification message might look like the following:
    Your OTP is: 1598
    @www.amazon.com #1598
    Here @www.amazon.com is the domain of the OTP verification page and #1598 is the OTP.

  2. if ('OTPCredential' in window) {
    window.addEventListener('DOMContentLoaded', e => {
    const ac = new AbortController();
    navigator.credentials.get({
    otp: { transport:['sms'] },
    signal: ac.signal
    }).then(otp => {
    alert(otp.code)
    }).catch(err => {
    console.log(err)
    });
    })
    } else {
    alert('WebOTP not supported!.')
    }

    Demo link- https://jyotishman.github.io/webOTPAPI/

Top comments (18)

Collapse
 
mhmdndri profile image
Mohammad Naderi

Hey Jyotishman, I'm using the same in my nextJS App, but when I get the pop-up and press allow, it doesn't fill my input with the OTP number; I tried a million ways to fix it, but I get Nothing. Do u know why?

Collapse
 
jyotishman profile image
Jyotishman Saikia

Hey in that case first you will have to pick the otp from the message. Why dont u console.log your otp first from the message ?

Collapse
 
divya_agarwal_d188f70a567 profile image
Divya Agarwal

hey I wrote
onst handleOTPAutoFill = useCallback(() => {
if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const ac = new AbortController();
navigator.credentials
.get({
otp: { transport: ['sms'] },
signal: ac.signal,
} as OTPCredentialRequestOptions)
.then((otp: any) => {
if (otp && otp.code) {
console.log(otp, 'OTP in autofill');
const otpArray = otp.code.split('');
console.log(otpArray, 'OTParray');
const updatedOtpValue = otpArray.slice(0, 6);
console.log(updatedOtpValue, 'updatedOTPValue');
setOtpValue(updatedOtpValue);
handleOTPChange(updatedOtpValue);
handleVerifyOnClick();
console.log('abort after this');
ac.abort();
console.log('end');
}
})
.catch(err => {
console.error('OTP Autofill error:', err);
});
});
} else {
alert('WebOTP not supported!.');
}
}, []);

useEffect(() => {
handleOTPAutoFill();
}, [handleOTPAutoFill]);

and chrome ask for permission but nothing happens after it
it says the otp for your adhar num xxx is 648375.
what should I do @jyotishman @mhmdndri

Collapse
 
jyotishman profile image
Jyotishman Saikia

are u trying on localhost ?

Collapse
 
ashishjob0424 profile image
ashishjob0424

Hi Mohammad,

I am also facing the same problem, can you please help me to resolve this issue.

Collapse
 
parthasn profile image
Partha Sarathi Nayak

Hi Mohammed, was your problem resolved? If yes, then can you tell me how? I am facing the same issue. Thanks.

Collapse
 
mhmdndri profile image
Mohammad Naderi

Yes, I solve it. The most important part is the text of the SMS. I deploy and test, and as he said in the article, it should contain the domain Address and the OTP code with #. remember you should use "navigator.credential.get " in the useEffect. I hope you can solve it, but If you can't, text me here to check your code together and solve it.

Thread Thread
 
suhasini_singyan_8aa3ad76 profile image
Suhasini Singyan

Hey can you help me with this. facing issue as it does ask for permission but doesn't paste the OTP.

Thread Thread
 
jyotishman profile image
Jyotishman Saikia

What issue are u getting? @suhasini_singyan_8aa3ad76

Collapse
 
ashishjob0424 profile image
ashishjob0424

Hi Partha,

I am also facing the same problem, can you please help me to resolve this issue.

Collapse
 
oceanrational profile image
VikramJS • Edited

Hey Jyotishman. I am using same for a while but it pop up everytime an sms having OTP received from different source like bank, zomatoetc.,

how can i prevent it. pop up everytime a new OTP SMS received.
I tried on button clicked but no luck.

with correct domain name
dev-to-uploads.s3.amazonaws.com/i/...

with wrong domain name.
dev-to-uploads.s3.amazonaws.com/i/...

Collapse
 
jyotishman profile image
Jyotishman Saikia

hi, Can you send the sample code so i that i can assist u better where you might be wrong.

Collapse
 
oceanrational profile image
VikramJS • Edited

This is form page.


< form action="ok.html" method="POST" >

< input type="number" class="form-control" id="mobileNo" placeholder="10 Digit Mobile No">

< button class="btn btn-primary" onfocus="test()" name="sendOTP">Validate

< input type="text" class="form-control" id="OTP" placeholder="OTP" autocomplete="one-time-code">

< button class="btn btn-primary btn-style" id="validateOTP">Verify
< /form>

And this is script.

function test(){


if ('OTPCredential' in window) {

console.log("in OTPCredentials");

window.addEventListener("DOMContentLoaded", e => {

const input = document.querySelector('input[autocomplete="one-time-code"]');

const button = document.querySelector("button[type='submit']");

if (!input) return;

const ac = new AbortController();

const form = input.closest('form');

if (form) {

form.addEventListener('submit', e => {

console.log("ac.abort() is called");

ac.abort();

});

}

console.log("WebOTP API is called");

navigator.credentials.get({

otp: { transport:['sms'] },

signal: ac.signal

}).then(otp => {

input.value = otp.code;

if (form) form.submit();

console.log("submit() is called");

navigator.credentials.preventSilentAccess();

}).catch(err => {

console.log(err);

});

});

}

const message = document.querySelector('#message');

message.innerText = Your OTP is: 123456.\n@${window.location.host} #123456;

}

Thread Thread
 
sumit_1991 profile image
Sumit Kandoi

@oceanrational : I have one doubt on your above code why you gave

const form = input.closest('form');
form id should come instead of form. What do you think?

Collapse
 
sumit_1991 profile image
Sumit Kandoi • Edited

@jyotishman In your code implementation I have seen

const form = input.closest('form'); which form is this ?

When we are submitting form does it means after otp is autofilled it will redirect to next page

I have written below code but it's not submitting my custom form.
Do we need to give input.closest('form '); here for every case ?

Below is my code implementation for autofill otp

if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
const ac = new AbortController();
const form = input.closest('firstInput');
if (form) {
form.addEventListener('submit', e => {
ac.abort();
});
}
navigator.credentials.get({
otp: {transport: ['sms']},
signal: ac.signal
}).then(otp => {
input.value = otp.code;

            console.log("Form Value ::::" + form);
            if (form) form.submit();
        }).catch(err => {
            console.log(err);
        });
    });
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
mobtec profile image
Guilherme

hi Jyotishman! is this api / demo still working?
i've tried your demo and isn't working for me. Im using clicksend.com to send the SMS to my device. the auth dialog never appers, thus the reading of the SMS...

thanks!

Collapse
 
sahilbisht0602 profile image
Sahil Bisht

Hey Jyotishman, My input have 4 separate field how to autocomplete them any idea ? I think this will work only if we have a single input field

Collapse
 
jyotishman profile image
Jyotishman Saikia

in that case u have to programatically fetch the otp and split the numbers into 4 digits.

or another case would be make one input and design from css that it look like 4 input boxes.