Атрибут autocomplete="one-time-code" сообщает браузеру и операционной системе, что поле предназначено для одноразового кода подтверждения (OTP). На совместимых устройствах пользователь может получить код из SMS и вставить его одним нажатием вместо ручного ввода.
Это простой progressive enhancement: если браузер не умеет автоматически подставлять OTP, поле продолжит работать как обычный <input>.
Не подходит для постоянного PIN-кода, пароля, CAPTCHA, recovery-кода или других значений, которые не являются одноразовым кодом подтверждения.
Готовое решение
<form action="/verify-code/" method="post">
<label for="OtpCode">Код подтверждения</label>
<input type="text"
id="OtpCode"
name="OtpCode"
inputmode="numeric"
autocomplete="one-time-code"
pattern="[0-9]{6}"
maxlength="6"
required
>
<button type="submit">Подтвердить</button>
</form>
Здесь каждый атрибут выполняет свою задачу:
-
type="text"— OTP является строкой, а не числом. Код может начинаться с нуля; -
inputmode="numeric"— показывает цифровую клавиатуру на мобильном устройстве; -
autocomplete="one-time-code"— сообщает браузеру назначение поля; -
pattern="[0-9]{6}"— разрешает шестизначный цифровой код; -
maxlength="6"— ограничивает длину ввода; -
required— запрещает отправку пустого значения средствами браузера.
Почему не type="number"?
Для OTP лучше использовать type="text". Одноразовый код — это последовательность символов, а не число, над которым выполняются математические операции.
Например, код:
012345
должен сохранить начальный ноль. Дополнительно type="number" может показывать элементы изменения числового значения, которые здесь не нужны.
Формат SMS
Для более надёжного распознавания кода можно использовать origin-bound формат SMS, в котором код связывается с доменом сайта.
Код подтверждения: 123456 @example.com #123456
Последняя строка содержит домен после @ и одноразовый код после #.
Для сайта example.com:
@example.com #123456
Такой формат помогает браузеру понять, что код предназначен именно для открытого сайта, а не для произвольной страницы.
Пример использования
- Пользователь вводит номер телефона.
- Сервер генерирует одноразовый код, например
483921. - Пользователь получает SMS.
- Браузер или операционная система распознаёт код.
- Над клавиатурой появляется предложение вставить
483921. - Пользователь подтверждает форму.
- Сервер проверяет код и помечает его использованным.
Никакой JavaScript для самого autocomplete="one-time-code" не требуется.
Краевые случаи — сломается или будет работать хуже, если…
- OTP разбит на шесть отдельных
<input>— автоматическое заполнение обычно надёжнее работает с одним полем; - код содержит буквы, но установлен
inputmode="numeric"и цифровойpattern; - браузер или операционная система не поддерживает получение OTP — пользователь просто введёт код вручную;
- сообщение пришло на другое устройство, между которым и текущим устройством нет поддержки передачи кодов;
- SMS имеет нестандартный формат, который система не смогла распознать;
- JavaScript очищает или перерисовывает поле после того, как браузер вставил значение.
Если дизайн требует визуально показать шесть отдельных ячеек, практичнее оставить внутри один настоящий <input>, а разделение на символы сделать средствами CSS.
Безопасность
autocomplete="one-time-code" улучшает UX, но никак не проверяет код и не делает механизм OTP безопасным сам по себе.
Проверка всегда должна выполняться на сервере.
- генерируйте код криптографически безопасным генератором;
- задавайте ограниченный срок действия;
- разрешайте использовать код только один раз;
- привязывайте код к пользователю, сессии или конкретному действию;
- ограничивайте количество попыток проверки;
- ограничивайте частоту повторной отправки кодов;
- не записывайте действующий OTP в обычные access/error/application logs;
- после успешной проверки сразу делайте код недействительным.
Для критичных операций SMS-код не стоит рассматривать как единственный сильный фактор аутентификации: существуют SIM-swap, перехват сообщений и фишинг. Для более сильной защиты стоит рассмотреть WebAuthn/passkeys.
Дополнение: WebOTP API
autocomplete="one-time-code" и WebOTP — не одно и то же.
Первый вариант лишь сообщает браузеру назначение поля. WebOTP API позволяет поддерживаемому браузеру программно получить OTP из специально сформированного SMS.
Это можно добавить как progressive enhancement:
const OtpInput = document.querySelector('input[autocomplete="one-time-code"]');
if (OtpInput && 'OTPCredential' in window) {
const Form = OtpInput.closest('form');
const Abort = new AbortController();
if (Form) {
Form.addEventListener('submit', () =>
{
Abort.abort();
}
, {
once: true
}
);
}
navigator.credentials.get( {
otp: {
transport: ['sms']
}
, signal: Abort.signal
}
) .then((Credential) =>
{
OtpInput.value = Credential.code;
OtpInput.dispatchEvent(new Event('input', {
bubbles: true
}
));
}
) .catch((Error) =>
{
if (Error.name !== 'AbortError') {
console.warn('WebOTP недоступен:', Error);
}
}
);
}
WebOTP следует считать дополнительным улучшением. Основная форма должна нормально работать и без него.
Производительность
Сам атрибут autocomplete="one-time-code" практически ничего не стоит с точки зрения производительности: это обычная подсказка браузеру.
В реальном OTP-процессе основная задержка обычно находится не во фронтенде, а в генерации и доставке сообщения через SMS-провайдера.
Совместимость
Значение one-time-code поддерживается современными браузерами, но конкретное поведение автозаполнения зависит от браузера, операционной системы и источника OTP.
Поэтому код следует строить по принципу progressive enhancement:
<input type="text" inputmode="numeric" autocomplete="one-time-code" name="OtpCode" required >
Если автозаполнение доступно — пользователь получает более удобный интерфейс. Если нет — вводит код вручную.
WebOTP API имеет более ограниченную браузерную поддержку и работает только в безопасном контексте HTTPS, поэтому делать его обязательным для работы формы не следует.
Комментарии
0Нашли ошибку или хотите дополнить материал?