Start · Sprachen · JavaScript · Referenz · OTPCredential

OTPCredential

Schnittstelle

Enthält das Einmalpasswort (OTP) aus einer SMS, wenn ein WebOTP-Aufruf von <code>navigator.credentials.get({ otp })</code> erfolgreich war.

seit JavaScript Chrome/Edge 84+ (Android), kein Firefox/Safari – e Kategorie: webapi

Signatur

interface OTPCredential extends Credential

Beschreibung

Die Schnittstelle OTPCredential gehört zur WebOTP API. Ein Objekt dieses Typs bekommst du, wenn das Promise von navigator.credentials.get() mit der Option otp: { transport: ["sms"] } erfüllt wird. Es enthält den Einmalcode aus einer speziell formatierten SMS. Die Nutzerin muss dafür keine App wechseln und nichts abtippen.

OTPCredential erbt von Credential. Deshalb gibt es die Eigenschaften id und type (immer "otp"). Dazu kommt die eigene Eigenschaft code, ein string mit dem Einmalpasswort. Einen öffentlichen Konstruktor gibt es nicht: Objekte entstehen nur über die Credential Management API.

Damit der Browser die SMS erkennt, muss ihre letzte Zeile so aussehen: @beispiel.de #123456. Also ein @ mit dem Host der Seite, dann # mit dem Code. Wird die Seite in einem Cross-Origin-iframe eingebettet, folgt die Origin des iframes: @top.de #123456 @iframe.de. Der Browser fragt die Nutzerin um Zustimmung, bevor er den Code an die Seite weitergibt.

Typischer Einsatz: Telefonnummer prüfen bei der Registrierung, Zwei-Faktor-Anmeldung oder Bestätigung einer Zahlung auf Mobilgeräten. Nutze die API immer als progressive Verbesserung zusätzlich zu einem normalen Eingabefeld mit autocomplete="one-time-code".

Parameter

Name Typ Default Beschreibung
$code Pflicht string Nur lesbare Eigenschaft: der Einmalcode aus der SMS (der Teil nach #).
$id Pflicht string Geerbt von Credential: Kennung der Zugangsdaten.
$type Pflicht string "otp" Geerbt von Credential: bei diesem Typ immer "otp".

Beispiele

Unterstützung prüfen und OTP automatisch einfügen

// HTML: <form id="otp-form"><input autocomplete="one-time-code" name="otp"></form>
if ('OTPCredential' in window) {
  window.addEventListener('DOMContentLoaded', async () => {
    const input = document.querySelector('input[autocomplete="one-time-code"]');
    if (!input) return;

    const ac = new AbortController();
    // Wird das Formular von Hand abgeschickt, das Warten auf die SMS beenden
    input.form?.addEventListener('submit', () => ac.abort());

    try {
      const otp = await navigator.credentials.get({
        otp: { transport: ['sms'] },
        signal: ac.signal
      });
      console.log(otp.type, otp.code);
      input.value = otp.code;
      input.form?.requestSubmit();
    } catch (err) {
      console.warn('WebOTP nicht erfolgreich:', err.name);
    }
  });
}
otp 123456

Passendes SMS-Format (Server-Seite, Node.js)

// Die letzte Zeile muss "@<host> #<code>" lauten
const buildOtpSms = (host, code) =>
  `Ihr Bestätigungscode lautet ${code}.\n\n@${host} #${code}`;

console.log(buildOtpSms('shop.beispiel.de', '482913'));
Ihr Bestätigungscode lautet 482913. @shop.beispiel.de #482913

Zeitlimit mit AbortSignal.timeout()

const fetchOtp = async (ms = 60_000) => {
  if (!('OTPCredential' in window)) return null;
  try {
    const cred = await navigator.credentials.get({
      otp: { transport: ['sms'] },
      signal: AbortSignal.timeout(ms)
    });
    return cred instanceof OTPCredential ? cred.code : null;
  } catch {
    return null; // Zeit abgelaufen, abgelehnt oder abgebrochen
  }
};

const code = await fetchOtp(30_000);
console.log(code ?? 'Bitte Code manuell eingeben');
482913

// Wichtig · Fallstricke

  • Kompatibilität: Die API ist experimentell. Sie funktioniert nur in Chromium-Browsern auf Android (ab Chrome 84) und in Teilen auf dem Desktop, wenn das Gerät gekoppelt ist. Firefox und Safari unterstützen sie nicht. Safari auf iOS füllt Codes stattdessen über autocomplete="one-time-code" aus. Prüfe die Unterstützung daher immer mit 'OTPCredential' in window.
  • Nur sichere Kontexte: Die Seite muss über HTTPS laufen. In iframes braucht es die Permissions Policy allow="otp-credentials".
  • SMS-Format: Stimmt der Host in der letzten Zeile nicht genau mit der Origin überein, bleibt das Promise einfach offen. Einen Fehler gibt es dann nicht. Setze deshalb immer ein Zeitlimit über signal.
  • Sicherheit: Die Zuordnung an die Origin schützt vor Phishing auf fremden Domains. Den Code musst du trotzdem auf dem Server prüfen. Er muss nach kurzer Zeit ablaufen und darf nur einmal gültig sein. SMS-OTP gilt wegen SIM-Swapping als schwacher zweiter Faktor. Für starke Anmeldung sind WebAuthn/Passkeys besser.
  • Pro Seite ist immer nur eine offene Anfrage erlaubt. Brich alte Anfragen mit AbortController ab.