ইমিডিয়েট UI মোডের মাধ্যমে দ্রুত সাইন-ইন করা

কোনও যাচাই না করা ব্যবহারকারী "সাইন-ইন করুন" লিঙ্কে ক্লিক করলে, চেক-আউট শুরু করলে, পছন্দের তালিকায় কোনও আইটেম সেভ করলে অথবা কোনও নিবন্ধের পেওয়ালে পৌঁছালে, তাকে একটি নির্দিষ্ট সাইন-ইন পৃষ্ঠায় নিয়ে গেলে, তিনি যে কাজ করছিলেন তা থেকে তার মনোযোগ সরে যায় এবং ব্যবহারকারী ড্রপ-অফ বেড়ে যায়। ডিভাইসে স্থানীয় পাসকী (publicKey) বা সেভ করা পাসওয়ার্ড (password: true) থাকলে, ইমিডিয়েট UI মোড (navigator.credentials.get()-এ uiMode: 'immediate') অবিলম্বে একটি ইউনিফায়েড ব্রাউজার অ্যাকাউন্ট বাছাইকারী দেখানোর মাধ্যমে প্রাসঙ্গিক দ্রুত সাইন-ইন করার সুবিধা দেয়।

স্ট্যান্ডার্ড মোডাল WebAuthn প্রম্পটের মতো নয়—যা সবসময় ব্রাউজার UI দেখায় এবং ক্রস-ডিভাইস QR কোড বা এক্সটার্নাল নিরাপত্তা কী-তে ফিরে যায়—ডিভাইসে কোনও উপযুক্ত ক্রেডেনশিয়াল স্থানীয়ভাবে উপলভ্য না থাকলে, ইমিডিয়েট UI মোড NotAllowedError-এর সাথে দ্রুত ব্যর্থ হয়। এটি আপনার অ্যাপ্লিকেশনকে, ফিরে আসা ব্যবহারকারীদের একটি ট্যাপের মাধ্যমে যাচাই করতে দেয় এবং লোকাল ক্রেডেনশিয়াল ছাড়া ব্যবহারকারীদের নির্বিঘ্নে আপনার স্ট্যান্ডার্ড সাইন-ইন পৃষ্ঠা, গেস্ট চেক-আউট বা ইনলাইন লগ-ইন ফর্মে নিয়ে যায়।

বর্তমান পৃষ্ঠা থেকে নেভিগেট করে বেরিয়ে যাওয়ার ঠিক আগে ব্যবহারকারীর স্পষ্ট ইনটেন্টের মুহূর্তে ব্যবহারকারীর শুরু করা ইভেন্ট হ্যান্ডলারের (ট্রানজিয়েন্ট ব্যবহারকারী অ্যাক্টিভেশন প্রয়োজন) মধ্যে ইমিডিয়েট UI মোড ট্রিগার করুন। অবিলম্বে যাচাইকরণ সফল হলে, ব্যবহারকারীর উদ্দেশ্য অবিলম্বে সম্পূর্ণ করুন (বর্তমান পৃষ্ঠাটি আপডেট করে বা সরাসরি তাদের যাচাইকৃত গন্তব্যে এগিয়ে যাওয়ার মাধ্যমে)। NotAllowedError-এর সাথে এটি ব্যর্থ হলে, ব্যবহারকারীর উদ্দেশ্য সম্পূর্ণ করার জন্য একটি পাথ সহ সাইন-ইন বা রেজিস্ট্রেশন ফ্লো দেখান।

সম্ভাব্য ব্যবহারিক প্রয়োগ:

  • হেডার সাইন-ইন লিঙ্ক বা বোতাম ইন্টারসেপশন: ফিরে আসা ব্যবহারকারীদের অবিলম্বে যাচাই করতে গ্লোবাল "সাইন-ইন" লিঙ্কে (event.preventDefault()) ক্লিক ইন্টারসেপ্ট করুন অথবা NotAllowedError-এ নির্দিষ্ট সাইন-ইন পৃষ্ঠায় নেভিগেট করা চালিয়ে যান।
  • চেক-আউটের আগে ডায়নামিক সাইন-ইন: পুরনো ক্রেতারা "চেক-আউট করতে এগিয়ে যান" বিকল্পে ক্লিক করলে, একবার ট্যাপ করেই তাদের যাচাই করুন যাতে তারা সরাসরি শিপিং ও পেমেন্টের ধাপে পৌঁছে যান অথবা ফলব্যাক হিসেবে স্ট্যান্ডার্ড সাইন-ইন বা গেস্ট চেক-আউট স্ক্রিনে ট্রানজিশন করেন।
  • মাইক্রো-অ্যাকশনের (পছন্দ, লাইক, বুকমার্ক, সেভ) জন্য ইনলাইন সাইন-ইন: সাইন-আউট করা ব্যবহারকারী মাইক্রো-অ্যাকশন বোতামে ক্লিক করলে, সেই জায়গাতেই যাচাইকরণ করুন এবং অবিলম্বে অ্যাকশনটি সম্পূর্ণ করুন (যেমন, aria-pressed="true" টগল করা) অথবা রিটার্ন URL প্যারামিটার সহ একটি ফলব্যাক লগ-ইন মডেল বা সাইন-ইন পৃষ্ঠা খুলুন।
  • ইন-আর্টিকেল সফ্ট পেওয়াল: পেওয়াল ব্যানারে "আপনার অ্যাকাউন্ট দিয়ে পড়া চালিয়ে যান" বিকল্পে ক্লিক করলে, পাঠকদের সেই জায়গাতেই যাচাই করা হয় অথবা ফলব্যাকে ইনলাইন সাইন-ইন বা রেজিস্ট্রেশন ফর্ম বড় করা হয়।

যেসব অ্যান্টি-প্যাটার্ন এড়িয়ে চলতে হবে:

  • নির্দিষ্ট সাইন-ইন পৃষ্ঠায় ইমিডিয়েট UI মোড ব্যবহার করবেন না: আপনার চূড়ান্ত গন্তব্যের সাইন-ইন পৃষ্ঠায় প্রাথমিক "সাইন-ইন করুন" বা "পাসকী ব্যবহার করে সাইন-ইন করুন" বোতামের সাথে কখনও uiMode: 'immediate' অ্যাটাচ করবেন না। ব্যবহারকারীরা নির্দিষ্ট সাইন-ইন পৃষ্ঠায় তখনই পৌঁছান যখন বর্তমান ডিভাইসে তাদের কোনও স্থানীয় ক্রেডেনশিয়াল থাকে না অথবা যখন তারা ক্রস-ডিভাইস পাসকী (ফোন দিয়ে QR কোড স্ক্যান করা) বা এক্সটার্নাল হার্ডওয়্যার নিরাপত্তা কী ব্যবহার করতে চান। যেহেতু uiMode: 'immediate' ক্রস-ডিভাইস QR কোড ও নিরাপত্তা 'কী' বিকল্পকে দমন করে এবং কোনও লোকাল ক্রেডেনশিয়াল না থাকলে অবিলম্বে NotAllowedError দেখায়, তাই ডেডিকেটেড সাইন-ইন পৃষ্ঠায় এটি ব্যবহার করলে ব্যবহারকারী এমন একটি ডেড এন্ডে আটকে যান যেখানে বোতামে ক্লিক করলে কিছুই হয় না। একটি নির্দিষ্ট সাইন-ইন পৃষ্ঠায়, স্ট্যান্ডার্ড মডাল navigator.credentials.get({ publicKey }) বোতামের সাথে পেয়ার করা ফর্ম ইনপুটে কন্ডিশনাল UI (autocomplete="username webauthn" সহ mediation: 'conditional') ব্যবহার করুন (পাসকী যাচাইকরণ দেখুন)।
  • স্টেপ-আপ রি-অথেন্টিকেশনের জন্য ইমিডিয়েট UI মোড ব্যবহার করবেন না: সংবেদনশীল অপারেশন (যেমন পাসওয়ার্ড পরিবর্তন করা, শিপিং অ্যাড্রেস আপডেট করা, সেভ করা পেমেন্ট পদ্ধতি এডিট করা অথবা নতুন পাসকী যোগ করা) করার আগে, আগে থেকেই সাইন-ইন করে থাকা ব্যবহারকারীকে রি-অথেন্টিকেট করতে কখনও uiMode: 'immediate' ব্যবহার করবেন না। পুনরায় যাচাইকরণ করার সময়, সাইন-ইন করা ব্যবহারকারীর ক্রেডেনশিয়াল সংক্রান্ত প্রম্পটটি অবশ্যই খালি নয় এমন allowCredentials তালিকার মাধ্যমে সীমাবদ্ধ করতে হবে, যা ইমিডিয়েট UI মোড NotAllowedError-এর মাধ্যমে বাতিল করে দেয় এবং allowCredentials বাদ দিলে ব্যবহারকারী অসাবধানতাবশত বর্তমানে সাইন-ইন করা অ্যাকাউন্টের পরিবর্তে অন্য একটি অ্যাকাউন্ট বেছে নিতে পারেন। স্টেপ-আপ রি-অথেন্টিকেশনের জন্য, পাসকী রি-অথেন্টিকেশন অনুসরণ করুন।

গোপনীয়তা ও নিরাপত্তা সংক্রান্ত সীমাবদ্ধতা

uiMode: 'immediate'-এর জন্য অনুরোধ করা হলে, ব্রাউজার কঠোর গোপনীয়তা ও নিরাপত্তা সংক্রান্ত নিয়ম এনফোর্স করে:

  • ট্রানজিয়েন্ট ব্যবহারকারী অ্যাক্টিভেশন প্রয়োজন: সাইলেন্ট ক্রেডেনশিয়াল প্রোবিং প্রতিরোধ করতে আপনাকে অবশ্যই ব্যবহারকারী-প্রবর্তিত ইভেন্ট হ্যান্ডলারের (যেমন <button> বা <a> এলিমেন্টে click লিসেনার) মধ্যে navigator.credentials.get({ uiMode: 'immediate' }) কল করতে হবে। পৃষ্ঠা লোড হওয়ার সময় এটি কখনও অটোমেটিক চালু করবেন না (DOMContentLoaded)। এপিআই কল করলে ট্রানজিয়েন্ট অ্যাক্টিভেশন খরচ হয় না।
  • খালি নয় এমন allowCredentials তালিকা পাস করবেন না: uiMode: 'immediate' নির্দিষ্ট করা থাকলে publicKey.allowCredentials পপুলেট করবেন না। ব্রাউজার অবিলম্বে NotAllowedError থ্রো করে খালি নয় এমন allowCredentials তালিকা সহ যেকোনও ইমিডিয়েট UI মোড অনুরোধ প্রত্যাখ্যান করে, যাতে রিলাইং পার্টি পূর্ববর্তী ভিজিট অনুমান করতে বা সেশন জুড়ে ব্যবহারকারীদের ট্র্যাক করতে নির্দিষ্ট ক্রেডেনশিয়াল আইডি খুঁজতে না পারে।
  • AbortSignal (signal) পাস করবেন না: uiMode: 'immediate' নির্দিষ্ট করা থাকলে navigator.credentials.get()-এ signal প্রপার্টি সেট করবেন না, কারণ ব্রাউজার অবিলম্বে লগ-ইন ডায়ালগ প্রোগ্রাম্যাটিক উপায়ে বাতিল করার অনুমতি দেয় না। আপনার পৃষ্ঠা ব্যাকগ্রাউন্ডে কন্ডিশনাল UI (mediation: 'conditional') অনুরোধও রান করলে, ইমিডিয়েট UI মোড চালু করার আগে সেই কন্ডিশনাল UI AbortController-এ abort() কল করুন এবং ইমিডিয়েট অনুরোধ থেকে signal বাদ দিন।
  • ছদ্মবেশী ও ব্যক্তিগত ব্রাউজিং সেশন: ছদ্মবেশী বা ব্যক্তিগত ব্রাউজিং উইন্ডোতে করা অনুরোধ সবসময় NotAllowedError-এর মাধ্যমে বাতিল করা হয় যাতে ব্যক্তিগত সেশনগুলি স্থানীয় ক্রেডেনশিয়াল ছাড়া সেশন থেকে আলাদা করা না যায়।

সার্ভার-সাইড সেট-আপ

বিকল্প জেনারেশন এন্ডপয়েন্ট

এমন একটি এন্ডপয়েন্ট এক্সপোজ করুন যা যাচাই না করা ভিজিটরদের জন্য খুঁজে পাওয়ার যোগ্য WebAuthn অনুরোধের বিকল্প তৈরি করে:

  1. সেশন-বাউন্ড চ্যালেঞ্জ জেনারেট করা: ক্রিপ্টোগ্রাফিকভাবে র‍্যান্ডম চ্যালেঞ্জ বাফার তৈরি করুন, সার্ভার সেশনে এটি স্টোর করুন এবং Base64URL হিসেবে এটি এনকোড করুন।
  2. ব্যবহারকারীর যাচাইকরণ সংক্রান্ত পছন্দ বজায় রাখা: সেশনে userVerification: 'preferred' সেট করুন এবং expectedUserVerification: 'preferred' স্টোর করুন।
  3. allowCredentials বাদ দিন: ইমিডিয়েট UI মোডের বিকল্পে খালি নয় এমন allowCredentials তালিকা অন্তর্ভুক্ত করবেন না, কারণ ব্রাউজার খালি নয় এমন অনুমোদিত তালিকা NotAllowedError-এর সাথে প্রত্যাখ্যান করে।
// Server-side options generation example (/api/login/options)
router.post('/api/login/options', (req, res) => {
  const options = {
    challenge: serverGeneratedBase64UrlChallenge, // High-entropy random challenge stored in session
    rpId: 'example.com',
    userVerification: 'preferred',
  };

  req.session.challenge = options.challenge;
  req.session.expectedUserVerification = 'preferred';
  return res.json(options);
});

ডুয়াল ক্রেডেনশিয়াল যাচাইকরণ এন্ডপয়েন্ট

যেহেতু navigator.credentials.get({ password: true, publicKey, uiMode: 'immediate' }) পাসকী (PublicKeyCredential) বা সেভ করা পাসওয়ার্ড (PasswordCredential) দিয়ে সমাধান করতে পারে, তাই দুটি ক্রেডেনশিয়ালের ধরনের জন্যই যাচাইকরণ হ্যান্ডলার প্রদান করুন:

  1. WebAuthn অ্যাসারশন যাচাইকরণ (/api/login/verify): সেশন চ্যালেঞ্জ ও সেভ করা সর্বজনীন কী-এর সাথে অ্যাসারশন যাচাই করুন। ডেটাবেসে ক্রেডেনশিয়াল আইডি খুঁজে পাওয়া না গেলে, HTTP স্ট্যাটাস 404 রিটার্ন করুন যাতে ক্লায়েন্ট PublicKeyCredential.signalUnknownCredential()-এর মাধ্যমে পাসওয়ার্ড ম্যানেজারকে জানাতে পারে।
  2. পাসওয়ার্ড যাচাইকরণ (/api/login/password): ব্যবহারকারীর ডেটাবেসের সাথে username (cred.id) এবং password (cred.password) যাচাই করুন এবং যাচাই করা সেশন তৈরি করুন।

ক্লায়েন্ট-সাইড ইমপ্লিমেন্টেশন

ইউনিফায়েড ক্রেডেনশিয়াল সংক্রান্ত অনুরোধ

  1. পাসকী ও পাসওয়ার্ড, দুটির জন্যই অনুরোধ করুন: PublicKeyCredential.parseRequestOptionsFromJSON() ব্যবহার করে সার্ভার বিকল্প ডিকোড করুন এবং password: true, publicKey ও uiMode: 'immediate' (signal পাস না করে) সহ ব্যবহারকারীর শুরু করা ক্লিক হ্যান্ডলারের মধ্যে navigator.credentials.get() কল করুন।
  2. cred.type-এর মাধ্যমে ব্রাঞ্চ যাচাইকরণ:
    • cred.type === 'public-key' হলে, cred.toJSON()-এর সাথে অ্যাসারশন সিরিয়ালাইজ করুন এবং আপনার WebAuthn যাচাইকরণ এন্ডপয়েন্টে এটি পোস্ট করুন। সার্ভার HTTP 404-এর মাধ্যমে উত্তর দিলে, PublicKeyCredential.signalUnknownCredential({ rpId: publicKey.rpId, credentialId: encoded.id })-এ কল করুন।
    • cred.type === 'password' হলে, আপনার পাসওয়ার্ড যাচাইকরণ এন্ডপয়েন্টে { username: cred.id, password: cred.password } POST করুন।
  3. কোনও স্থানীয় ক্রেডেনশিয়াল না থাকলে NotAllowedError হ্যান্ডেল করুন: NotAllowedError ক্যাচ করুন (ডিভাইসে কোনও স্থানীয় পাসকী বা সেভ করা পাসওয়ার্ড না থাকলে অথবা ব্যবহারকারী বেছে নেওয়ার বিকল্প বাতিল করলে অবিলম্বে থ্রো করা হয়) এবং আপনার স্ট্যান্ডার্ড সাইন-ইন ফ্লোতে ট্রানজিশন করুন (যেমন, ইনলাইন সাইন-ইন ডায়ালগ খোলা বা রিটার্ন URL সহ /signin-এ নেভিগেট করা)।
let isAuthenticating = false;

async function authenticateWithImmediateUi() {
  const optionsResponse = await fetch('/api/login/options', { method: 'POST' });
  if (!optionsResponse.ok) {
    throw new Error('Failed to fetch authentication options');
  }
  const optionsJSON = await optionsResponse.json();
  const publicKey = PublicKeyCredential.parseRequestOptionsFromJSON(optionsJSON);

  // MANDATORY: Request both password and publicKey with uiMode: 'immediate' and NO signal parameter
  const cred = await navigator.credentials.get({
    password: true,
    publicKey,
    uiMode: 'immediate',
  });

  if (!cred) {
    throw new DOMException('No credential returned', 'NotAllowedError');
  }

  if (cred.type === 'public-key') {
    const encoded = cred.toJSON();
    const verifyResponse = await fetch('/api/login/verify', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(encoded),
    });

    if (verifyResponse.status === 404) {
      await PublicKeyCredential.signalUnknownCredential({
        rpId: publicKey.rpId || window.location.hostname,
        credentialId: encoded.id, // Base64URL-encoded credential ID string
      });
      throw new Error('Passkey credential is no longer recognized by the server');
    }

    if (!verifyResponse.ok) {
      throw new Error('Passkey verification failed');
    }
    return await verifyResponse.json();
  }

  if (cred.type === 'password') {
    const verifyResponse = await fetch('/api/login/password', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        username: cred.id,
        password: cred.password,
      }),
    });

    if (!verifyResponse.ok) {
      throw new Error('Password verification failed');
    }
    return await verifyResponse.json();
  }

  throw new Error(`Unsupported credential type: ${cred.type}`);
}

// Example: Intercepting an inline micro-action (Favorite button) or Header Sign-in click
const favoriteButton = document.getElementById('favorite-btn');

favoriteButton.addEventListener('click', async (event) => {
  event.preventDefault();
  if (isAuthenticating) return;

  // If already signed in, toggle the micro-action state immediately
  if (document.body.dataset.signedIn === 'true') {
    const nextPressed = favoriteButton.getAttribute('aria-pressed') !== 'true';
    favoriteButton.setAttribute('aria-pressed', String(nextPressed));
    return;
  }

  isAuthenticating = true;
  try {
    const user = await authenticateWithImmediateUi();
    // Complete the user's intended action immediately
    document.body.dataset.signedIn = 'true';
    favoriteButton.setAttribute('aria-pressed', 'true');
    updateHeaderUserState(user);
  } catch (err) {
    if (err.name === 'NotAllowedError') {
      // No local credentials available or user dismissed dialog:
      // transition smoothly to fallback sign-in UI or redirect with return URL
      showFallbackSignInUi({ returnAction: 'favorite' });
      return;
    }
    console.error('Authentication error:', err);
  } finally {
    isAuthenticating = false;
  }
});

ফলব্যাক স্ট্র্যাটেজি

Immediate UI mode fallback

  • প্রোগ্রেসিভ এনহ্যান্সমেন্ট অভিজ্ঞতা: uiMode: 'immediate'-কে প্রোগ্রেসিভ এনহ্যান্সমেন্ট হিসেবে বিবেচনা করুন। ব্রাউজারের নাম বা ভার্সন থেকে সাপোর্ট অনুমান করবেন না; একমাত্র নির্ভরযোগ্য সাপোর্ট সিগন্যাল হল PublicKeyCredential.getClientCapabilities()-এর মাধ্যমে capabilities.immediateGet রানটাইম চেক। বাধ্যতামূলক: navigator.credentials.get({ uiMode: 'immediate' }) কল করার আগে সবসময় capabilities.immediateGet চেক করুন—যেসব ব্রাউজার uiMode: 'immediate' শনাক্ত করে না, সেগুলি অজানা ডিকশনারি কী উপেক্ষা করে এবং ব্লকিং মডাল পাসকী ও QR কোড ডায়ালগ খোলে। capabilities.immediateGet-এর ভ্যালু falsy হলে অথবা navigator.credentials.get()-এর ভ্যালু NotAllowedError-এর সাথে রিজেক্ট হলে, আপনার অ্যাপ্লিকেশনের স্ট্যান্ডার্ড সাইন-ইন অভিজ্ঞতায় ফিরে যান (যেমন, ইনলাইন সাইন-ইন মডাল খোলা বা রিটার্ন URL প্যারামিটার সহ নির্দিষ্ট সাইন-ইন পৃষ্ঠায় নেভিগেট করা), যাতে কাজ করে না এমন ব্রাউজার ব্যবহারকারীরা আপনার বর্তমান সাইন-ইন ফ্লো অপরিবর্তিত অবস্থায় দেখতে পান:
async function isImmediateUiSupported() {
  if (!window.PublicKeyCredential || !PublicKeyCredential.getClientCapabilities) {
    return false;
  }
  try {
    const capabilities = await PublicKeyCredential.getClientCapabilities();
    return Boolean(capabilities?.immediateGet);
  } catch {
    return false;
  }
}

async function authenticateWithImmediateUi() {
  // MANDATORY: Check immediateGet support so unsupported browsers do not open a modal QR dialog
  const supported = await isImmediateUiSupported();
  if (!supported) {
    // Throw NotAllowedError so the caller's single catch path treats "unsupported" like "no local credentials"
    throw new DOMException('Immediate UI mode is not supported', 'NotAllowedError');
  }
  // Proceed with fetching options and calling navigator.credentials.get({ password: true, publicKey, uiMode: 'immediate' })
}

ক্লায়েন্ট ক্যাপাবিলিটি শনাক্তকরণ ফলব্যাক

সবসময় 'webauthn-polyfills' ইনস্টল করুন এবং আপনার ক্লায়েন্ট মডিউলে এটি ইমপোর্ট করুন যাতে PublicKeyCredential কাজ করলেই PublicKeyCredential.getClientCapabilities() উপলভ্য হয়:

import 'webauthn-polyfills';

পাসওয়ার্ড ক্রেডেনশিয়াল ফলব্যাক

navigator.credentials.get()-এ publicKey-এর পাশাপাশি password: true পাস করলে, তা কাজ করে এমন ব্রাউজারকে, ব্রাউজারের পাসওয়ার্ড ম্যানেজার থেকে সেভ করা পাসওয়ার্ড, ইউনিফায়েড ইমিডিয়েট অ্যাকাউন্ট বাছাইকারীতে অন্তর্ভুক্ত করার অনুমতি দেয়।

  • ফলব্যাক অভিজ্ঞতা: যেসব ব্রাউজার PasswordCredential সাপোর্ট করে না, সেগুলি password: true বিকল্প উপেক্ষা করে অথবা capabilities.immediateGet ফিচার চেকের মাধ্যমে স্ট্যান্ডার্ড সাইন-ইন ফর্মে ফলব্যাক করে, যেখানে <input autocomplete="username webauthn"> এবং <input type="password" autocomplete="current-password"> নেটিভ পাসওয়ার্ড অটোফিল প্রদান করে।

সহজ JSON সিরিয়ালাইজেশন ফলব্যাক

সবসময় 'webauthn-polyfills' ইনস্টল করুন এবং ক্লায়েন্ট বান্ডেলে এটি ইমপোর্ট করুন যাতে PublicKeyCredential-কে সাপোর্ট করে এমন ব্রাউজার জুড়ে PublicKeyCredential.parseRequestOptionsFromJSON() এবং PublicKeyCredential.prototype.toJSON() ধারাবাহিকভাবে কাজ করে:

import 'webauthn-polyfills';

সিগন্যাল API সিঙ্ক্রোনাইজেশন ফলব্যাক

WebAuthn Signal API (webauthn-signals) হল একটি প্রোগ্রেসিভ এনহ্যান্সমেন্ট যা সার্ভার HTTP 404-এর মাধ্যমে উত্তর দিলে ব্যবহারকারীর পাসওয়ার্ড ম্যানেজার থেকে পুরনো পাসকী সরিয়ে দেয়।

  • ফলব্যাক অভিজ্ঞতা: if (PublicKeyCredential.signalUnknownCredential)-এর পরে গেট কল। সমর্থিত না হলে, সিগন্যাল কলটি এড়িয়ে যান এবং ব্যবহারকারীকে অন্য কোনও পদ্ধতিতে সাইন-ইন করার জন্য নির্দেশিকা সহ একটি স্পষ্ট মেসেজ দেখান।