[{"data":1,"prerenderedAt":3152},["ShallowReactive",2],{"guide-passkeys-future":3},{"id":4,"title":5,"body":6,"date":3144,"description":3145,"extension":3146,"meta":3147,"navigation":271,"path":3148,"readingTime":354,"seo":3149,"stem":3150,"__hash__":3151},"guides\u002Fguides\u002Fpasskeys-future.md","Passkeys: The Future of Passwordless Authentication",{"type":7,"value":8,"toc":3113},"minimark",[9,14,18,21,24,28,36,57,60,65,152,156,163,177,181,716,720,1044,1048,1488,1492,1496,1576,1580,1647,1651,1716,1720,1724,1832,1836,1977,1981,1985,2611,2615,2622,2802,2806,2809,2813,2816,2836,2839,2843,2846,2924,2928,2931,3037,3040,3065,3069,3072,3092,3095,3099,3109],[10,11,13],"h2",{"id":12},"introduction","Introduction",[15,16,17],"p",{},"Passwords have been the primary method of authentication for decades, but they are increasingly showing their age. Users struggle with password fatigue, weak passwords, and phishing attacks. Meanwhile, organizations face the cost of password resets, breach notifications, and compliance issues.",[15,19,20],{},"Passkeys represent a paradigm shift in authentication. Built on the WebAuthn (Web Authentication) API and FIDO2 (Fast Identity Online) standards, passkeys offer a passwordless, phishing-resistant authentication method that is both more secure and more user-friendly.",[15,22,23],{},"This guide explains how passkeys work, how they compare to passwords, and how to implement them in your applications.",[10,25,27],{"id":26},"what-are-passkeys","What Are Passkeys?",[15,29,30,31,35],{},"A ",[32,33,34],"strong",{},"passkey"," is a cryptographic credential that replaces passwords. Instead of typing a memorable string, the user authenticates using:",[37,38,39,46,51],"ul",{},[40,41,42,45],"li",{},[32,43,44],{},"Biometric sensors"," (fingerprint, face recognition)",[40,47,48],{},[32,49,50],{},"Device PIN or pattern",[40,52,53,56],{},[32,54,55],{},"Security keys"," (YubiKey, Titan Key)",[15,58,59],{},"The passkey itself is stored on the user's device and never leaves it. When authenticating, the device uses the passkey to cryptographically sign a challenge from the server.",[61,62,64],"h3",{"id":63},"key-characteristics","Key Characteristics",[66,67,68,84],"table",{},[69,70,71],"thead",{},[72,73,74,78,81],"tr",{},[75,76,77],"th",{},"Feature",[75,79,80],{},"Passwords",[75,82,83],{},"Passkeys",[85,86,87,101,114,127,140],"tbody",{},[72,88,89,95,98],{},[90,91,92],"td",{},[32,93,94],{},"Phishing resistant",[90,96,97],{},"No",[90,99,100],{},"Yes",[72,102,103,108,111],{},[90,104,105],{},[32,106,107],{},"Reusable across sites",[90,109,110],{},"Often (bad practice)",[90,112,113],{},"Never (unique per site)",[72,115,116,121,124],{},[90,117,118],{},[32,119,120],{},"Stored on server",[90,122,123],{},"Yes (hashed)",[90,125,126],{},"No (only public key)",[72,128,129,134,137],{},[90,130,131],{},[32,132,133],{},"User remembers",[90,135,136],{},"Yes (burden)",[90,138,139],{},"No (device handles it)",[72,141,142,147,150],{},[90,143,144],{},[32,145,146],{},"Works cross-device",[90,148,149],{},"Yes (with sync)",[90,151,149],{},[10,153,155],{"id":154},"how-passkeys-work","How Passkeys Work",[15,157,158,159,162],{},"Passkeys use ",[32,160,161],{},"public-key cryptography",". When a user creates a passkey, a key pair is generated:",[37,164,165,171],{},[40,166,167,170],{},[32,168,169],{},"Private key",": Stays on the user's device (never transmitted)",[40,172,173,176],{},[32,174,175],{},"Public key",": Sent to the server and stored in the user's account",[61,178,180],{"id":179},"registration-flow","Registration Flow",[182,183,188],"pre",{"className":184,"code":185,"language":186,"meta":187,"style":187},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F Step 1: Server generates a challenge and sends to client\nasync function startRegistration(userId, username) {\n  const challenge = crypto.getRandomValues(new Uint8Array(32));\n\n  \u002F\u002F Send challenge to server, receive registration options\n  const options = await fetch('\u002Fapi\u002Fpasskey\u002Fregister-options', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application\u002Fjson' },\n    body: JSON.stringify({ userId, username, challenge })\n  }).then(r => r.json());\n\n  \u002F\u002F Step 2: Create the passkey on the client\n  const credential = await navigator.credentials.create({\n    publicKey: {\n      challenge: base64urlToBuffer(options.challenge),\n      rp: {\n        name: \"Example App\",\n        id: \"example.com\"\n      },\n      user: {\n        id: base64urlToBuffer(options.userId),\n        name: username,\n        displayName: username\n      },\n      pubKeyCredParams: [\n        { alg: -7, type: \"public-key\" },   \u002F\u002F ES256\n        { alg: -257, type: \"public-key\" }  \u002F\u002F RS256\n      ],\n      authenticatorSelection: {\n        authenticatorAttachment: \"platform\", \u002F\u002F or \"cross-platform\" for security keys\n        userVerification: \"required\"\n      },\n      timeout: 60000\n    }\n  });\n\n  \u002F\u002F Step 3: Send the credential to server for storage\n  await fetch('\u002Fapi\u002Fpasskey\u002Fregister', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application\u002Fjson' },\n    body: JSON.stringify({\n      credentialId: bufferToBase64url(credential.rawId),\n      publicKey: bufferToBase64url(credential.response.publicKey),\n      attestation: bufferToBase64url(credential.response.attestationObject)\n    })\n  });\n}\n","javascript","",[189,190,191,200,231,266,273,279,304,316,334,352,378,383,389,410,416,428,434,445,454,460,466,476,482,488,493,499,523,543,549,555,569,578,583,592,598,604,609,615,630,639,652,665,677,688,699,705,710],"code",{"__ignoreMap":187},[192,193,196],"span",{"class":194,"line":195},"line",1,[192,197,199],{"class":198},"sJ8bj","\u002F\u002F Step 1: Server generates a challenge and sends to client\n",[192,201,203,207,210,214,218,222,225,228],{"class":194,"line":202},2,[192,204,206],{"class":205},"szBVR","async",[192,208,209],{"class":205}," function",[192,211,213],{"class":212},"sScJk"," startRegistration",[192,215,217],{"class":216},"sVt8B","(",[192,219,221],{"class":220},"s4XuR","userId",[192,223,224],{"class":216},", ",[192,226,227],{"class":220},"username",[192,229,230],{"class":216},") {\n",[192,232,234,237,241,244,247,250,252,255,258,260,263],{"class":194,"line":233},3,[192,235,236],{"class":205},"  const",[192,238,240],{"class":239},"sj4cs"," challenge",[192,242,243],{"class":205}," =",[192,245,246],{"class":216}," crypto.",[192,248,249],{"class":212},"getRandomValues",[192,251,217],{"class":216},[192,253,254],{"class":205},"new",[192,256,257],{"class":212}," Uint8Array",[192,259,217],{"class":216},[192,261,262],{"class":239},"32",[192,264,265],{"class":216},"));\n",[192,267,269],{"class":194,"line":268},4,[192,270,272],{"emptyLinePlaceholder":271},true,"\n",[192,274,276],{"class":194,"line":275},5,[192,277,278],{"class":198},"  \u002F\u002F Send challenge to server, receive registration options\n",[192,280,282,284,287,289,292,295,297,301],{"class":194,"line":281},6,[192,283,236],{"class":205},[192,285,286],{"class":239}," options",[192,288,243],{"class":205},[192,290,291],{"class":205}," await",[192,293,294],{"class":212}," fetch",[192,296,217],{"class":216},[192,298,300],{"class":299},"sZZnC","'\u002Fapi\u002Fpasskey\u002Fregister-options'",[192,302,303],{"class":216},", {\n",[192,305,307,310,313],{"class":194,"line":306},7,[192,308,309],{"class":216},"    method: ",[192,311,312],{"class":299},"'POST'",[192,314,315],{"class":216},",\n",[192,317,319,322,325,328,331],{"class":194,"line":318},8,[192,320,321],{"class":216},"    headers: { ",[192,323,324],{"class":299},"'Content-Type'",[192,326,327],{"class":216},": ",[192,329,330],{"class":299},"'application\u002Fjson'",[192,332,333],{"class":216}," },\n",[192,335,337,340,343,346,349],{"class":194,"line":336},9,[192,338,339],{"class":216},"    body: ",[192,341,342],{"class":239},"JSON",[192,344,345],{"class":216},".",[192,347,348],{"class":212},"stringify",[192,350,351],{"class":216},"({ userId, username, challenge })\n",[192,353,355,358,361,363,366,369,372,375],{"class":194,"line":354},10,[192,356,357],{"class":216},"  }).",[192,359,360],{"class":212},"then",[192,362,217],{"class":216},[192,364,365],{"class":220},"r",[192,367,368],{"class":205}," =>",[192,370,371],{"class":216}," r.",[192,373,374],{"class":212},"json",[192,376,377],{"class":216},"());\n",[192,379,381],{"class":194,"line":380},11,[192,382,272],{"emptyLinePlaceholder":271},[192,384,386],{"class":194,"line":385},12,[192,387,388],{"class":198},"  \u002F\u002F Step 2: Create the passkey on the client\n",[192,390,392,394,397,399,401,404,407],{"class":194,"line":391},13,[192,393,236],{"class":205},[192,395,396],{"class":239}," credential",[192,398,243],{"class":205},[192,400,291],{"class":205},[192,402,403],{"class":216}," navigator.credentials.",[192,405,406],{"class":212},"create",[192,408,409],{"class":216},"({\n",[192,411,413],{"class":194,"line":412},14,[192,414,415],{"class":216},"    publicKey: {\n",[192,417,419,422,425],{"class":194,"line":418},15,[192,420,421],{"class":216},"      challenge: ",[192,423,424],{"class":212},"base64urlToBuffer",[192,426,427],{"class":216},"(options.challenge),\n",[192,429,431],{"class":194,"line":430},16,[192,432,433],{"class":216},"      rp: {\n",[192,435,437,440,443],{"class":194,"line":436},17,[192,438,439],{"class":216},"        name: ",[192,441,442],{"class":299},"\"Example App\"",[192,444,315],{"class":216},[192,446,448,451],{"class":194,"line":447},18,[192,449,450],{"class":216},"        id: ",[192,452,453],{"class":299},"\"example.com\"\n",[192,455,457],{"class":194,"line":456},19,[192,458,459],{"class":216},"      },\n",[192,461,463],{"class":194,"line":462},20,[192,464,465],{"class":216},"      user: {\n",[192,467,469,471,473],{"class":194,"line":468},21,[192,470,450],{"class":216},[192,472,424],{"class":212},[192,474,475],{"class":216},"(options.userId),\n",[192,477,479],{"class":194,"line":478},22,[192,480,481],{"class":216},"        name: username,\n",[192,483,485],{"class":194,"line":484},23,[192,486,487],{"class":216},"        displayName: username\n",[192,489,491],{"class":194,"line":490},24,[192,492,459],{"class":216},[192,494,496],{"class":194,"line":495},25,[192,497,498],{"class":216},"      pubKeyCredParams: [\n",[192,500,502,505,508,511,514,517,520],{"class":194,"line":501},26,[192,503,504],{"class":216},"        { alg: ",[192,506,507],{"class":205},"-",[192,509,510],{"class":239},"7",[192,512,513],{"class":216},", type: ",[192,515,516],{"class":299},"\"public-key\"",[192,518,519],{"class":216}," },   ",[192,521,522],{"class":198},"\u002F\u002F ES256\n",[192,524,526,528,530,533,535,537,540],{"class":194,"line":525},27,[192,527,504],{"class":216},[192,529,507],{"class":205},[192,531,532],{"class":239},"257",[192,534,513],{"class":216},[192,536,516],{"class":299},[192,538,539],{"class":216}," }  ",[192,541,542],{"class":198},"\u002F\u002F RS256\n",[192,544,546],{"class":194,"line":545},28,[192,547,548],{"class":216},"      ],\n",[192,550,552],{"class":194,"line":551},29,[192,553,554],{"class":216},"      authenticatorSelection: {\n",[192,556,558,561,564,566],{"class":194,"line":557},30,[192,559,560],{"class":216},"        authenticatorAttachment: ",[192,562,563],{"class":299},"\"platform\"",[192,565,224],{"class":216},[192,567,568],{"class":198},"\u002F\u002F or \"cross-platform\" for security keys\n",[192,570,572,575],{"class":194,"line":571},31,[192,573,574],{"class":216},"        userVerification: ",[192,576,577],{"class":299},"\"required\"\n",[192,579,581],{"class":194,"line":580},32,[192,582,459],{"class":216},[192,584,586,589],{"class":194,"line":585},33,[192,587,588],{"class":216},"      timeout: ",[192,590,591],{"class":239},"60000\n",[192,593,595],{"class":194,"line":594},34,[192,596,597],{"class":216},"    }\n",[192,599,601],{"class":194,"line":600},35,[192,602,603],{"class":216},"  });\n",[192,605,607],{"class":194,"line":606},36,[192,608,272],{"emptyLinePlaceholder":271},[192,610,612],{"class":194,"line":611},37,[192,613,614],{"class":198},"  \u002F\u002F Step 3: Send the credential to server for storage\n",[192,616,618,621,623,625,628],{"class":194,"line":617},38,[192,619,620],{"class":205},"  await",[192,622,294],{"class":212},[192,624,217],{"class":216},[192,626,627],{"class":299},"'\u002Fapi\u002Fpasskey\u002Fregister'",[192,629,303],{"class":216},[192,631,633,635,637],{"class":194,"line":632},39,[192,634,309],{"class":216},[192,636,312],{"class":299},[192,638,315],{"class":216},[192,640,642,644,646,648,650],{"class":194,"line":641},40,[192,643,321],{"class":216},[192,645,324],{"class":299},[192,647,327],{"class":216},[192,649,330],{"class":299},[192,651,333],{"class":216},[192,653,655,657,659,661,663],{"class":194,"line":654},41,[192,656,339],{"class":216},[192,658,342],{"class":239},[192,660,345],{"class":216},[192,662,348],{"class":212},[192,664,409],{"class":216},[192,666,668,671,674],{"class":194,"line":667},42,[192,669,670],{"class":216},"      credentialId: ",[192,672,673],{"class":212},"bufferToBase64url",[192,675,676],{"class":216},"(credential.rawId),\n",[192,678,680,683,685],{"class":194,"line":679},43,[192,681,682],{"class":216},"      publicKey: ",[192,684,673],{"class":212},[192,686,687],{"class":216},"(credential.response.publicKey),\n",[192,689,691,694,696],{"class":194,"line":690},44,[192,692,693],{"class":216},"      attestation: ",[192,695,673],{"class":212},[192,697,698],{"class":216},"(credential.response.attestationObject)\n",[192,700,702],{"class":194,"line":701},45,[192,703,704],{"class":216},"    })\n",[192,706,708],{"class":194,"line":707},46,[192,709,603],{"class":216},[192,711,713],{"class":194,"line":712},47,[192,714,715],{"class":216},"}\n",[61,717,719],{"id":718},"authentication-flow","Authentication Flow",[182,721,723],{"className":184,"code":722,"language":186,"meta":187,"style":187},"async function startAuthentication() {\n  \u002F\u002F Step 1: Get authentication options from server\n  const options = await fetch('\u002Fapi\u002Fpasskey\u002Fauth-options').then(r => r.json());\n\n  \u002F\u002F Step 2: Get the passkey assertion from the client\n  const assertion = await navigator.credentials.get({\n    publicKey: {\n      challenge: base64urlToBuffer(options.challenge),\n      allowCredentials: options.allowedCredentials?.map(c => ({\n        id: base64urlToBuffer(c.id),\n        type: 'public-key'\n      })) || [],\n      userVerification: \"required\",\n      timeout: 60000\n    }\n  });\n\n  \u002F\u002F Step 3: Send assertion to server for verification\n  const result = await fetch('\u002Fapi\u002Fpasskey\u002Fauthenticate', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application\u002Fjson' },\n    body: JSON.stringify({\n      credentialId: bufferToBase64url(assertion.rawId),\n      authenticatorData: bufferToBase64url(assertion.response.authenticatorData),\n      clientDataJSON: bufferToBase64url(assertion.response.clientDataJSON),\n      signature: bufferToBase64url(assertion.response.signature)\n    })\n  }).then(r => r.json());\n\n  if (result.success) {\n    console.log(\"Authenticated successfully!\");\n  }\n}\n",[189,724,725,737,742,776,780,785,803,807,815,833,842,850,861,871,877,881,885,889,894,914,922,934,946,955,965,975,985,989,1007,1011,1019,1035,1040],{"__ignoreMap":187},[192,726,727,729,731,734],{"class":194,"line":195},[192,728,206],{"class":205},[192,730,209],{"class":205},[192,732,733],{"class":212}," startAuthentication",[192,735,736],{"class":216},"() {\n",[192,738,739],{"class":194,"line":202},[192,740,741],{"class":198},"  \u002F\u002F Step 1: Get authentication options from server\n",[192,743,744,746,748,750,752,754,756,759,762,764,766,768,770,772,774],{"class":194,"line":233},[192,745,236],{"class":205},[192,747,286],{"class":239},[192,749,243],{"class":205},[192,751,291],{"class":205},[192,753,294],{"class":212},[192,755,217],{"class":216},[192,757,758],{"class":299},"'\u002Fapi\u002Fpasskey\u002Fauth-options'",[192,760,761],{"class":216},").",[192,763,360],{"class":212},[192,765,217],{"class":216},[192,767,365],{"class":220},[192,769,368],{"class":205},[192,771,371],{"class":216},[192,773,374],{"class":212},[192,775,377],{"class":216},[192,777,778],{"class":194,"line":268},[192,779,272],{"emptyLinePlaceholder":271},[192,781,782],{"class":194,"line":275},[192,783,784],{"class":198},"  \u002F\u002F Step 2: Get the passkey assertion from the client\n",[192,786,787,789,792,794,796,798,801],{"class":194,"line":281},[192,788,236],{"class":205},[192,790,791],{"class":239}," assertion",[192,793,243],{"class":205},[192,795,291],{"class":205},[192,797,403],{"class":216},[192,799,800],{"class":212},"get",[192,802,409],{"class":216},[192,804,805],{"class":194,"line":306},[192,806,415],{"class":216},[192,808,809,811,813],{"class":194,"line":318},[192,810,421],{"class":216},[192,812,424],{"class":212},[192,814,427],{"class":216},[192,816,817,820,823,825,828,830],{"class":194,"line":336},[192,818,819],{"class":216},"      allowCredentials: options.allowedCredentials?.",[192,821,822],{"class":212},"map",[192,824,217],{"class":216},[192,826,827],{"class":220},"c",[192,829,368],{"class":205},[192,831,832],{"class":216}," ({\n",[192,834,835,837,839],{"class":194,"line":354},[192,836,450],{"class":216},[192,838,424],{"class":212},[192,840,841],{"class":216},"(c.id),\n",[192,843,844,847],{"class":194,"line":380},[192,845,846],{"class":216},"        type: ",[192,848,849],{"class":299},"'public-key'\n",[192,851,852,855,858],{"class":194,"line":385},[192,853,854],{"class":216},"      })) ",[192,856,857],{"class":205},"||",[192,859,860],{"class":216}," [],\n",[192,862,863,866,869],{"class":194,"line":391},[192,864,865],{"class":216},"      userVerification: ",[192,867,868],{"class":299},"\"required\"",[192,870,315],{"class":216},[192,872,873,875],{"class":194,"line":412},[192,874,588],{"class":216},[192,876,591],{"class":239},[192,878,879],{"class":194,"line":418},[192,880,597],{"class":216},[192,882,883],{"class":194,"line":430},[192,884,603],{"class":216},[192,886,887],{"class":194,"line":436},[192,888,272],{"emptyLinePlaceholder":271},[192,890,891],{"class":194,"line":447},[192,892,893],{"class":198},"  \u002F\u002F Step 3: Send assertion to server for verification\n",[192,895,896,898,901,903,905,907,909,912],{"class":194,"line":456},[192,897,236],{"class":205},[192,899,900],{"class":239}," result",[192,902,243],{"class":205},[192,904,291],{"class":205},[192,906,294],{"class":212},[192,908,217],{"class":216},[192,910,911],{"class":299},"'\u002Fapi\u002Fpasskey\u002Fauthenticate'",[192,913,303],{"class":216},[192,915,916,918,920],{"class":194,"line":462},[192,917,309],{"class":216},[192,919,312],{"class":299},[192,921,315],{"class":216},[192,923,924,926,928,930,932],{"class":194,"line":468},[192,925,321],{"class":216},[192,927,324],{"class":299},[192,929,327],{"class":216},[192,931,330],{"class":299},[192,933,333],{"class":216},[192,935,936,938,940,942,944],{"class":194,"line":478},[192,937,339],{"class":216},[192,939,342],{"class":239},[192,941,345],{"class":216},[192,943,348],{"class":212},[192,945,409],{"class":216},[192,947,948,950,952],{"class":194,"line":484},[192,949,670],{"class":216},[192,951,673],{"class":212},[192,953,954],{"class":216},"(assertion.rawId),\n",[192,956,957,960,962],{"class":194,"line":490},[192,958,959],{"class":216},"      authenticatorData: ",[192,961,673],{"class":212},[192,963,964],{"class":216},"(assertion.response.authenticatorData),\n",[192,966,967,970,972],{"class":194,"line":495},[192,968,969],{"class":216},"      clientDataJSON: ",[192,971,673],{"class":212},[192,973,974],{"class":216},"(assertion.response.clientDataJSON),\n",[192,976,977,980,982],{"class":194,"line":501},[192,978,979],{"class":216},"      signature: ",[192,981,673],{"class":212},[192,983,984],{"class":216},"(assertion.response.signature)\n",[192,986,987],{"class":194,"line":525},[192,988,704],{"class":216},[192,990,991,993,995,997,999,1001,1003,1005],{"class":194,"line":545},[192,992,357],{"class":216},[192,994,360],{"class":212},[192,996,217],{"class":216},[192,998,365],{"class":220},[192,1000,368],{"class":205},[192,1002,371],{"class":216},[192,1004,374],{"class":212},[192,1006,377],{"class":216},[192,1008,1009],{"class":194,"line":551},[192,1010,272],{"emptyLinePlaceholder":271},[192,1012,1013,1016],{"class":194,"line":557},[192,1014,1015],{"class":205},"  if",[192,1017,1018],{"class":216}," (result.success) {\n",[192,1020,1021,1024,1027,1029,1032],{"class":194,"line":571},[192,1022,1023],{"class":216},"    console.",[192,1025,1026],{"class":212},"log",[192,1028,217],{"class":216},[192,1030,1031],{"class":299},"\"Authenticated successfully!\"",[192,1033,1034],{"class":216},");\n",[192,1036,1037],{"class":194,"line":580},[192,1038,1039],{"class":216},"  }\n",[192,1041,1042],{"class":194,"line":585},[192,1043,715],{"class":216},[61,1045,1047],{"id":1046},"utility-functions","Utility Functions",[182,1049,1051],{"className":184,"code":1050,"language":186,"meta":187,"style":187},"\u002F\u002F Base64URL encoding\u002Fdecoding for WebAuthn\nfunction bufferToBase64url(buffer) {\n  const bytes = new Uint8Array(buffer);\n  let binary = '';\n  for (let i = 0; i \u003C bytes.byteLength; i++) {\n    binary += String.fromCharCode(bytes[i]);\n  }\n  return btoa(binary)\n    .replace(\u002F\\+\u002Fg, '-')\n    .replace(\u002F\\\u002F\u002Fg, '_')\n    .replace(\u002F=+$\u002F, '');\n}\n\nfunction base64urlToBuffer(base64url) {\n  const base64 = base64url\n    .replace(\u002F-\u002Fg, '+')\n    .replace(\u002F_\u002Fg, '\u002F');\n  const padded = base64 + '==='.slice((base64.length + 3) % 4);\n  const binary = atob(padded);\n  const buffer = new ArrayBuffer(binary.length);\n  const bytes = new Uint8Array(buffer);\n  for (let i = 0; i \u003C binary.length; i++) {\n    bytes[i] = binary.charCodeAt(i);\n  }\n  return buffer;\n}\n",[189,1052,1053,1058,1073,1090,1107,1140,1157,1161,1172,1202,1226,1251,1255,1259,1273,1285,1308,1332,1378,1393,1414,1428,1458,1473,1477,1484],{"__ignoreMap":187},[192,1054,1055],{"class":194,"line":195},[192,1056,1057],{"class":198},"\u002F\u002F Base64URL encoding\u002Fdecoding for WebAuthn\n",[192,1059,1060,1063,1066,1068,1071],{"class":194,"line":202},[192,1061,1062],{"class":205},"function",[192,1064,1065],{"class":212}," bufferToBase64url",[192,1067,217],{"class":216},[192,1069,1070],{"class":220},"buffer",[192,1072,230],{"class":216},[192,1074,1075,1077,1080,1082,1085,1087],{"class":194,"line":233},[192,1076,236],{"class":205},[192,1078,1079],{"class":239}," bytes",[192,1081,243],{"class":205},[192,1083,1084],{"class":205}," new",[192,1086,257],{"class":212},[192,1088,1089],{"class":216},"(buffer);\n",[192,1091,1092,1095,1098,1101,1104],{"class":194,"line":268},[192,1093,1094],{"class":205},"  let",[192,1096,1097],{"class":216}," binary ",[192,1099,1100],{"class":205},"=",[192,1102,1103],{"class":299}," ''",[192,1105,1106],{"class":216},";\n",[192,1108,1109,1112,1115,1118,1121,1123,1126,1129,1132,1135,1138],{"class":194,"line":275},[192,1110,1111],{"class":205},"  for",[192,1113,1114],{"class":216}," (",[192,1116,1117],{"class":205},"let",[192,1119,1120],{"class":216}," i ",[192,1122,1100],{"class":205},[192,1124,1125],{"class":239}," 0",[192,1127,1128],{"class":216},"; i ",[192,1130,1131],{"class":205},"\u003C",[192,1133,1134],{"class":216}," bytes.byteLength; i",[192,1136,1137],{"class":205},"++",[192,1139,230],{"class":216},[192,1141,1142,1145,1148,1151,1154],{"class":194,"line":281},[192,1143,1144],{"class":216},"    binary ",[192,1146,1147],{"class":205},"+=",[192,1149,1150],{"class":216}," String.",[192,1152,1153],{"class":212},"fromCharCode",[192,1155,1156],{"class":216},"(bytes[i]);\n",[192,1158,1159],{"class":194,"line":306},[192,1160,1039],{"class":216},[192,1162,1163,1166,1169],{"class":194,"line":318},[192,1164,1165],{"class":205},"  return",[192,1167,1168],{"class":212}," btoa",[192,1170,1171],{"class":216},"(binary)\n",[192,1173,1174,1177,1180,1182,1185,1189,1191,1194,1196,1199],{"class":194,"line":336},[192,1175,1176],{"class":216},"    .",[192,1178,1179],{"class":212},"replace",[192,1181,217],{"class":216},[192,1183,1184],{"class":299},"\u002F",[192,1186,1188],{"class":1187},"snhLl","\\+",[192,1190,1184],{"class":299},[192,1192,1193],{"class":205},"g",[192,1195,224],{"class":216},[192,1197,1198],{"class":299},"'-'",[192,1200,1201],{"class":216},")\n",[192,1203,1204,1206,1208,1210,1212,1215,1217,1219,1221,1224],{"class":194,"line":354},[192,1205,1176],{"class":216},[192,1207,1179],{"class":212},[192,1209,217],{"class":216},[192,1211,1184],{"class":299},[192,1213,1214],{"class":1187},"\\\u002F",[192,1216,1184],{"class":299},[192,1218,1193],{"class":205},[192,1220,224],{"class":216},[192,1222,1223],{"class":299},"'_'",[192,1225,1201],{"class":216},[192,1227,1228,1230,1232,1234,1236,1239,1242,1244,1246,1249],{"class":194,"line":380},[192,1229,1176],{"class":216},[192,1231,1179],{"class":212},[192,1233,217],{"class":216},[192,1235,1184],{"class":299},[192,1237,1100],{"class":1238},"sA_wV",[192,1240,1241],{"class":205},"+$",[192,1243,1184],{"class":299},[192,1245,224],{"class":216},[192,1247,1248],{"class":299},"''",[192,1250,1034],{"class":216},[192,1252,1253],{"class":194,"line":385},[192,1254,715],{"class":216},[192,1256,1257],{"class":194,"line":391},[192,1258,272],{"emptyLinePlaceholder":271},[192,1260,1261,1263,1266,1268,1271],{"class":194,"line":412},[192,1262,1062],{"class":205},[192,1264,1265],{"class":212}," base64urlToBuffer",[192,1267,217],{"class":216},[192,1269,1270],{"class":220},"base64url",[192,1272,230],{"class":216},[192,1274,1275,1277,1280,1282],{"class":194,"line":418},[192,1276,236],{"class":205},[192,1278,1279],{"class":239}," base64",[192,1281,243],{"class":205},[192,1283,1284],{"class":216}," base64url\n",[192,1286,1287,1289,1291,1293,1295,1297,1299,1301,1303,1306],{"class":194,"line":430},[192,1288,1176],{"class":216},[192,1290,1179],{"class":212},[192,1292,217],{"class":216},[192,1294,1184],{"class":299},[192,1296,507],{"class":1238},[192,1298,1184],{"class":299},[192,1300,1193],{"class":205},[192,1302,224],{"class":216},[192,1304,1305],{"class":299},"'+'",[192,1307,1201],{"class":216},[192,1309,1310,1312,1314,1316,1318,1321,1323,1325,1327,1330],{"class":194,"line":436},[192,1311,1176],{"class":216},[192,1313,1179],{"class":212},[192,1315,217],{"class":216},[192,1317,1184],{"class":299},[192,1319,1320],{"class":1238},"_",[192,1322,1184],{"class":299},[192,1324,1193],{"class":205},[192,1326,224],{"class":216},[192,1328,1329],{"class":299},"'\u002F'",[192,1331,1034],{"class":216},[192,1333,1334,1336,1339,1341,1344,1347,1350,1352,1355,1358,1361,1364,1367,1370,1373,1376],{"class":194,"line":447},[192,1335,236],{"class":205},[192,1337,1338],{"class":239}," padded",[192,1340,243],{"class":205},[192,1342,1343],{"class":216}," base64 ",[192,1345,1346],{"class":205},"+",[192,1348,1349],{"class":299}," '==='",[192,1351,345],{"class":216},[192,1353,1354],{"class":212},"slice",[192,1356,1357],{"class":216},"((base64.",[192,1359,1360],{"class":239},"length",[192,1362,1363],{"class":205}," +",[192,1365,1366],{"class":239}," 3",[192,1368,1369],{"class":216},") ",[192,1371,1372],{"class":205},"%",[192,1374,1375],{"class":239}," 4",[192,1377,1034],{"class":216},[192,1379,1380,1382,1385,1387,1390],{"class":194,"line":456},[192,1381,236],{"class":205},[192,1383,1384],{"class":239}," binary",[192,1386,243],{"class":205},[192,1388,1389],{"class":212}," atob",[192,1391,1392],{"class":216},"(padded);\n",[192,1394,1395,1397,1400,1402,1404,1407,1410,1412],{"class":194,"line":462},[192,1396,236],{"class":205},[192,1398,1399],{"class":239}," buffer",[192,1401,243],{"class":205},[192,1403,1084],{"class":205},[192,1405,1406],{"class":212}," ArrayBuffer",[192,1408,1409],{"class":216},"(binary.",[192,1411,1360],{"class":239},[192,1413,1034],{"class":216},[192,1415,1416,1418,1420,1422,1424,1426],{"class":194,"line":468},[192,1417,236],{"class":205},[192,1419,1079],{"class":239},[192,1421,243],{"class":205},[192,1423,1084],{"class":205},[192,1425,257],{"class":212},[192,1427,1089],{"class":216},[192,1429,1430,1432,1434,1436,1438,1440,1442,1444,1446,1449,1451,1454,1456],{"class":194,"line":478},[192,1431,1111],{"class":205},[192,1433,1114],{"class":216},[192,1435,1117],{"class":205},[192,1437,1120],{"class":216},[192,1439,1100],{"class":205},[192,1441,1125],{"class":239},[192,1443,1128],{"class":216},[192,1445,1131],{"class":205},[192,1447,1448],{"class":216}," binary.",[192,1450,1360],{"class":239},[192,1452,1453],{"class":216},"; i",[192,1455,1137],{"class":205},[192,1457,230],{"class":216},[192,1459,1460,1463,1465,1467,1470],{"class":194,"line":484},[192,1461,1462],{"class":216},"    bytes[i] ",[192,1464,1100],{"class":205},[192,1466,1448],{"class":216},[192,1468,1469],{"class":212},"charCodeAt",[192,1471,1472],{"class":216},"(i);\n",[192,1474,1475],{"class":194,"line":490},[192,1476,1039],{"class":216},[192,1478,1479,1481],{"class":194,"line":495},[192,1480,1165],{"class":205},[192,1482,1483],{"class":216}," buffer;\n",[192,1485,1486],{"class":194,"line":501},[192,1487,715],{"class":216},[10,1489,1491],{"id":1490},"passkeys-vs-passwords-detailed-comparison","Passkeys vs Passwords: Detailed Comparison",[61,1493,1495],{"id":1494},"security","Security",[66,1497,1498,1509],{},[69,1499,1500],{},[72,1501,1502,1505,1507],{},[75,1503,1504],{},"Threat",[75,1506,80],{},[75,1508,83],{},[85,1510,1511,1524,1537,1550,1563],{},[72,1512,1513,1518,1521],{},[90,1514,1515],{},[32,1516,1517],{},"Phishing",[90,1519,1520],{},"Vulnerable (user types password on fake site)",[90,1522,1523],{},"Immune (passkey bound to domain)",[72,1525,1526,1531,1534],{},[90,1527,1528],{},[32,1529,1530],{},"Credential stuffing",[90,1532,1533],{},"High risk (reused passwords)",[90,1535,1536],{},"Impossible (unique per site)",[72,1538,1539,1544,1547],{},[90,1540,1541],{},[32,1542,1543],{},"Server breach",[90,1545,1546],{},"Hashed passwords can be cracked",[90,1548,1549],{},"Only public keys exposed (useless to attacker)",[72,1551,1552,1557,1560],{},[90,1553,1554],{},[32,1555,1556],{},"Brute force",[90,1558,1559],{},"Possible with weak passwords",[90,1561,1562],{},"Not applicable (private key never leaves device)",[72,1564,1565,1570,1573],{},[90,1566,1567],{},[32,1568,1569],{},"Man-in-the-middle",[90,1571,1572],{},"Vulnerable (if not using HTTPS)",[90,1574,1575],{},"Resistant (origin binding)",[61,1577,1579],{"id":1578},"user-experience","User Experience",[66,1581,1582,1593],{},[69,1583,1584],{},[72,1585,1586,1589,1591],{},[75,1587,1588],{},"Aspect",[75,1590,80],{},[75,1592,83],{},[85,1594,1595,1608,1621,1634],{},[72,1596,1597,1602,1605],{},[90,1598,1599],{},[32,1600,1601],{},"Creation",[90,1603,1604],{},"User must invent\u002Fremember",[90,1606,1607],{},"Automatic (one tap)",[72,1609,1610,1615,1618],{},[90,1611,1612],{},[32,1613,1614],{},"Login speed",[90,1616,1617],{},"Type + submit (10-30 seconds)",[90,1619,1620],{},"Biometric\u002FPIN (2-5 seconds)",[72,1622,1623,1628,1631],{},[90,1624,1625],{},[32,1626,1627],{},"Recovery",[90,1629,1630],{},"Email reset (can be phished)",[90,1632,1633],{},"New device sync or backup",[72,1635,1636,1641,1644],{},[90,1637,1638],{},[32,1639,1640],{},"Cross-device",[90,1642,1643],{},"Works everywhere",[90,1645,1646],{},"Works with sync or QR code",[61,1648,1650],{"id":1649},"implementation-complexity","Implementation Complexity",[66,1652,1653,1663],{},[69,1654,1655],{},[72,1656,1657,1659,1661],{},[75,1658,1588],{},[75,1660,80],{},[75,1662,83],{},[85,1664,1665,1678,1691,1703],{},[72,1666,1667,1672,1675],{},[90,1668,1669],{},[32,1670,1671],{},"Backend",[90,1673,1674],{},"Simple (store hash)",[90,1676,1677],{},"Moderate (WebAuthn library needed)",[72,1679,1680,1685,1688],{},[90,1681,1682],{},[32,1683,1684],{},"Frontend",[90,1686,1687],{},"Simple (form POST)",[90,1689,1690],{},"Moderate (WebAuthn API)",[72,1692,1693,1697,1700],{},[90,1694,1695],{},[32,1696,1627],{},[90,1698,1699],{},"Email-based",[90,1701,1702],{},"Device sync or fallback methods",[72,1704,1705,1710,1713],{},[90,1706,1707],{},[32,1708,1709],{},"Legacy support",[90,1711,1712],{},"Universal",[90,1714,1715],{},"Requires modern browser",[10,1717,1719],{"id":1718},"browser-and-platform-support","Browser and Platform Support",[61,1721,1723],{"id":1722},"current-support-2026","Current Support (2026)",[66,1725,1726,1742],{},[69,1727,1728],{},[72,1729,1730,1733,1736,1739],{},[75,1731,1732],{},"Platform",[75,1734,1735],{},"Browser",[75,1737,1738],{},"Supported",[75,1740,1741],{},"Notes",[85,1743,1744,1760,1771,1782,1793,1808,1820],{},[72,1745,1746,1751,1754,1757],{},[90,1747,1748],{},[32,1749,1750],{},"Desktop",[90,1752,1753],{},"Chrome 108+",[90,1755,1756],{},"✅",[90,1758,1759],{},"Full support",[72,1761,1762,1764,1767,1769],{},[90,1763],{},[90,1765,1766],{},"Firefox 119+",[90,1768,1756],{},[90,1770,1759],{},[72,1772,1773,1775,1778,1780],{},[90,1774],{},[90,1776,1777],{},"Safari 16+",[90,1779,1756],{},[90,1781,1759],{},[72,1783,1784,1786,1789,1791],{},[90,1785],{},[90,1787,1788],{},"Edge 108+",[90,1790,1756],{},[90,1792,1759],{},[72,1794,1795,1800,1803,1805],{},[90,1796,1797],{},[32,1798,1799],{},"Mobile",[90,1801,1802],{},"iOS 16+ Safari",[90,1804,1756],{},[90,1806,1807],{},"Face ID \u002F Touch ID",[72,1809,1810,1812,1815,1817],{},[90,1811],{},[90,1813,1814],{},"Android Chrome 108+",[90,1816,1756],{},[90,1818,1819],{},"Fingerprint \u002F Screen lock",[72,1821,1822,1824,1827,1829],{},[90,1823],{},[90,1825,1826],{},"Samsung Internet 23+",[90,1828,1756],{},[90,1830,1831],{},"Fingerprint",[61,1833,1835],{"id":1834},"checking-for-support","Checking for Support",[182,1837,1839],{"className":184,"code":1838,"language":186,"meta":187,"style":187},"function isPasskeySupported() {\n  return window.PublicKeyCredential !== undefined &&\n         typeof window.PublicKeyCredential === 'function' &&\n         \u002F\u002F Check if platform authenticator is available\n         PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();\n}\n\nisPasskeySupported().then(supported => {\n  if (supported) {\n    console.log(\"Passkeys are supported!\");\n  } else {\n    console.log(\"Passkeys not available, show password login\");\n  }\n});\n",[189,1840,1841,1850,1866,1881,1886,1897,1901,1905,1925,1932,1945,1955,1968,1972],{"__ignoreMap":187},[192,1842,1843,1845,1848],{"class":194,"line":195},[192,1844,1062],{"class":205},[192,1846,1847],{"class":212}," isPasskeySupported",[192,1849,736],{"class":216},[192,1851,1852,1854,1857,1860,1863],{"class":194,"line":202},[192,1853,1165],{"class":205},[192,1855,1856],{"class":216}," window.PublicKeyCredential ",[192,1858,1859],{"class":205},"!==",[192,1861,1862],{"class":239}," undefined",[192,1864,1865],{"class":205}," &&\n",[192,1867,1868,1871,1873,1876,1879],{"class":194,"line":233},[192,1869,1870],{"class":205},"         typeof",[192,1872,1856],{"class":216},[192,1874,1875],{"class":205},"===",[192,1877,1878],{"class":299}," 'function'",[192,1880,1865],{"class":205},[192,1882,1883],{"class":194,"line":268},[192,1884,1885],{"class":198},"         \u002F\u002F Check if platform authenticator is available\n",[192,1887,1888,1891,1894],{"class":194,"line":275},[192,1889,1890],{"class":216},"         PublicKeyCredential.",[192,1892,1893],{"class":212},"isUserVerifyingPlatformAuthenticatorAvailable",[192,1895,1896],{"class":216},"();\n",[192,1898,1899],{"class":194,"line":281},[192,1900,715],{"class":216},[192,1902,1903],{"class":194,"line":306},[192,1904,272],{"emptyLinePlaceholder":271},[192,1906,1907,1910,1913,1915,1917,1920,1922],{"class":194,"line":318},[192,1908,1909],{"class":212},"isPasskeySupported",[192,1911,1912],{"class":216},"().",[192,1914,360],{"class":212},[192,1916,217],{"class":216},[192,1918,1919],{"class":220},"supported",[192,1921,368],{"class":205},[192,1923,1924],{"class":216}," {\n",[192,1926,1927,1929],{"class":194,"line":336},[192,1928,1015],{"class":205},[192,1930,1931],{"class":216}," (supported) {\n",[192,1933,1934,1936,1938,1940,1943],{"class":194,"line":354},[192,1935,1023],{"class":216},[192,1937,1026],{"class":212},[192,1939,217],{"class":216},[192,1941,1942],{"class":299},"\"Passkeys are supported!\"",[192,1944,1034],{"class":216},[192,1946,1947,1950,1953],{"class":194,"line":380},[192,1948,1949],{"class":216},"  } ",[192,1951,1952],{"class":205},"else",[192,1954,1924],{"class":216},[192,1956,1957,1959,1961,1963,1966],{"class":194,"line":385},[192,1958,1023],{"class":216},[192,1960,1026],{"class":212},[192,1962,217],{"class":216},[192,1964,1965],{"class":299},"\"Passkeys not available, show password login\"",[192,1967,1034],{"class":216},[192,1969,1970],{"class":194,"line":391},[192,1971,1039],{"class":216},[192,1973,1974],{"class":194,"line":412},[192,1975,1976],{"class":216},"});\n",[10,1978,1980],{"id":1979},"server-side-implementation","Server-Side Implementation",[61,1982,1984],{"id":1983},"nodejs-example","Node.js Example",[182,1986,1988],{"className":184,"code":1987,"language":186,"meta":187,"style":187},"const express = require('express');\nconst crypto = require('crypto');\nconst app = express();\n\n\u002F\u002F In production, use a WebAuthn library like @simplewebauthn\u002Fserver\n\u002F\u002F This is a simplified example\n\nconst userChallenges = new Map(); \u002F\u002F Store challenges temporarily\nconst userCredentials = new Map(); \u002F\u002F Store registered credentials\n\n\u002F\u002F Step 1: Generate registration options\napp.post('\u002Fapi\u002Fpasskey\u002Fregister-options', (req, res) => {\n  const { userId, username } = req.body;\n  const challenge = crypto.randomBytes(32).toString('base64url');\n\n  \u002F\u002F Store challenge for this user\n  userChallenges.set(userId, challenge);\n\n  res.json({\n    challenge,\n    rp: { name: \"Example App\", id: \"localhost\" },\n    user: { id: userId, name: username, displayName: username },\n    pubKeyCredParams: [\n      { alg: -7, type: \"public-key\" },   \u002F\u002F ES256\n      { alg: -257, type: \"public-key\" }   \u002F\u002F RS256\n    ]\n  });\n});\n\n\u002F\u002F Step 2: Verify registration\napp.post('\u002Fapi\u002Fpasskey\u002Fregister', (req, res) => {\n  const { credentialId, publicKey, userId } = req.body;\n\n  \u002F\u002F In production: verify the attestation using a library\n  \u002F\u002F Store the public key for this user\n  userCredentials.set(userId, { credentialId, publicKey });\n\n  res.json({ success: true });\n});\n\n\u002F\u002F Step 3: Generate authentication options\napp.post('\u002Fapi\u002Fpasskey\u002Fauth-options', (req, res) => {\n  const challenge = crypto.randomBytes(32).toString('base64url');\n\n  \u002F\u002F In production: associate challenge with session\n  res.json({\n    challenge,\n    allowCredentials: [] \u002F\u002F or list specific credential IDs\n  });\n});\n\n\u002F\u002F Step 4: Verify authentication\napp.post('\u002Fapi\u002Fpasskey\u002Fauthenticate', (req, res) => {\n  const { credentialId, signature, authenticatorData, clientDataJSON } = req.body;\n\n  \u002F\u002F In production: verify the signature using the stored public key\n  \u002F\u002F If valid, issue a session token\n\n  res.json({ success: true, token: \"session-token-here\" });\n});\n",[189,1989,1990,2010,2028,2041,2045,2050,2055,2059,2079,2097,2101,2106,2136,2157,2186,2190,2195,2206,2210,2219,2224,2239,2244,2249,2266,2283,2288,2292,2296,2300,2305,2329,2353,2357,2362,2367,2377,2381,2396,2400,2404,2409,2433,2459,2463,2468,2476,2480,2489,2494,2499,2504,2510,2535,2565,2570,2576,2582,2587,2606],{"__ignoreMap":187},[192,1991,1992,1995,1998,2000,2003,2005,2008],{"class":194,"line":195},[192,1993,1994],{"class":205},"const",[192,1996,1997],{"class":239}," express",[192,1999,243],{"class":205},[192,2001,2002],{"class":212}," require",[192,2004,217],{"class":216},[192,2006,2007],{"class":299},"'express'",[192,2009,1034],{"class":216},[192,2011,2012,2014,2017,2019,2021,2023,2026],{"class":194,"line":202},[192,2013,1994],{"class":205},[192,2015,2016],{"class":239}," crypto",[192,2018,243],{"class":205},[192,2020,2002],{"class":212},[192,2022,217],{"class":216},[192,2024,2025],{"class":299},"'crypto'",[192,2027,1034],{"class":216},[192,2029,2030,2032,2035,2037,2039],{"class":194,"line":233},[192,2031,1994],{"class":205},[192,2033,2034],{"class":239}," app",[192,2036,243],{"class":205},[192,2038,1997],{"class":212},[192,2040,1896],{"class":216},[192,2042,2043],{"class":194,"line":268},[192,2044,272],{"emptyLinePlaceholder":271},[192,2046,2047],{"class":194,"line":275},[192,2048,2049],{"class":198},"\u002F\u002F In production, use a WebAuthn library like @simplewebauthn\u002Fserver\n",[192,2051,2052],{"class":194,"line":281},[192,2053,2054],{"class":198},"\u002F\u002F This is a simplified example\n",[192,2056,2057],{"class":194,"line":306},[192,2058,272],{"emptyLinePlaceholder":271},[192,2060,2061,2063,2066,2068,2070,2073,2076],{"class":194,"line":318},[192,2062,1994],{"class":205},[192,2064,2065],{"class":239}," userChallenges",[192,2067,243],{"class":205},[192,2069,1084],{"class":205},[192,2071,2072],{"class":212}," Map",[192,2074,2075],{"class":216},"(); ",[192,2077,2078],{"class":198},"\u002F\u002F Store challenges temporarily\n",[192,2080,2081,2083,2086,2088,2090,2092,2094],{"class":194,"line":336},[192,2082,1994],{"class":205},[192,2084,2085],{"class":239}," userCredentials",[192,2087,243],{"class":205},[192,2089,1084],{"class":205},[192,2091,2072],{"class":212},[192,2093,2075],{"class":216},[192,2095,2096],{"class":198},"\u002F\u002F Store registered credentials\n",[192,2098,2099],{"class":194,"line":354},[192,2100,272],{"emptyLinePlaceholder":271},[192,2102,2103],{"class":194,"line":380},[192,2104,2105],{"class":198},"\u002F\u002F Step 1: Generate registration options\n",[192,2107,2108,2111,2114,2116,2118,2121,2124,2126,2129,2131,2134],{"class":194,"line":385},[192,2109,2110],{"class":216},"app.",[192,2112,2113],{"class":212},"post",[192,2115,217],{"class":216},[192,2117,300],{"class":299},[192,2119,2120],{"class":216},", (",[192,2122,2123],{"class":220},"req",[192,2125,224],{"class":216},[192,2127,2128],{"class":220},"res",[192,2130,1369],{"class":216},[192,2132,2133],{"class":205},"=>",[192,2135,1924],{"class":216},[192,2137,2138,2140,2143,2145,2147,2149,2152,2154],{"class":194,"line":391},[192,2139,236],{"class":205},[192,2141,2142],{"class":216}," { ",[192,2144,221],{"class":239},[192,2146,224],{"class":216},[192,2148,227],{"class":239},[192,2150,2151],{"class":216}," } ",[192,2153,1100],{"class":205},[192,2155,2156],{"class":216}," req.body;\n",[192,2158,2159,2161,2163,2165,2167,2170,2172,2174,2176,2179,2181,2184],{"class":194,"line":412},[192,2160,236],{"class":205},[192,2162,240],{"class":239},[192,2164,243],{"class":205},[192,2166,246],{"class":216},[192,2168,2169],{"class":212},"randomBytes",[192,2171,217],{"class":216},[192,2173,262],{"class":239},[192,2175,761],{"class":216},[192,2177,2178],{"class":212},"toString",[192,2180,217],{"class":216},[192,2182,2183],{"class":299},"'base64url'",[192,2185,1034],{"class":216},[192,2187,2188],{"class":194,"line":418},[192,2189,272],{"emptyLinePlaceholder":271},[192,2191,2192],{"class":194,"line":430},[192,2193,2194],{"class":198},"  \u002F\u002F Store challenge for this user\n",[192,2196,2197,2200,2203],{"class":194,"line":436},[192,2198,2199],{"class":216},"  userChallenges.",[192,2201,2202],{"class":212},"set",[192,2204,2205],{"class":216},"(userId, challenge);\n",[192,2207,2208],{"class":194,"line":447},[192,2209,272],{"emptyLinePlaceholder":271},[192,2211,2212,2215,2217],{"class":194,"line":456},[192,2213,2214],{"class":216},"  res.",[192,2216,374],{"class":212},[192,2218,409],{"class":216},[192,2220,2221],{"class":194,"line":462},[192,2222,2223],{"class":216},"    challenge,\n",[192,2225,2226,2229,2231,2234,2237],{"class":194,"line":468},[192,2227,2228],{"class":216},"    rp: { name: ",[192,2230,442],{"class":299},[192,2232,2233],{"class":216},", id: ",[192,2235,2236],{"class":299},"\"localhost\"",[192,2238,333],{"class":216},[192,2240,2241],{"class":194,"line":478},[192,2242,2243],{"class":216},"    user: { id: userId, name: username, displayName: username },\n",[192,2245,2246],{"class":194,"line":484},[192,2247,2248],{"class":216},"    pubKeyCredParams: [\n",[192,2250,2251,2254,2256,2258,2260,2262,2264],{"class":194,"line":490},[192,2252,2253],{"class":216},"      { alg: ",[192,2255,507],{"class":205},[192,2257,510],{"class":239},[192,2259,513],{"class":216},[192,2261,516],{"class":299},[192,2263,519],{"class":216},[192,2265,522],{"class":198},[192,2267,2268,2270,2272,2274,2276,2278,2281],{"class":194,"line":495},[192,2269,2253],{"class":216},[192,2271,507],{"class":205},[192,2273,532],{"class":239},[192,2275,513],{"class":216},[192,2277,516],{"class":299},[192,2279,2280],{"class":216}," }   ",[192,2282,542],{"class":198},[192,2284,2285],{"class":194,"line":501},[192,2286,2287],{"class":216},"    ]\n",[192,2289,2290],{"class":194,"line":525},[192,2291,603],{"class":216},[192,2293,2294],{"class":194,"line":545},[192,2295,1976],{"class":216},[192,2297,2298],{"class":194,"line":551},[192,2299,272],{"emptyLinePlaceholder":271},[192,2301,2302],{"class":194,"line":557},[192,2303,2304],{"class":198},"\u002F\u002F Step 2: Verify registration\n",[192,2306,2307,2309,2311,2313,2315,2317,2319,2321,2323,2325,2327],{"class":194,"line":571},[192,2308,2110],{"class":216},[192,2310,2113],{"class":212},[192,2312,217],{"class":216},[192,2314,627],{"class":299},[192,2316,2120],{"class":216},[192,2318,2123],{"class":220},[192,2320,224],{"class":216},[192,2322,2128],{"class":220},[192,2324,1369],{"class":216},[192,2326,2133],{"class":205},[192,2328,1924],{"class":216},[192,2330,2331,2333,2335,2338,2340,2343,2345,2347,2349,2351],{"class":194,"line":580},[192,2332,236],{"class":205},[192,2334,2142],{"class":216},[192,2336,2337],{"class":239},"credentialId",[192,2339,224],{"class":216},[192,2341,2342],{"class":239},"publicKey",[192,2344,224],{"class":216},[192,2346,221],{"class":239},[192,2348,2151],{"class":216},[192,2350,1100],{"class":205},[192,2352,2156],{"class":216},[192,2354,2355],{"class":194,"line":585},[192,2356,272],{"emptyLinePlaceholder":271},[192,2358,2359],{"class":194,"line":594},[192,2360,2361],{"class":198},"  \u002F\u002F In production: verify the attestation using a library\n",[192,2363,2364],{"class":194,"line":600},[192,2365,2366],{"class":198},"  \u002F\u002F Store the public key for this user\n",[192,2368,2369,2372,2374],{"class":194,"line":606},[192,2370,2371],{"class":216},"  userCredentials.",[192,2373,2202],{"class":212},[192,2375,2376],{"class":216},"(userId, { credentialId, publicKey });\n",[192,2378,2379],{"class":194,"line":611},[192,2380,272],{"emptyLinePlaceholder":271},[192,2382,2383,2385,2387,2390,2393],{"class":194,"line":617},[192,2384,2214],{"class":216},[192,2386,374],{"class":212},[192,2388,2389],{"class":216},"({ success: ",[192,2391,2392],{"class":239},"true",[192,2394,2395],{"class":216}," });\n",[192,2397,2398],{"class":194,"line":632},[192,2399,1976],{"class":216},[192,2401,2402],{"class":194,"line":641},[192,2403,272],{"emptyLinePlaceholder":271},[192,2405,2406],{"class":194,"line":654},[192,2407,2408],{"class":198},"\u002F\u002F Step 3: Generate authentication options\n",[192,2410,2411,2413,2415,2417,2419,2421,2423,2425,2427,2429,2431],{"class":194,"line":667},[192,2412,2110],{"class":216},[192,2414,2113],{"class":212},[192,2416,217],{"class":216},[192,2418,758],{"class":299},[192,2420,2120],{"class":216},[192,2422,2123],{"class":220},[192,2424,224],{"class":216},[192,2426,2128],{"class":220},[192,2428,1369],{"class":216},[192,2430,2133],{"class":205},[192,2432,1924],{"class":216},[192,2434,2435,2437,2439,2441,2443,2445,2447,2449,2451,2453,2455,2457],{"class":194,"line":679},[192,2436,236],{"class":205},[192,2438,240],{"class":239},[192,2440,243],{"class":205},[192,2442,246],{"class":216},[192,2444,2169],{"class":212},[192,2446,217],{"class":216},[192,2448,262],{"class":239},[192,2450,761],{"class":216},[192,2452,2178],{"class":212},[192,2454,217],{"class":216},[192,2456,2183],{"class":299},[192,2458,1034],{"class":216},[192,2460,2461],{"class":194,"line":690},[192,2462,272],{"emptyLinePlaceholder":271},[192,2464,2465],{"class":194,"line":701},[192,2466,2467],{"class":198},"  \u002F\u002F In production: associate challenge with session\n",[192,2469,2470,2472,2474],{"class":194,"line":707},[192,2471,2214],{"class":216},[192,2473,374],{"class":212},[192,2475,409],{"class":216},[192,2477,2478],{"class":194,"line":712},[192,2479,2223],{"class":216},[192,2481,2483,2486],{"class":194,"line":2482},48,[192,2484,2485],{"class":216},"    allowCredentials: [] ",[192,2487,2488],{"class":198},"\u002F\u002F or list specific credential IDs\n",[192,2490,2492],{"class":194,"line":2491},49,[192,2493,603],{"class":216},[192,2495,2497],{"class":194,"line":2496},50,[192,2498,1976],{"class":216},[192,2500,2502],{"class":194,"line":2501},51,[192,2503,272],{"emptyLinePlaceholder":271},[192,2505,2507],{"class":194,"line":2506},52,[192,2508,2509],{"class":198},"\u002F\u002F Step 4: Verify authentication\n",[192,2511,2513,2515,2517,2519,2521,2523,2525,2527,2529,2531,2533],{"class":194,"line":2512},53,[192,2514,2110],{"class":216},[192,2516,2113],{"class":212},[192,2518,217],{"class":216},[192,2520,911],{"class":299},[192,2522,2120],{"class":216},[192,2524,2123],{"class":220},[192,2526,224],{"class":216},[192,2528,2128],{"class":220},[192,2530,1369],{"class":216},[192,2532,2133],{"class":205},[192,2534,1924],{"class":216},[192,2536,2538,2540,2542,2544,2546,2549,2551,2554,2556,2559,2561,2563],{"class":194,"line":2537},54,[192,2539,236],{"class":205},[192,2541,2142],{"class":216},[192,2543,2337],{"class":239},[192,2545,224],{"class":216},[192,2547,2548],{"class":239},"signature",[192,2550,224],{"class":216},[192,2552,2553],{"class":239},"authenticatorData",[192,2555,224],{"class":216},[192,2557,2558],{"class":239},"clientDataJSON",[192,2560,2151],{"class":216},[192,2562,1100],{"class":205},[192,2564,2156],{"class":216},[192,2566,2568],{"class":194,"line":2567},55,[192,2569,272],{"emptyLinePlaceholder":271},[192,2571,2573],{"class":194,"line":2572},56,[192,2574,2575],{"class":198},"  \u002F\u002F In production: verify the signature using the stored public key\n",[192,2577,2579],{"class":194,"line":2578},57,[192,2580,2581],{"class":198},"  \u002F\u002F If valid, issue a session token\n",[192,2583,2585],{"class":194,"line":2584},58,[192,2586,272],{"emptyLinePlaceholder":271},[192,2588,2590,2592,2594,2596,2598,2601,2604],{"class":194,"line":2589},59,[192,2591,2214],{"class":216},[192,2593,374],{"class":212},[192,2595,2389],{"class":216},[192,2597,2392],{"class":239},[192,2599,2600],{"class":216},", token: ",[192,2602,2603],{"class":299},"\"session-token-here\"",[192,2605,2395],{"class":216},[192,2607,2609],{"class":194,"line":2608},60,[192,2610,1976],{"class":216},[61,2612,2614],{"id":2613},"using-a-library-recommended","Using a Library (Recommended)",[15,2616,2617,2618,2621],{},"For production, use a well-tested library like ",[189,2619,2620],{},"@simplewebauthn\u002Fserver",":",[182,2623,2625],{"className":184,"code":2624,"language":186,"meta":187,"style":187},"import { generateRegistrationOptions, verifyRegistrationResponse } from '@simplewebauthn\u002Fserver';\n\nconst rpName = 'Example App';\nconst rpID = 'example.com';\nconst origin = `https:\u002F\u002F${rpID}`;\n\n\u002F\u002F Registration\nconst options = await generateRegistrationOptions({\n  rpName,\n  rpID,\n  userID: userId,\n  userName: username,\n  attestationType: 'none',\n  excludeCredentials: existingCredentials,\n});\n\nconst verification = await verifyRegistrationResponse({\n  response: credential,\n  expectedChallenge: options.challenge,\n  expectedOrigin: origin,\n  expectedRPID: rpID,\n});\n",[189,2626,2627,2643,2647,2661,2675,2695,2699,2704,2719,2724,2729,2734,2739,2749,2754,2758,2762,2778,2783,2788,2793,2798],{"__ignoreMap":187},[192,2628,2629,2632,2635,2638,2641],{"class":194,"line":195},[192,2630,2631],{"class":205},"import",[192,2633,2634],{"class":216}," { generateRegistrationOptions, verifyRegistrationResponse } ",[192,2636,2637],{"class":205},"from",[192,2639,2640],{"class":299}," '@simplewebauthn\u002Fserver'",[192,2642,1106],{"class":216},[192,2644,2645],{"class":194,"line":202},[192,2646,272],{"emptyLinePlaceholder":271},[192,2648,2649,2651,2654,2656,2659],{"class":194,"line":233},[192,2650,1994],{"class":205},[192,2652,2653],{"class":239}," rpName",[192,2655,243],{"class":205},[192,2657,2658],{"class":299}," 'Example App'",[192,2660,1106],{"class":216},[192,2662,2663,2665,2668,2670,2673],{"class":194,"line":268},[192,2664,1994],{"class":205},[192,2666,2667],{"class":239}," rpID",[192,2669,243],{"class":205},[192,2671,2672],{"class":299}," 'example.com'",[192,2674,1106],{"class":216},[192,2676,2677,2679,2682,2684,2687,2690,2693],{"class":194,"line":275},[192,2678,1994],{"class":205},[192,2680,2681],{"class":239}," origin",[192,2683,243],{"class":205},[192,2685,2686],{"class":299}," `https:\u002F\u002F${",[192,2688,2689],{"class":216},"rpID",[192,2691,2692],{"class":299},"}`",[192,2694,1106],{"class":216},[192,2696,2697],{"class":194,"line":281},[192,2698,272],{"emptyLinePlaceholder":271},[192,2700,2701],{"class":194,"line":306},[192,2702,2703],{"class":198},"\u002F\u002F Registration\n",[192,2705,2706,2708,2710,2712,2714,2717],{"class":194,"line":318},[192,2707,1994],{"class":205},[192,2709,286],{"class":239},[192,2711,243],{"class":205},[192,2713,291],{"class":205},[192,2715,2716],{"class":212}," generateRegistrationOptions",[192,2718,409],{"class":216},[192,2720,2721],{"class":194,"line":336},[192,2722,2723],{"class":216},"  rpName,\n",[192,2725,2726],{"class":194,"line":354},[192,2727,2728],{"class":216},"  rpID,\n",[192,2730,2731],{"class":194,"line":380},[192,2732,2733],{"class":216},"  userID: userId,\n",[192,2735,2736],{"class":194,"line":385},[192,2737,2738],{"class":216},"  userName: username,\n",[192,2740,2741,2744,2747],{"class":194,"line":391},[192,2742,2743],{"class":216},"  attestationType: ",[192,2745,2746],{"class":299},"'none'",[192,2748,315],{"class":216},[192,2750,2751],{"class":194,"line":412},[192,2752,2753],{"class":216},"  excludeCredentials: existingCredentials,\n",[192,2755,2756],{"class":194,"line":418},[192,2757,1976],{"class":216},[192,2759,2760],{"class":194,"line":430},[192,2761,272],{"emptyLinePlaceholder":271},[192,2763,2764,2766,2769,2771,2773,2776],{"class":194,"line":436},[192,2765,1994],{"class":205},[192,2767,2768],{"class":239}," verification",[192,2770,243],{"class":205},[192,2772,291],{"class":205},[192,2774,2775],{"class":212}," verifyRegistrationResponse",[192,2777,409],{"class":216},[192,2779,2780],{"class":194,"line":447},[192,2781,2782],{"class":216},"  response: credential,\n",[192,2784,2785],{"class":194,"line":456},[192,2786,2787],{"class":216},"  expectedChallenge: options.challenge,\n",[192,2789,2790],{"class":194,"line":462},[192,2791,2792],{"class":216},"  expectedOrigin: origin,\n",[192,2794,2795],{"class":194,"line":468},[192,2796,2797],{"class":216},"  expectedRPID: rpID,\n",[192,2799,2800],{"class":194,"line":478},[192,2801,1976],{"class":216},[10,2803,2805],{"id":2804},"cross-device-authentication","Cross-Device Authentication",[15,2807,2808],{},"One of the challenges with passkeys is using them on a new device. The FIDO standard supports this via:",[61,2810,2812],{"id":2811},"_1-cloud-sync-most-common","1. Cloud Sync (Most Common)",[15,2814,2815],{},"Passkeys synced via:",[37,2817,2818,2824,2830],{},[40,2819,2820,2823],{},[32,2821,2822],{},"iCloud Keychain"," (Apple devices)",[40,2825,2826,2829],{},[32,2827,2828],{},"Google Password Manager"," (Android\u002FChrome)",[40,2831,2832,2835],{},[32,2833,2834],{},"Microsoft Account"," (Windows\u002FEdge)",[15,2837,2838],{},"When the user signs into their account on a new device, their passkeys sync automatically.",[61,2840,2842],{"id":2841},"_2-qr-code-flow-hybrid","2. QR Code Flow (Hybrid)",[15,2844,2845],{},"For using a passkey from a phone on a desktop:",[182,2847,2849],{"className":184,"code":2848,"language":186,"meta":187,"style":187},"\u002F\u002F Desktop browser shows QR code\n\u002F\u002F User scans with phone (which has the passkey)\n\u002F\u002F Phone signs the challenge and sends it back\nconst assertion = await navigator.credentials.get({\n  publicKey: {\n    challenge: ...,\n    extensions: {\n      appid: true \u002F\u002F For backwards compatibility\n    }\n  }\n});\n",[189,2850,2851,2856,2861,2866,2882,2887,2897,2902,2912,2916,2920],{"__ignoreMap":187},[192,2852,2853],{"class":194,"line":195},[192,2854,2855],{"class":198},"\u002F\u002F Desktop browser shows QR code\n",[192,2857,2858],{"class":194,"line":202},[192,2859,2860],{"class":198},"\u002F\u002F User scans with phone (which has the passkey)\n",[192,2862,2863],{"class":194,"line":233},[192,2864,2865],{"class":198},"\u002F\u002F Phone signs the challenge and sends it back\n",[192,2867,2868,2870,2872,2874,2876,2878,2880],{"class":194,"line":268},[192,2869,1994],{"class":205},[192,2871,791],{"class":239},[192,2873,243],{"class":205},[192,2875,291],{"class":205},[192,2877,403],{"class":216},[192,2879,800],{"class":212},[192,2881,409],{"class":216},[192,2883,2884],{"class":194,"line":275},[192,2885,2886],{"class":216},"  publicKey: {\n",[192,2888,2889,2892,2895],{"class":194,"line":281},[192,2890,2891],{"class":216},"    challenge: ",[192,2893,2894],{"class":205},"...",[192,2896,315],{"class":216},[192,2898,2899],{"class":194,"line":306},[192,2900,2901],{"class":216},"    extensions: {\n",[192,2903,2904,2907,2909],{"class":194,"line":318},[192,2905,2906],{"class":216},"      appid: ",[192,2908,2392],{"class":239},[192,2910,2911],{"class":198}," \u002F\u002F For backwards compatibility\n",[192,2913,2914],{"class":194,"line":336},[192,2915,597],{"class":216},[192,2917,2918],{"class":194,"line":354},[192,2919,1039],{"class":216},[192,2921,2922],{"class":194,"line":380},[192,2923,1976],{"class":216},[10,2925,2927],{"id":2926},"fallback-strategies","Fallback Strategies",[15,2929,2930],{},"Not all users will have passkey-capable devices. Implement a graceful fallback:",[182,2932,2934],{"className":184,"code":2933,"language":186,"meta":187,"style":187},"async function authenticate() {\n  \u002F\u002F Try passkey first\n  if (await isPasskeySupported()) {\n    try {\n      return await startAuthentication();\n    } catch (error) {\n      console.log(\"Passkey failed, falling back to password\");\n    }\n  }\n\n  \u002F\u002F Fallback to password\n  showPasswordLogin();\n}\n",[189,2935,2936,2947,2952,2966,2973,2984,2995,3009,3013,3017,3021,3026,3033],{"__ignoreMap":187},[192,2937,2938,2940,2942,2945],{"class":194,"line":195},[192,2939,206],{"class":205},[192,2941,209],{"class":205},[192,2943,2944],{"class":212}," authenticate",[192,2946,736],{"class":216},[192,2948,2949],{"class":194,"line":202},[192,2950,2951],{"class":198},"  \u002F\u002F Try passkey first\n",[192,2953,2954,2956,2958,2961,2963],{"class":194,"line":233},[192,2955,1015],{"class":205},[192,2957,1114],{"class":216},[192,2959,2960],{"class":205},"await",[192,2962,1847],{"class":212},[192,2964,2965],{"class":216},"()) {\n",[192,2967,2968,2971],{"class":194,"line":268},[192,2969,2970],{"class":205},"    try",[192,2972,1924],{"class":216},[192,2974,2975,2978,2980,2982],{"class":194,"line":275},[192,2976,2977],{"class":205},"      return",[192,2979,291],{"class":205},[192,2981,733],{"class":212},[192,2983,1896],{"class":216},[192,2985,2986,2989,2992],{"class":194,"line":281},[192,2987,2988],{"class":216},"    } ",[192,2990,2991],{"class":205},"catch",[192,2993,2994],{"class":216}," (error) {\n",[192,2996,2997,3000,3002,3004,3007],{"class":194,"line":306},[192,2998,2999],{"class":216},"      console.",[192,3001,1026],{"class":212},[192,3003,217],{"class":216},[192,3005,3006],{"class":299},"\"Passkey failed, falling back to password\"",[192,3008,1034],{"class":216},[192,3010,3011],{"class":194,"line":318},[192,3012,597],{"class":216},[192,3014,3015],{"class":194,"line":336},[192,3016,1039],{"class":216},[192,3018,3019],{"class":194,"line":354},[192,3020,272],{"emptyLinePlaceholder":271},[192,3022,3023],{"class":194,"line":380},[192,3024,3025],{"class":198},"  \u002F\u002F Fallback to password\n",[192,3027,3028,3031],{"class":194,"line":385},[192,3029,3030],{"class":212},"  showPasswordLogin",[192,3032,1896],{"class":216},[192,3034,3035],{"class":194,"line":391},[192,3036,715],{"class":216},[15,3038,3039],{},"Common fallback methods:",[3041,3042,3043,3049,3054,3060],"ol",{},[40,3044,3045,3048],{},[32,3046,3047],{},"Password + MFA"," (traditional)",[40,3050,3051],{},[32,3052,3053],{},"Magic link email",[40,3055,3056,3059],{},[32,3057,3058],{},"SMS verification"," (less secure)",[40,3061,3062],{},[32,3063,3064],{},"Backup codes",[10,3066,3068],{"id":3067},"summary","Summary",[15,3070,3071],{},"Passkeys represent the future of authentication:",[37,3073,3074,3080,3086],{},[40,3075,3076,3079],{},[32,3077,3078],{},"More secure",": Phishing-resistant, unique per site, private key never leaves device",[40,3081,3082,3085],{},[32,3083,3084],{},"Better UX",": No passwords to remember, instant biometric login",[40,3087,3088,3091],{},[32,3089,3090],{},"Industry backed",": Supported by Apple, Google, Microsoft, and the FIDO Alliance",[15,3093,3094],{},"While passwords won't disappear overnight, passkeys are quickly becoming the preferred authentication method for modern applications. Start implementing passkey support today to give your users the best possible authentication experience.",[10,3096,3098],{"id":3097},"related-tools","Related Tools",[37,3100,3101],{},[40,3102,3103,3104],{},"Generate strong passwords with our ",[3105,3106,3108],"a",{"href":3107},"\u002Ftools\u002Fpassword-generator","Password Generator",[3110,3111,3112],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .snhLl, html code.shiki .snhLl{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#85E89D;--shiki-dark-font-weight:bold}html pre.shiki code .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}",{"title":187,"searchDepth":202,"depth":202,"links":3114},[3115,3116,3119,3124,3129,3133,3137,3141,3142,3143],{"id":12,"depth":202,"text":13},{"id":26,"depth":202,"text":27,"children":3117},[3118],{"id":63,"depth":233,"text":64},{"id":154,"depth":202,"text":155,"children":3120},[3121,3122,3123],{"id":179,"depth":233,"text":180},{"id":718,"depth":233,"text":719},{"id":1046,"depth":233,"text":1047},{"id":1490,"depth":202,"text":1491,"children":3125},[3126,3127,3128],{"id":1494,"depth":233,"text":1495},{"id":1578,"depth":233,"text":1579},{"id":1649,"depth":233,"text":1650},{"id":1718,"depth":202,"text":1719,"children":3130},[3131,3132],{"id":1722,"depth":233,"text":1723},{"id":1834,"depth":233,"text":1835},{"id":1979,"depth":202,"text":1980,"children":3134},[3135,3136],{"id":1983,"depth":233,"text":1984},{"id":2613,"depth":233,"text":2614},{"id":2804,"depth":202,"text":2805,"children":3138},[3139,3140],{"id":2811,"depth":233,"text":2812},{"id":2841,"depth":233,"text":2842},{"id":2926,"depth":202,"text":2927},{"id":3067,"depth":202,"text":3068},{"id":3097,"depth":202,"text":3098},"2026-05-26","Learn how Passkeys work with WebAuthn and FIDO2 standards, compare them with traditional passwords, check browser support, and implement passkey authentication in your apps.","md",{"immutable":271},"\u002Fguides\u002Fpasskeys-future",{"title":5,"description":3145},"guides\u002Fpasskeys-future","bFHPJQw4oXC7RGE3o6Pf-MSDdYfOJ2giKUXo6JkidFI",1780401324231]