আপনার সাইটে ইমেল যাচাইকরণ প্রয়োগ করতে, টোকেনের অনুরোধ জানাতে আপনার ফর্ম মার্ক-আপ আপডেট করুন এবং ইনকামিং টোকেনের জন্য সার্ভার-সাইড যাচাইকরণ যোগ করুন।
অরিজিন ট্রায়ালের জন্য রেজিস্টার করা
যাচাই করা সাইটে অবশ্যই অরিজিন ট্রায়াল কনফিগার করা থাকতে হবে।
Chrome 154 ভার্সন অনুযায়ী, থার্ড-পার্টি অরিজিন ট্রায়াল কাজ করে, তবে একটি গুরুত্বপূর্ণ শর্ত আছে: ট্রায়ালের জন্য রেজিস্টার করা অরিজিনকে ইস্যুকারীর সাথে একই সাইটের হতে হবে। যেমন:
- ইস্যুকারী ডোমেন:
issuer.example - OT রেজিস্ট্যান্ট:
https://issuer.example - জাভাস্ক্রিপ্ট অরিজিন:
https://issuer.example(বাhttps://app.issuer.exampleসাবডোমেন ম্যাচিং সহ)
ফর্ম ফিল্ড কনফিগার করা
আপনার ইমেল জমা দেওয়ার ফর্মে একটি লুকানো টোকেন ফিল্ড যোগ করুন:
<input
type="email"
name="email-address"
autocomplete="email">
<input
type="hidden"
name="token"
autocomplete="email-verification-token"
nonce="rAnD0m-VaLuE">
ফিল্ড সংক্রান্ত প্রয়োজনীয়তা:
- ইমেল ফিল্ড:
type="email"ওautocomplete="email"সেট করুন যাতে Chrome ঠিকানা অটোফিল ও শনাক্ত করতে পারে। - টোকেন ফিল্ড অ্যাট্রিবিউট:
autocomplete="email-verification-token"সেট করুন: জমা দেওয়ার সময় টোকেন পূরণ করার জন্য Chrome এই ফিল্ডটি শনাক্ত করে।- সেট
nonce="<VALUE>": ফর্ম জমা দেওয়ার বিষয়টি যাচাই করতে সাইটকে অবশ্যই সেশন-বাউন্ড নন্স প্রদান করতে হবে।
ইমেল যাচাইকরণ টোকেন (EVT) ভ্যালিডেট করা
ব্যবহারকারী ফর্ম জমা দিলে, আপনার সার্ভার ইমেল আইডি এবং লুকানো ফিল্ড থেকে টোকেন পায়। টোকেন ফিল্ড খালি থাকলে বুঝতে হবে যে ব্রাউজার বা পরিষেবা প্রদানকারী EVP কাজ করে না অথবা ব্যবহারকারী যাচাইকরণ এড়িয়ে গেছেন। এটি ঘটলে, আপনার বর্তমান যাচাইকরণ প্রক্রিয়া ব্যবহার করুন, যেমন ওটিপি বা ম্যাজিক লিঙ্ক পাঠানো।
কোনও টোকেন থাকলে, নিম্নলিখিত উপায়ে সেটি যাচাই করুন:
- SD-JWT লাইব্রেরি ব্যবহার করে টোকেন পার্স করুন।
- প্রত্যাশিত ভ্যালু ও সেশন দাবি যাচাই করুন।
- ডিএনএস ডেলিগেশন যাচাই করুন।
- ইস্যুকারী মেটাডেটা খুঁজে বের করা এবং JWKS পাওয়া।
- ক্রিপ্টোগ্রাফিক স্বাক্ষর ও কী বাইন্ডিং যাচাই করুন।
১. টোকেন পার্স করা
টোকেনটি RFC 9901: বেছে নেওয়া তথ্য প্রকাশ করা JWT
(SD-JWT+KB) ফর্ম্যাট ব্যবহার করে। টোকেন পার্স ও যাচাই করার জন্য আপনার প্ল্যাটফর্মের জন্য
উপযুক্ত লাইব্রেরি ব্যবহার করুন।
যেমন, Node-এর জন্য আপনি
@sd-jwt/core এবং
jose ব্যবহার করতে পারেন। কাঁচা ফর্মে এটি
এইরকম: ইস্যুকারীর স্বাক্ষর করা JWT, তারপরে শূন্য বা তার বেশি ডিসক্লোজার এবং শেষে
একটি কী বাইন্ডিং JWT, প্রতিটি কম্পোনেন্ট টিল্ড চিহ্ন দিয়ে আলাদা করা থাকে:
<Issuer-signed EVT>~<Disclosure 1>~...~<Disclosure N>~<Key Binding JWT>
বর্তমান প্রয়োগে, টোকেনে কোনও ডিসক্লোজার নেই
(<Issuer-signed EVT>~<Key Binding JWT>)। তবে, ভবিষ্যতে এটি
পরিবর্তিত হতে পারে।
লাইব্রেরির সাহায্যে টোকেনটি ডিকোড করুন:
import { decodeSdJwtSync } from "@sd-jwt/core";
import { createHash } from "node:crypto";
const hasher = (data, alg) =>
createHash(alg === "sha-256" ? "sha256" : alg)
.update(data)
.digest();
const decoded = decodeSdJwtSync(rawToken, hasher);
const evtPayload = decoded.jwt.payload;
const kbPayload = decoded.kbJwt?.payload;
verifier.example যাচাই করলে demo@provider.example, ডিকোড করা টোকেনটি
নিচে দেওয়া টোকেনের মতো দেখতে হবে:
{
"evtJwtDecodedHeader": {
"typ": "evt+jwt",
"alg": "EdDSA",
"kid": "issuer-key-id"
},
"evtJwtDecodedPayload": {
"iss": "https://provider.example",
"iat": 12345678901,
"exp": 12345679901,
"cnf": {
"jwk": {
"kty": "OKP",
"crv": "Ed25519",
"x": "pUbLiCkEy123pUbLiCkEy123pUbLiCkEy123"
}
},
"email": "demo@provider.example",
"email_verified": true
},
"kbJwtDecodedHeader": {
"alg": "EdDSA",
"typ": "kb+jwt"
},
"kbJwtDecodedPayload": {
"aud": "https://verifier.example",
"iat": 12345678901,
"nonce": "rAnDoM123rAnDoM123rAnDoM123rAnDoM123",
"sd_hash": "hAsH456hAsH456hAsH456hAsH456hAsH456"
},
"disclosures": []
}
২. প্রত্যাশিত ভ্যালু ও সেশন দাবি যাচাই করা
পে-লোডের প্রাথমিক ভ্যালু আপনার দেওয়া ও প্রত্যাশিত ভ্যালুর সাথে মিলছে কিনা তা চেক করুন:
email_verified:trueহতে হবে।email: ফর্মে জমা দেওয়া ইমেল আইডির সাথে মিলতে হবে।aud(দর্শক): আপনার সাইটের অরিজিনের সাথে ম্যাচ করতে হবে।nonce: আপনার ফর্মে দেওয়া ননসের সাথে মিলতে হবে।iat(ইস্যু করার তারিখ) ওexp(মেয়াদ শেষ হওয়ার তারিখ): টোকেনটি বৈধ সময়সীমার মধ্যে আছে এবং এর মেয়াদ শেষ হয়ে যায়নি কিনা তা কনফার্ম করুন।
৩. ডিএনএস ডেলিগেশন যাচাই করা
ইমেল আইডি ডোমেনের জন্য _email-verification DNS রেকর্ড যাচাই করুন। যেমন, demo@gmail.com-এর জন্য, _email-verification.gmail.com TXT
রেকর্ড কোয়েরি করুন। এই পরিষেবা প্রদানকারীর জন্য, কোয়েরি অ্যাকাউন্টের লোকেশন
পরিষেবা প্রদানকারী রিটার্ন করে, অর্থাৎ accounts.google.com।
$ dig +short TXT _email-verification.gmail.com
"iss=accounts.google.com"
যাচাই করুন যে ইস্যুকারী স্কিম হল https:// এবং https://<domain>, EVT-তে থাকা iss দাবি
এর সাথে মিলছে।
৪. EVT স্বাক্ষর যাচাই করা
https://<issuer>/.well-known/email-verificationথেকে ইস্যুকারীর ডিসকভারি মেটাডেটা সংগ্রহ করুন:
{
"issuance_endpoint": "https://accounts.google.com/gsi/email-verification/issue",
"jwks_uri": "https://verifiablecredentials-pa.googleapis.com/.well-known/vc-public-jwks",
"signing_alg_values_supported": ["EdDSA"]
}
jwks_uri থেকে JSON ওয়েব কী সেট সংগ্রহ করুন।
টোকেন প্যাকেজ যাচাই করতে আপনার SD-JWT লাইব্রেরি ব্যবহার করুন। লাইব্রেরি যাচাইকরণ কোঅর্ডিনেট করে:
- ফেচ করা JWKS-এর সাথে EVT-তে ইস্যুকারীর স্বাক্ষর যাচাই করা।
cnf.jwk-এ ক্ষণস্থায়ী পাবলিক কী ব্যবহার করে KB-JWT-তে ব্রাউজারের সিগনেচার যাচাই করা।- কী বাইন্ডিং যাচাই করা (
aud,nonceএবং ডাইজেস্ট হ্যাশsd_hash)।
Node.js-এ যাচাইকরণের লজিকের উদাহরণ:
import { SDJwtInstance } from "@sd-jwt/core";
import { importJWK, compactVerify } from "jose";
import { createHash } from "node:crypto";
const hasher = (data, alg) =>
createHash(alg === "sha-256" ? "sha256" : alg)
.update(data)
.digest();
const sdJwt = new SDJwtInstance({ hasher });
sdJwt.config({
hasher,
// Verifier for the Issuer-signed EVT
verifier: async (data, sig) => {
const token = `${data}.${sig}`;
const header = decoded.jwt.header;
const headerAlg = header.alg || "ES256";
// Match by kid if present, or iterate across matching algorithm keys
const keysToTry = header.kid
? jwksData.keys.filter(k => k.kid === header.kid)
: jwksData.keys;
for (const jwk of keysToTry) {
try {
const pubKey = await importJWK(jwk, jwk.alg || headerAlg);
await compactVerify(token, pubKey);
return true;
} catch {
// Try next candidate key
}
}
return false;
},
// Verifier for the Key Binding JWT (KB-JWT)
kbVerifier: async (data, sig) => {
try {
const browserJwkKey = evtPayload.cnf?.jwk;
if (!browserJwkKey) return false;
const pubKey = await importJWK(browserJwkKey, decoded.kbJwt.header.alg || "ES256");
await compactVerify(`${data}.${sig}`, pubKey);
return true;
} catch {
return false;
}
},
});
// The library automatically verifies EVT signature, KB-JWT signature, audience, nonce, and sd_hash
const result = await sdJwt.verify(rawToken, {
kb: {
expectedNonce: sessionNonce,
expectedAudience: "https://example.com",
required: true,
},
});
const verifiedPayload = result.payload;
সব ধাপ সফলভাবে সম্পন্ন হলে, আপনি পরিষেবা প্রদানকারীর কাছে ইমেল আইডি যাচাই করেছেন। যাচাইকরণ না হলে, আপনার স্বাভাবিক ফ্লো ব্যবহার করে ব্যবহারকারীকে একটি কনফার্মেশন ইমেল পাঠান।
সমস্যার সমাধান
যাচাইকরণ করা না গেলে বা ব্রাউজার টোকেন না দিলে, নিচে উল্লেখ করা সাধারণ সমস্যাগুলি চেক করুন:
জমা দেওয়ার সময় টোকেন ফিল্ড খালি রয়েছে
- অরিজিন ট্রায়াল রেজিস্ট্রেশন:
Origin-Trialহেডার বা<meta>ট্যাগ পৃষ্ঠায় দেখানো হচ্ছে কিনা তা কনফার্ম করুন। থার্ড-পার্টি অরিজিন ট্রায়ালের (Chrome 154+) ক্ষেত্রে, রেজিস্টার করা ট্রায়াল অরিজিনকে ইস্যুকারীর সাথে একই সাইটের হতে হবে (https://<issuer-domain>)। আপনি DevTools-এর মধ্যে কোনও সাইটে অ্যাপ্লিকেশন > ফ্রেম > (প্রাসঙ্গিক ফ্রেম বেছে নিন) > অরিজিন ট্রায়াল বিকল্পের অধীনে অরিজিন ট্রায়াল কনফিগারেশন পরিদর্শন করতে পারবেন। - ফর্ম মার্ক-আপ:
<input type="email" autocomplete="email">ও<input type="hidden" autocomplete="email-verification-token" nonce="...">দুটিকেই একই<form>এলিমেন্টের মধ্যে থাকতে হবে (Shadow DOM সীমানা জুড়ে আলাদা আলাদা করে রাখা যাবে না) এবংnonceখালি রাখা যাবে না। - শীঘ্র জমা দেওয়া বা আবার ব্যবহার করা পৃষ্ঠা: ইমেল লেখার বা অটোফিল করার পরে ব্রাউজার ব্যাকগ্রাউন্ডে টোকেন ফেচ করে। অনুরোধ সম্পূর্ণ হওয়ার আগে জমা দিলে টোকেন খালি থাকে। ব্যবহারকারী ইমেল আইডি লেখার পরে ফর্ম জমা দেওয়ার জন্য Return কী টিপলে এটি হতে পারে।
- ব্রাউজার ও পরিষেবা প্রদানকারী সংক্রান্ত পূর্বশর্ত: ব্যবহারকারীকে একই ব্রাউজার প্রোফাইলে অংশগ্রহণকারী পরিষেবা প্রদানকারীর
সাথে সাইন-ইন করতে হবে এবং Chrome সেটিংস (
chrome://settings/contactInfo)-এ যাচাই করা ইমেল চালু থাকতে হবে।
ইস্যুকারীর স্বাক্ষর যাচাইকরণ সম্পূর্ণ হয়নি
kidহেডার নেই: EVT হেডারেkid(কী আইডি) দাবি এবং JWKS ঐচ্ছিক (যেমন, Gmailkidবাদ দেয়)।kidনা থাকলে, কী আইডি লুক-আপে ব্যর্থ হওয়ার পরিবর্তে, ইস্যুকারীরjwks_uri-এ সবকটি সম্ভাব্য কী-এর মাধ্যমে পুনরাবৃত্তি করুন।- অ্যালগরিদম শনাক্তকারী (EdDSA এবং Ed25519): ইস্যুকারী ও লাইব্রেরি
EdDSAঅথবাEd25519(ES256-এর সাথে) উল্লেখ করতে পারে। আপনার JWK ইমপোর্ট ও যাচাইকরণ লজিক যাতে দুটি শনাক্তকারীকেই গ্রহণ করে তা নিশ্চিত করুন। - ইস্যুকারী (
iss) অরিজিন ফর্ম্যাট: DNS TXT রেকর্ডে (_email-verification.<domain>) একটি বেয়ার হোস্টনেম (iss=accounts.issuer.example) থাকে, যেখানে EVTissদাবি হল একটি সম্পূর্ণ HTTPS অরিজিন (https://accounts.issuer.example, শেষে কোনও স্ল্যাশ নেই)। তুলনা করার আগে DNS রেকর্ড ভ্যালুতে Prefixhttps://যোগ করুন।
কী বাইন্ডিং (KB-JWT) যাচাইকরণ সম্পূর্ণ হয়নি
- নন্স না মিললে বা সেটির মেয়াদ শেষ হয়ে গেলে: নিশ্চিত করুন যে
nonce<input>-এ রেন্ডার করা নন্স আপনার সার্ভারে অ্যাক্টিভ সেশনের নন্সের সাথে মিলছে এবং অন্য কোনও ট্যাব সেটি ওভাররাইট করেনি বা আগের কোনও অনুরোধে সেটি ব্যবহার করা হয়নি। - শ্রোতা (
aud) সংক্রান্ত অমিল:audদাবি হল যাচাইকারীর HTTPS অরিজিন (https://verifier.example, কোনও পাথ বা ট্রেলিং স্ল্যাশ নেই)।
ইমেল দাবি (email) তুলনা করা যায়নি
- কেসিং ও ক্যাননিক্যালাইজেশন: Chrome 156+ ভার্সন
emailদাবি বাইটের জন্য-বাইট হিসেবে ফর্মের মধ্যে যেভাবে লেখা হয়েছে সেইভাবেই রিটার্ন করে, কিন্তু আগের ব্রাউজার ভার্সন বা প্রোভাইডাররা ক্যাননিক্যালাইজড অ্যাড্রেস রিটার্ন করতে পারে (যেমন,first.last@example.com-এর জন্যFirst.Last@example.com)। টোকেনেরemailদাবিকে জমা দেওয়া ফর্মের ভ্যালুর সাথে ম্যাচ করানোর সময় কেস-ইনসেনসিটিভ তুলনা ব্যবহার করুন।