এই নির্দেশিকায় বিস্তারিতভাবে বলা হয়েছে যে কীভাবে ব্যবহারকারীদের তাদের অ্যাকাউন্টের জন্য পাসকী রেজিস্টার করার সুবিধা দেওয়া যায়, যা অত্যন্ত সুরক্ষিত, ফিশিং-প্রতিরোধী পাসওয়ার্ডহীন সাইন-ইন বিকল্প প্রদান করে।
ডেটাবেস সংক্রান্ত প্রয়োজনীয়তা
পাসকী রেজিস্ট্রেশন সংক্রান্ত সুবিধা দিতে, আপনার ডেটাবেস ক্রেডেনশিয়াল টেবিলে নিম্নলিখিত ফিল্ডগুলি অবশ্যই সেভ করতে হবে:
export interface StoredPasskeyCredential {
id: string; // Base64URL-encoded credential ID (unique lookup key)
passkeyUserId: string; // Associated application user ID
credentialPublicKey: string; // Base64URL-encoded public key used to verify assertion signatures
credentialType: "public-key";
credentialDeviceType: "singleDevice" | "multiDevice"; // Helps distinguish device-bound vs cloud-synced passkeys
credentialBackedUp: boolean; // Boolean backup state reported by the authenticator
aaguid: string; // Authenticator Attestation GUID
providerIcon?: string; // Provider icon derived from the AAGUID registry (dark or light theme URLs)
name: string; // Provider name derived from AAGUID registry
transports: string[]; // Array of transport names (e.g. 'internal', 'hybrid') necessary for exclusion options
lastUsedAt?: number; // Optional epoch timestamp of last sign-in
registeredAt: number; // Registration epoch timestamp
counter: number; // Authenticator sign-in signature counter used to prevent replay attacks
}
সার্ভার-সাইড
বিকল্প তৈরি করা
WebAuthn তৈরির প্যারামিটার জেনারেট করে এমন একটি এন্ডপয়েন্ট তৈরি করুন। হ্যান্ড-রোলিং ক্রিপ্টোগ্রাফির পরিবর্তে প্রতিটি বিভাগের স্ট্যান্ডার্ড অনুযায়ী যাচাই করা লাইব্রেরির উপর নির্ভর করুন।
- আগে থেকে নির্ধারিত RP ID ব্যবহার করা: কনস্ট্যান্ট স্ট্রিং হিসেবে আগে থেকে নির্ধারিত সঠিক RP ID ব্যবহার করুন।
- একটি সুরক্ষিত চ্যালেঞ্জ তৈরি করুন: সার্ভারে একটি হাই-এনট্রপি, ক্রিপ্টোগ্রাফিকভাবে সুরক্ষিত র্যান্ডম বাফার তৈরি করুন, ব্যবহারকারীর সেশনে এটি নিরাপদে স্টোর করুন এবং বিকল্প ডেলিভারির জন্য Base64URL হিসেবে এটি এনকোড করুন।
- ডুপ্লিকেট পাসকী এড়ানো: ব্যবহারকারীর আগে থেকে রেজিস্টার করা ক্রেডেনশিয়াল আইডি
excludeCredentialsবিকল্পের অ্যারেতে ম্যাপ করুন। এটি একই পাসকী প্রদানকারী অ্যাকাউন্টে প্রমাণীকরণকারীকে ডুপ্লিকেট ক্রেডেনশিয়াল রেজিস্টার করা থেকে আটকায়। - খুঁজে নেওয়ার যোগ্য ক্রেডেনশিয়াল এনফোর্স করুন: খুঁজে নেওয়ার যোগ্য ক্রেডেনশিয়ালের অনুরোধ করতে
authenticatorSelectionবিকল্পেrequireResidentKey: trueওresidentKey: "required"সেট করুন, যা খুঁজে নেওয়ার যোগ্য সাইন-ইনের জন্য প্রয়োজন। - ব্যবহারকারী যাচাইকরণ কনফিগার করুন:
userVerification: "preferred"বাuserVerification: "required"উল্লেখ করুন। অনেক সম্মতি সংক্রান্ত ব্যবহারের ক্ষেত্রে (যেমন, ফাইন্যান্স, স্বাস্থ্য পরিষেবা) তৈরি করার সময় ব্যবহারকারী যাচাইকরণ এনফোর্স করার জন্য'required'প্রয়োজন। - অ্যাটাচমেন্টের স্কোপ নির্ধারণ করা:
- প্রোমোশন ফ্লো: স্ট্যান্ডার্ড পাসওয়ার্ড সাইন-ইন বা সাইন-আপ পরবর্তী প্রোমোশনের ঠিক পরেই পাসকী তৈরির প্রস্তাব দেওয়ার সময়, প্ল্যাটফর্ম অথেন্টিকেটর এনফোর্স করতে এবং এক্সটার্নাল নিরাপত্তা কী প্রম্পট বাইপাস করতে
authenticatorAttachment: "platform"সেট করুন। - ম্যানেজমেন্ট ফ্লো: প্ল্যাটফর্ম যাচাইকারীর পাশাপাশি এক্সটার্নাল নিরাপত্তা কী কাজ করে এমন কোনও নির্দিষ্ট সেটিংস বা নিরাপত্তা প্যানেল থেকে কল করা হলে,
authenticatorAttachmentপ্রপার্টি সম্পূর্ণভাবে বাদ দিন। - পরামর্শ: একটি এন্ডপয়েন্ট দিয়ে দুটি ফ্লো শর্তসাপেক্ষে ম্যানেজ করতে
promotion: booleanঅনুরোধ ফ্ল্যাগ গ্রহণ করুন।
- প্রোমোশন ফ্লো: স্ট্যান্ডার্ড পাসওয়ার্ড সাইন-ইন বা সাইন-আপ পরবর্তী প্রোমোশনের ঠিক পরেই পাসকী তৈরির প্রস্তাব দেওয়ার সময়, প্ল্যাটফর্ম অথেন্টিকেটর এনফোর্স করতে এবং এক্সটার্নাল নিরাপত্তা কী প্রম্পট বাইপাস করতে
// Options generation example
const options = {
challenge: serverGeneratedBase64UrlChallenge, // Cryptographically random challenge
rp: { id: "example.com", name: "Secure Application" },
user: {
id: userBase64UrlId, // Unique base64url string identifying the account
name: "user@example.com",
displayName: "Jane Doe",
},
pubKeyCredParams: [
{
type: "public-key",
alg: -7,
},
{
type: "public-key",
alg: -257,
},
],
excludeCredentials: userExistingCredentials.map((cred) => ({
type: "public-key",
id: cred.id,
transports: cred.transports,
})),
authenticatorSelection: {
residentKey: "required",
requireResidentKey: true,
userVerification: "preferred",
...(isPromotionFlow && { authenticatorAttachment: "platform" }),
},
};
যাচাইকরণ
- চ্যালেঞ্জ যাচাইকরণ: প্রত্যাশিত সেশন বাউন্ড চ্যালেঞ্জের বিপরীতে চ্যালেঞ্জটি নিরাপদে যাচাই করুন।
- ব্যবহারকারীর উপস্থিতি যাচাই করুন:
- তৈরি করার সময় ব্যবহারকারীর ফিজিক্যাল উপস্থিতি কনফার্ম করতে, পার্স করা যাচাইকারীর ডেটায় ফেরত আসা ইউজার প্রেজেন্ট (UP) ফ্ল্যাগ
trueকিনা তা নিশ্চিত করুন।
- তৈরি করার সময় ব্যবহারকারীর ফিজিক্যাল উপস্থিতি কনফার্ম করতে, পার্স করা যাচাইকারীর ডেটায় ফেরত আসা ইউজার প্রেজেন্ট (UP) ফ্ল্যাগ
- 'পছন্দের' জন্য যাচাইকরণ শিথিল করা:
- তৈরি করার বিকল্প
userVerification: "preferred"উল্লেখ করা থাকলে, সার্ভার-সাইড যাচাইকরণ কল অবশ্যইrequireUserVerification: false-এর সাথে কনফিগার করতে হবে। অন্যথায়, যেসব যাচাইকারী ব্যবহারকারী যাচাইকরণ ছাড়াই রেজিস্টার করে (যেমন, স্ক্রিন লক বন্ধ করা আছে) সেগুলি সার্ভার যাচাইকরণে মিথ্যা ব্যর্থতা ট্রিগার করবে।
- তৈরি করার বিকল্প
ক্লায়েন্ট-সাইড লজিক
- পৃষ্ঠা লোড হওয়ার সময় UI গেট করা:
- পৃষ্ঠা লোড হওয়ার সময়,
conditionalGetবাpasskeyPlatformAuthenticatorউপলভ্য না থাকলে,PublicKeyCredential.getClientCapabilities()কল করুন এবং "পাসকী তৈরি করুন" বোতাম বন্ধ করুন।
- পৃষ্ঠা লোড হওয়ার সময়,
- তৈরি করার জন্য ইনভোক ও সিরিয়ালাইজ করুন:
PublicKeyCredential.parseCreationOptionsFromJSON()-এর মাধ্যমে সার্ভার বিকল্প ডিকোড করুন এবং ফলাফল হিসেবে পাওয়া কনফিগারেশনnavigator.credentials.create()-এ পাস করুন।- যাচাইকরণ এন্ডপয়েন্ট ফেচ করার আগে
AuthenticatorAttestationResponse-কে সঠিক, JSON-সিরিয়ালাইজেবল অবজেক্টে এনকোড করতেcredential.toJSON()-কে কল করুন।
- যাচাইকরণ এন্ডপয়েন্ট ফেচ করার আগে
- WebAuthn ব্যতিক্রম ম্যানেজ করা:
InvalidStateError: একটি ম্যাচিং পাসকী আগে থেকেই আছে (excludeCredentials-এর সাথে ম্যাচ করেছে)।NotAllowedError: ব্যবহারকারী যাচাইকরণ পাসকী ডায়ালগ বাতিল করেছেন বা সেটির সময়সীমা শেষ হয়ে গেছে।AbortError: অপারেশনটি বাতিল করা হয়েছে।SecurityError: সুরক্ষিত অরিজিন (HTTPS) বা RP আইডি অমিল হওয়ার সমস্যা (কনফিগারেশন সংক্রান্ত সমস্যা)।
- সিগন্যাল API-এর জন্য Try/Catch Segregation:
- try/catch ব্লকে সার্ভার যাচাইকরণ
fetch()কল র্যাপ করুন। সার্ভার যাচাইকরণ ফেচ করা না গেলে (যেকোনও স্ট্যাটাসresponse.ok === falseবা নেটওয়ার্ক থ্রো)signalUnknownCredential()কল করুন।
- try/catch ব্লকে সার্ভার যাচাইকরণ
// optionsFetch and registerVerifyFetch are app-defined HTTP methods
import { optionsFetch, registerVerifyFetch } from "./api.js";
async function registerPasskey(isPromotion = false) {
// Verify passkey capability and conditional UI are available
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (
!capabilities.passkeyPlatformAuthenticator ||
!capabilities.conditionalGet
) {
// Hide "Create passkey" buttons and fall back to password flows instead
showStandardPasswordFallbackUI();
return;
}
const creationOptionsJSON = await optionsFetch({ promotion: isPromotion });
const publicKey =
PublicKeyCredential.parseCreationOptionsFromJSON(creationOptionsJSON);
let credential;
try {
// passkey prompt execution
credential = await navigator.credentials.create({ publicKey });
} catch (err) {
if (err.name === "InvalidStateError") {
console.log("A passkey already exists for this account.");
alert("A passkey already exists for this account.");
} else if (err.name === "SecurityError") {
console.error("Configuration RP ID or Secure Context error.");
alert("Configuration RP ID or Secure Context error.");
} else if (err.name === "NotAllowedError") {
console.log("User cancelled the passkey dialog.");
} else if (err.name === "AbortError") {
console.log("The creation operation has been aborted.");
}
return; // Safe API exit, do not signal unknown for standard WebAuthn cancels
}
// Server Verification phase (Segregated Try/Catch)
let encodedResponse = credential.toJSON();
try {
const response = await registerVerifyFetch(encodedResponse);
if (!response.ok) {
// Server verification failed to verify/authenticate the credential (orphaned)
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encodedResponse.id, // Base64URL-encoded credential ID
});
}
} catch (serverErr) {
console.error("Server verification network failure:", serverErr);
await publickeycredential.signalunknowncredential({
rpId, // RP ID must match the one defined on the server
credentialid: encodedresponse.id, // base64url-encoded credential id
});
}
}
ফলব্যাক স্ট্র্যাটেজি
সিগন্যাল API সিঙ্ক্রোনাইজেশন ফলব্যাক
WebAuthn Signal API (webauthn-signals) হল একটি প্রোগ্রেসিভ অপ্টিমাইজেশন যা পাসওয়ার্ড ম্যানেজারকে সার্ভার ক্রেডেনশিয়াল স্ট্যাটাসের সাথে সিঙ্ক করে রাখতে ব্যবহার করা হয়।
- ফলব্যাক অভিজ্ঞতা: ব্রাউজার
PublicKeyCredential.signalUnknownCredential-কে সাপোর্ট না করলে, ফিচার শনাক্তকরণ গেটিং (if (PublicKeyCredential.signalUnknownCredential))-এর মাধ্যমে কলটি অবশ্যই নিরাপদে বাইপাস করতে হবে এবং সার্ভার-সাইড যাচাইকরণ ম্যানেজার আপডেট ট্রিগার না করেই ব্যর্থতা লগ করে।
Easy JSON Serialization Fallback
সবসময় 'webauthn-polyfills' ইনস্টল করুন এবং কনটেক্সটে এটি ইমপোর্ট করুন।
মনে রাখবেন, যতক্ষণ PublicKeyCredential কাজ করবে, ততক্ষণ PublicKeyCredential.parseCreationOptionsFromJSON এবং PublicKeyCredential.prototype.toJSON-ও কাজ করবে।
import 'webauthn-polyfills';