{"id":31507,"date":"2026-10-27T20:33:45","date_gmt":"2026-10-27T20:33:45","guid":{"rendered":"https:\/\/umang.pk\/2026\/10\/27\/webauthn%d8%8c-next-js%d8%8c-%d8%a7%d9%88%d8%b1-nestjs-%da%a9%d8%a7-%d8%a7%d8%b3%d8%aa%d8%b9%d9%85%d8%a7%d9%84-%da%a9%d8%b1%d8%aa%db%92-%db%81%d9%88%d8%a6%db%92-%d8%ae%d9%81%db%8c%db%81-%da%a9%d9%84\/"},"modified":"2026-10-27T20:33:46","modified_gmt":"2026-10-27T20:33:46","slug":"webauthn%d8%8c-next-js%d8%8c-%d8%a7%d9%88%d8%b1-nestjs-%da%a9%d8%a7-%d8%a7%d8%b3%d8%aa%d8%b9%d9%85%d8%a7%d9%84-%da%a9%d8%b1%d8%aa%db%92-%db%81%d9%88%d8%a6%db%92-%d8%ae%d9%81%db%8c%db%81-%da%a9%d9%84","status":"publish","type":"post","link":"https:\/\/umang.pk\/en_us\/2026\/10\/27\/webauthn%d8%8c-next-js%d8%8c-%d8%a7%d9%88%d8%b1-nestjs-%da%a9%d8%a7-%d8%a7%d8%b3%d8%aa%d8%b9%d9%85%d8%a7%d9%84-%da%a9%d8%b1%d8%aa%db%92-%db%81%d9%88%d8%a6%db%92-%d8%ae%d9%81%db%8c%db%81-%da%a9%d9%84\/","title":{"rendered":"WebAuthn\u060c Next.js\u060c \u0627\u0648\u0631 NestJS \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u06cc\u0633\u06d2 \u06a9\u06cc \u062c\u0627\u0626\u06d2\u06d4"},"content":{"rendered":"\n<div id=\"\">\n<p>\u067e\u0627\u0633 \u0648\u0631\u0688 \u0635\u0627\u0631\u0641\u06cc\u0646 \u0627\u0648\u0631 \u0633\u0631\u0648\u0633 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u0648\u06ba \u062f\u0648\u0646\u0648\u06ba \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0631\u062f \u0633\u0631 \u06c1\u06cc\u06ba\u06d4 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u0627\u06a9\u062b\u0631 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06cc\u0627\u062f \u0631\u06a9\u06be\u0646\u06d2 \u0645\u06cc\u06ba \u062f\u0634\u0648\u0627\u0631\u06cc \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0645\u062a\u0639\u062f\u062f \u0648\u06cc\u0628 \u0633\u0627\u0626\u0679\u0633 \u067e\u0631 \u0641\u0634\u0646\u06af \u0627\u0648\u0631 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06d2 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0627 \u0632\u06cc\u0627\u062f\u06c1 \u062e\u0637\u0631\u06c1 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0688\u0648\u06cc\u0644\u067e\u0631\u0632 \u06a9\u0648 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06c1\u06cc\u0634 \u06a9\u0631\u0646\u0627 \u06c1\u0648\u06ba \u06af\u06d2\u060c \u0627\u0646 \u067e\u0631 \u0646\u0645\u06a9 \u0688\u0627\u0644\u0646\u0627 \u06c1\u0648\u06af\u0627\u060c \u0644\u0627\u06af \u0627\u0646 \u06a9\u06cc \u06a9\u0648\u0634\u0634\u0648\u06ba \u06a9\u06cc \u0634\u0631\u062d \u06a9\u0648 \u0645\u062d\u062f\u0648\u062f \u06a9\u0631\u0646\u0627 \u06c1\u0648\u06af\u0627\u060c \u0627\u0648\u0631 &quot;\u0628\u06be\u0648\u0644\u06d2 \u06c1\u0648\u0626\u06d2 \u067e\u0627\u0633 \u0648\u0631\u0688&#8221; \u06a9\u0627 \u0628\u06c1\u0627\u0624 \u0628\u0646\u0627\u0646\u0627 \u06c1\u0648\u06af\u0627 \u062c\u0633\u06d2 \u06a9\u0648\u0626\u06cc \u0628\u06be\u06cc \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u0627 \u067e\u0633\u0646\u062f \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u062e\u0648\u0634 \u0642\u0633\u0645\u062a\u06cc \u0633\u06d2\u060c \u06a9\u0631\u067e\u0679\u0648\u06af\u0631\u0627\u0641\u06a9 \u06a9\u06cc\u0632 \u0627\u0646 \u0645\u06cc\u06ba \u0633\u06d2 \u0628\u06c1\u062a \u0633\u06d2 \u0645\u0633\u0627\u0626\u0644 \u06a9\u0648 \u062d\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u06d4 \u067e\u0627\u0633 \u0648\u0631\u0688 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u0622\u067e \u062f\u06cc\u06af\u0631 \u0622\u0644\u0627\u062a \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u06d2 \u0645\u062e\u062a\u0644\u0641 \u0637\u0631\u06cc\u0642\u0648\u06ba\u060c \u062c\u06cc\u0633\u06d2 \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679\u060c \u0686\u06c1\u0631\u06d2 \u06a9\u06cc \u0634\u0646\u0627\u062e\u062a\u060c \u0627\u0648\u0631 PIN \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0627\u067e\u0646\u06cc \u0634\u0646\u0627\u062e\u062a \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0646\u0646\u062f\u06c1 \u0622\u0644\u06c1 \u067e\u0631 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u062f\u06c1 \u0627\u06cc\u06a9 \u0627\u0646\u06a9\u0631\u067e\u0634\u0646 \u06a9\u0644\u06cc\u062f \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0686\u06cc\u0644\u0646\u062c \u067e\u0631 \u062f\u0633\u062a\u062e\u0637 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u06a9\u0628\u06be\u06cc \u06a9\u0633\u06cc \u0627\u0648\u0631 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u0634\u062a\u0631\u0627\u06a9 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06cc\u06c1 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0622\u067e \u06a9\u0648 \u062f\u06a9\u06be\u0627\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0627\u06cc\u0633\u06cc \u0627\u06cc\u067e \u06a9\u06cc\u0633\u06d2 \u0628\u0646\u0627\u0626\u06cc \u062c\u0627\u0626\u06d2 \u062c\u0648 \u0631\u0648\u0627\u06cc\u062a\u06cc \u067e\u0627\u0633 \u0648\u0631\u0688 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0646\u06c1 \u06a9\u0631\u06d2\u06d4 \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u0627\u06cc\u06a9 NestJS API \u06c1\u06d2 \u062c\u0648 PostgreSQL \u0645\u06cc\u06ba \u0635\u0627\u0631\u0641\u06cc\u0646 \u0627\u0648\u0631 \u0627\u0646 \u06a9\u06cc \u062e\u0641\u06cc\u06c1 \u0686\u0627\u0628\u06cc\u0627\u06ba \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u0627\u06cc\u06a9 Next.js \u0627\u06cc\u067e \u06c1\u06d2 \u062c\u06c1\u0627\u06ba \u0635\u0627\u0631\u0641\u06cc\u0646 \u0633\u0627\u0626\u0646 \u0627\u067e \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0635\u0631\u0641 \u0627\u067e\u0646\u06d2 \u0627\u06cc \u0645\u06cc\u0644 \u0627\u06cc\u0688\u0631\u06cc\u0633 \u0627\u0648\u0631 \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0644\u0627\u06af \u0627\u0646 \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>SimpleWebAuthn\u060c \u0627\u06cc\u06a9 \u0627\u0686\u06be\u06cc \u0637\u0631\u062d \u0633\u06d2 \u0628\u0631\u0642\u0631\u0627\u0631 \u0631\u06a9\u06be\u0646\u06d2 \u0648\u0627\u0644\u06cc TypeScript \u0644\u0627\u0626\u0628\u0631\u06cc\u0631\u06cc \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 WebAuthn \u0627\u0646\u06a9\u0631\u067e\u0634\u0646 \u0627\u0648\u0631 \u0688\u06cc\u0679\u0627 \u067e\u0627\u0631\u0633\u0646\u06af \u0633\u06d2 \u0645\u062a\u0639\u0644\u0642 \u06a9\u0627\u0645\u0648\u06ba \u06a9\u0648 \u0622\u0633\u0627\u0646 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u0633 \u0645\u0636\u0645\u0648\u0646 \u06a9\u06d2 \u0627\u062e\u062a\u062a\u0627\u0645 \u062a\u06a9\u060c \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u0648\u06c1 \u0686\u06cc\u0632 \u06c1\u0648 \u06af\u06cc \u062c\u0648 \u0622\u067e \u06a9\u0648 \u0627\u067e\u0646\u06cc \u0648\u06cc\u0628 \u0633\u0627\u0626\u0679 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0631\u067e\u0679\u0648\u06af\u0631\u0627\u0641\u06a9 \u06a9\u0644\u06cc\u062f \u06a9\u06d2 \u0627\u0646\u062f\u0631\u0627\u062c \u0627\u0648\u0631 \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0648 \u0644\u0627\u06af\u0648 \u06a9\u0631\u0646\u06d2 \u0627\u0648\u0631 \u0627\u067e\u0646\u06d2 \u0633\u0631\u0648\u0631 \u067e\u0631 \u06a9\u0631\u067e\u0679\u0648\u06af\u0631\u0627\u0641\u06a9 \u06a9\u06cc\u0632 \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u062f\u0631\u0633\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0631\u06a9\u0627\u0631 \u06c1\u06d2\u06d4 \u0622\u067e \u0627\u067e\u0646\u06cc \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u0648\u06ba \u0633\u06d2 \u0645\u062a\u0639\u0644\u0642 \u0645\u0645\u06a9\u0646\u06c1 \u062e\u0637\u0631\u0627\u062a \u0627\u0648\u0631 \u0645\u0633\u0627\u0626\u0644 \u0633\u06d2 \u0628\u0686\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0628\u06be\u06cc \u062c\u0627\u0646 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0627\u0642\u062f\u0627\u0645\u0627\u062a \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0648 \u0622\u067e \u06a9\u06d2 \u0627\u06cc\u067e\u0633 \u06cc\u0627 \u0635\u0627\u0631\u0641 \u0627\u06a9\u0627\u0624\u0646\u0679\u0633 \u06a9\u0648 \u0645\u062a\u0627\u062b\u0631 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0622\u067e GitHub \u067e\u0631 \u0645\u06a9\u0645\u0644 \u0633\u0648\u0631\u0633 \u06a9\u0648\u0688 \u062a\u0644\u0627\u0634 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-table-of-contents\">\u0627\u0646\u0688\u06cc\u06a9\u0633<\/h2>\n<p>\u06a9\u0648\u0688 \u06a9\u06cc \u0627\u06cc\u06a9 \u0644\u0627\u0626\u0646 \u0644\u06a9\u06be\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u0622\u067e \u06a9\u0648 \u0648\u0627\u0636\u062d \u0637\u0648\u0631 \u067e\u0631 \u0627\u0633 \u0628\u0627\u062a \u06a9\u06cc \u0648\u0636\u0627\u062d\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2 \u06a9\u06c1 \u0622\u067e \u06a9\u06cc\u0627 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u067e\u0627\u0633 \u0648\u0631\u0688 \u067e\u0631 \u0645\u0628\u0646\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0626\u06cc \u062f\u06c1\u0627\u0626\u06cc\u0648\u06ba \u0633\u06d2 \u0644\u0627\u06af \u0627\u0646 \u06a9\u0627 \u0688\u06cc\u0641\u0627\u0644\u0679 \u0637\u0631\u06cc\u0642\u06c1 \u0631\u06c1\u0627 \u06c1\u06d2\u06d4 \u0627\u0648\u0631 \u06cc\u06c1 \u06a9\u0627\u0631\u0622\u0645\u062f \u062b\u0627\u0628\u062a \u06c1\u0648\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0645\u0639\u06cc\u0627\u0631 \u0628\u0646 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4 \u0644\u06cc\u06a9\u0646 \u062c\u0633 \u0645\u0627\u0688\u0644 \u067e\u0631 \u06cc\u06c1 \u0627\u0646\u062d\u0635\u0627\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 (<em>\u0627\u06cc\u06a9 \u0631\u0627\u0632 \u062c\u0633\u06d2 \u0627\u0646\u0633\u0627\u0646 \u06a9\u0648 \u062d\u0641\u0638 \u06a9\u0631\u0646\u0627\u060c \u062f\u0627\u062e\u0644 \u06a9\u0631\u0646\u0627 \u0627\u0648\u0631 \u0627\u067e\u0646\u06d2 \u0644\u06cc\u06d2 \u0631\u06a9\u06be\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/em>) \u06a9\u06cc \u0627\u06c1\u0645 \u062d\u062f\u0648\u062f \u06c1\u06cc\u06ba\u06d4 \u062c\u06cc\u0633\u0627 \u06a9\u06c1 \u06c1\u0645 \u062f\u06cc\u06a9\u06be\u06cc\u06ba \u06af\u06d2\u060c \u0627\u0633 \u0645\u0627\u0688\u0644 \u06a9\u06d2 \u06c1\u0631 \u067e\u06c1\u0644\u0648 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0645\u0633\u0627\u0626\u0644 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-1-phishing-attacks\">1. \u0641\u0634\u0646\u06af \u062d\u0645\u0644\u06c1<\/h3>\n<p>\u0622\u067e \u06a9\u0627 \u067e\u0627\u0633 \u0648\u0631\u0688 \u062c\u06c1\u0627\u06ba \u0628\u06be\u06cc \u0622\u067e \u0627\u0633\u06d2 \u062f\u0627\u062e\u0644 \u06a9\u0631\u06cc\u06ba \u06af\u06d2 \u06a9\u0627\u0645 \u06a9\u0631\u06d2 \u06af\u0627\u06d4 \u0627\u06af\u0631 \u06a9\u0648\u0626\u06cc \u062d\u0645\u0644\u06c1 \u0622\u0648\u0631 \u0622\u067e \u06a9\u06d2 \u0628\u06cc\u0646\u06a9 \u06a9\u06d2 \u0644\u0627\u06af \u0627\u0646 \u0635\u0641\u062d\u06c1 \u0633\u06d2 \u0645\u0644\u062a\u0627 \u062c\u0644\u062a\u0627 \u0635\u0641\u062d\u06c1 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u067e\u0627\u0633 \u0648\u0631\u0688 \u0627\u0633 \u0635\u0641\u062d\u06c1 \u067e\u0631 \u0628\u06be\u06cc \u0648\u06c1\u06cc \u06a9\u0627\u0645 \u06a9\u0631\u06d2 \u06af\u0627\u06d4 \u0635\u0631\u0641 \u0627\u06cc\u06a9 \u06c1\u06cc \u0686\u06cc\u0632 \u062c\u0648 \u0622\u067e \u06a9\u06d2 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u0633\u0645\u062c\u06be\u0648\u062a\u06c1 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u0628\u0686\u0627\u0626\u06d2 \u06af\u06cc \u0627\u06af\u0631 \u0648\u06c1 \u062f\u06cc\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 URL \u062a\u06be\u0648\u0691\u0627 \u0633\u0627 \u0639\u062c\u06cc\u0628 \u0644\u06af\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u067e\u0648\u0686\u06be\u0646\u06d2 \u06a9\u0648 \u0628\u06c1\u062a \u06a9\u0686\u06be \u06c1\u06d2\u06d4 \u0641\u0634\u0646\u06af \u0635\u0641\u062d\u0627\u062a \u0627\u06a9\u062b\u0631 \u067e\u06a9\u0633\u0644 \u067e\u0631\u0641\u06cc\u06a9\u0679 \u06a9\u06d2 \u0628\u06c1\u062a \u0642\u0631\u06cc\u0628 \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0641\u0648\u0631\u06cc \u0627\u06cc \u0645\u06cc\u0644\u0632 \u06cc\u0627 \u0679\u06cc\u06a9\u0633\u0679 \u067e\u06cc\u063a\u0627\u0645\u0627\u062a \u06a9\u06cc \u0634\u06a9\u0644 \u0645\u06cc\u06ba \u0622\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0627\u06a9\u06c1 \u0622\u067e \u06a9\u0648 \u0641\u0648\u0631\u06cc \u0637\u0648\u0631 \u067e\u0631 \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0688\u06cc\u0632\u0627\u0626\u0646 \u06a9\u06cc\u0627 \u062c\u0627\u0626\u06d2\u06d4 \u06cc\u06c1\u0627\u06ba \u062a\u06a9 \u06a9\u06c1 \u0633\u0628 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0645\u062d\u062a\u0627\u0637 \u0627\u0648\u0631 \u062a\u06a9\u0646\u06cc\u06a9\u06cc \u0630\u06c1\u0646 \u0631\u06a9\u06be\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u0628\u06be\u06cc \u0628\u06d2 \u0648\u0642\u0648\u0641 \u0628\u0646\u0627\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06cc\u0633 \u0627\u06cc\u0645 \u0627\u06cc\u0633 \u06cc\u0627 \u062a\u0648\u062b\u06cc\u0642\u06cc \u0627\u06cc\u067e \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0628\u06be\u06cc\u062c\u06d2 \u062c\u0627\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0627\u06cc\u06a9 \u0648\u0642\u062a\u06cc \u067e\u0627\u0633 \u0648\u0631\u0688 \u06cc\u0642\u06cc\u0646\u0627\u064b \u0645\u0641\u06cc\u062f \u06c1\u06cc\u06ba\u060c \u0644\u06cc\u06a9\u0646 \u06cc\u06c1 \u0644\u0648\u06af\u0648\u06ba \u06a9\u0648 \u062c\u0639\u0644\u06cc \u0635\u0641\u062d\u0627\u062a \u067e\u0631 \u0627\u067e\u0646\u0627 \u067e\u0627\u0633 \u0648\u0631\u0688 \u062f\u0627\u062e\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0628\u06be\u06cc \u062f\u06be\u0648\u06a9\u06c1 \u062f\u06d2 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-2-password-reuse\">2. \u067e\u0627\u0633 \u0648\u0631\u0688 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u0632\u06cc\u0627\u062f\u06c1 \u062a\u0631 \u0644\u0648\u06af\u0648\u06ba \u06a9\u06d2 \u067e\u0627\u0633 \u062f\u0631\u062c\u0646\u0648\u06ba\u060c \u0627\u06af\u0631 \u0633\u06cc\u0646\u06a9\u0691\u0648\u06ba \u0646\u06c1\u06cc\u06ba\u060c \u062a\u0648 \u0622\u0646 \u0644\u0627\u0626\u0646 \u0627\u06a9\u0627\u0624\u0646\u0679\u0633 \u06c1\u06cc\u06ba\u06d4 \u0686\u0648\u0646\u06a9\u06c1 \u0622\u067e \u06c1\u0631 \u0627\u06cc\u06a9 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0645\u0646\u0641\u0631\u062f\u060c \u0645\u0636\u0628\u0648\u0637 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06cc\u0627\u062f \u0646\u06c1\u06cc\u06ba \u0631\u06a9\u06be \u0633\u06a9\u062a\u06d2\u060c \u0627\u0633 \u0644\u06cc\u06d2 \u0622\u067e \u0628\u0648\u0631\u0688 \u0645\u06cc\u06ba \u06c1\u0631 \u0648\u0642\u062a \u0648\u06c1\u06cc \u0686\u0646\u062f \u067e\u0627\u0633 \u0648\u0631\u0688 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u0631\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u062d\u0645\u0644\u06c1 \u0622\u0648\u0631 \u06cc\u06c1 \u062c\u0627\u0646\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0627\u06af\u0631 \u0627\u06cc\u06a9 \u0633\u0627\u0626\u0679 \u0633\u06d2 \u0633\u0645\u062c\u06be\u0648\u062a\u06c1 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u06cc\u06c1 \u0633\u0645\u062c\u06be\u0648\u062a\u06c1 \u0634\u062f\u06c1 \u0627\u06cc \u0645\u06cc\u0644 \u0627\u0648\u0631 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06d2 \u062c\u0648\u0691\u06d2 \u0644\u06cc\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u062e\u0648\u062f \u0628\u062e\u0648\u062f \u0627\u0646\u06c1\u06cc\u06ba \u062f\u0648\u0633\u0631\u06cc \u0633\u0627\u0626\u0679\u0648\u06ba \u067e\u0631 \u0622\u0632\u0645\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u06a9\u06c1 <strong>\u0627\u0633\u0646\u0627\u062f \u0628\u06be\u0631\u0646\u0627<\/strong>. \u0627\u06cc\u06a9 \u0686\u06be\u0648\u0679\u06d2\u060c \u0637\u0648\u06cc\u0644 \u0639\u0631\u0635\u06d2 \u0633\u06d2 \u0628\u06be\u0648\u0644\u06d2 \u06c1\u0648\u0626\u06d2 \u0641\u0648\u0631\u0645 \u067e\u0631 \u062e\u0644\u0627\u0641 \u0648\u0631\u0632\u06cc \u06a9\u0633\u06cc \u06a9\u0648 \u0622\u067e \u06a9\u06d2 \u0627\u06cc \u0645\u06cc\u0644 \u06cc\u0627 \u0628\u06cc\u0646\u06a9 \u0627\u06a9\u0627\u0624\u0646\u0679 \u062a\u06a9 \u0631\u0633\u0627\u0626\u06cc \u062f\u06d2 \u0633\u06a9\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-3-data-breaches\">3. \u0688\u06cc\u0679\u0627 \u06a9\u06cc \u062e\u0644\u0627\u0641 \u0648\u0631\u0632\u06cc<\/h3>\n<p>\u06a9\u0648\u0626\u06cc \u0628\u06be\u06cc \u0633\u0627\u0626\u0679 \u062c\u0648 \u067e\u0627\u0633 \u0648\u0631\u0688\u0632 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06d2 \u0627\u0633\u06d2 \u0627\u06cc\u0633\u06cc \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u06a9\u0648 \u0630\u062e\u06cc\u0631\u06c1 \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2 \u062c\u0648 \u067e\u0627\u0633 \u0648\u0631\u0688\u0632 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc \u062c\u0627 \u0633\u06a9\u06d2\u06d4 \u0645\u062b\u0627\u0644\u06cc \u0635\u0648\u0631\u062a \u062d\u0627\u0644 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u06a9\u0633\u06cc \u0633\u0627\u0626\u0679 \u06a9\u0648 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0646\u0645\u06a9\u06cc\u0646 \u06c1\u06cc\u0634 \u06a9\u0648 \u0627\u0633\u0679\u0648\u0631 \u06a9\u06cc\u0627 \u062c\u0627\u0626\u06d2\u06d4 \u062a\u0627\u06c1\u0645\u060c \u062a\u0645\u0627\u0645 \u0633\u0627\u0626\u0679\u06cc\u06ba \u06cc\u06c1 \u0627\u0686\u06be\u06cc \u0637\u0631\u062d \u0633\u06d2 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u062c\u0628 \u062d\u0645\u0644\u06c1 \u0622\u0648\u0631 \u06a9\u0648 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06cc \u06a9\u0627\u067e\u06cc \u0645\u0644 \u062c\u0627\u062a\u06cc \u06c1\u06d2 \u062a\u0648 \u06a9\u0645\u0632\u0648\u0631 \u067e\u0627\u0633 \u0648\u0631\u0688\u0632 \u06a9\u06cc \u06c1\u06cc\u0634 \u06a9\u0648 \u0622\u0641 \u0644\u0627\u0626\u0646 \u0688\u06a9\u0631\u067e\u0679 \u06a9\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06cc\u06c1 \u0648\u0627\u0636\u062d \u0637\u0648\u0631 \u067e\u0631 \u0688\u0648\u06cc\u0644\u067e\u0631\u0632 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0628\u0648\u062c\u06be \u06c1\u06d2\u06d4 \u0622\u067e \u06a9\u0648 \u0635\u062d\u06cc\u062d \u06c1\u06cc\u0634\u0646\u06af \u0627\u0644\u06af\u0648\u0631\u062a\u06be\u0645 \u06a9\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0631\u0646\u06d2\u060c \u0627\u0633\u06d2 \u0679\u06cc\u0648\u0646 \u06a9\u0631\u0646\u06d2\u060c \u0627\u0648\u0631 \u0627\u067e\u0646\u06d2 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06cc \u062d\u0641\u0627\u0638\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2 \u062c\u0628\u06a9\u06c1 \u0627\u0628 \u0628\u06be\u06cc \u0622\u067e \u06a9\u06d2 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0622\u0641\u062a \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0644\u06cc\u06a9 \u06c1\u0648\u0646\u06d2 \u06a9\u0627 \u0639\u0644\u0627\u062c \u06a9\u0631\u0646\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-4-lack-of-privacy\">4. \u0631\u0627\u0632\u062f\u0627\u0631\u06cc \u06a9\u06cc \u06a9\u0645\u06cc<\/h3>\n<p>\u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06d2 \u0633\u0627\u062a\u06be\u060c \u0635\u0627\u0631\u0641\u06cc\u0646 \u06c1\u0631 \u0627\u0633 \u0633\u0627\u0626\u0679 \u067e\u0631 \u0627\u06cc\u06a9 \u0645\u0634\u062a\u0631\u06a9\u06c1 \u0631\u0627\u0632 \u0645\u0646\u062a\u0642\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0633 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0648\u06c1 \u0633\u0627\u0626\u0646 \u0627\u067e \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0627\u0646\u06c1\u06cc\u06ba \u0633\u0627\u0626\u0679 \u06a9\u06cc \u062d\u0641\u0627\u0638\u062a \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0633 \u067e\u0631 \u0628\u06be\u0631\u0648\u0633\u06c1 \u06a9\u0631\u0646\u0627 \u06c1\u0648\u06af\u0627\u060c \u0627\u0648\u0631 \u0627\u0646 \u06a9\u0627 \u0627\u0633 \u067e\u0631 \u06a9\u0648\u0626\u06cc \u06a9\u0646\u0679\u0631\u0648\u0644 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2 \u06a9\u06c1 \u0627\u06af\u0631 \u0633\u0627\u0626\u0679 \u06a9\u06cc \u062e\u0644\u0627\u0641 \u0648\u0631\u0632\u06cc \u06a9\u06cc \u062c\u0627\u062a\u06cc \u06c1\u06d2 \u062a\u0648 \u06a9\u06cc\u0627 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0686\u0648\u0646\u06a9\u06c1 \u0644\u0648\u06af \u0627\u06cc\u06a9 \u06c1\u06cc \u0627\u06cc \u0645\u06cc\u0644 \u0627\u0648\u0631 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06d2 \u0627\u0645\u062a\u0632\u0627\u062c \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0633 \u0644\u06cc\u06d2 \u0644\u06cc\u06a9 \u0634\u062f\u06c1 \u0627\u0633\u0646\u0627\u062f \u06a9\u0648 \u062e\u0644\u0627\u0641 \u0648\u0631\u0632\u06cc \u0645\u06cc\u06ba \u0645\u0644\u0627\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 \u0646\u062a\u06cc\u062c\u06d2 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631\u060c \u062a\u0645\u0627\u0645 \u0633\u0631\u0648\u0633\u0632 \u0645\u06cc\u06ba \u0627\u06a9\u0627\u0624\u0646\u0679\u0633 \u06a9\u0648 \u062c\u0648\u0691\u0646\u0627 \u0627\u0648\u0631 \u0627\u0641\u0631\u0627\u062f \u06a9\u06d2 \u0622\u0646 \u0644\u0627\u0626\u0646 \u0631\u0648\u06cc\u06d2 \u06a9\u06d2 \u067e\u0631\u0648\u0641\u0627\u0626\u0644 \u0628\u0646\u0627\u0646\u0627 \u0628\u06c1\u062a \u0622\u0633\u0627\u0646 \u06c1\u0648 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-5-credential-fatigue\">5. \u0633\u0646\u062f\u06cc \u062a\u06be\u06a9\u0627\u0648\u0679<\/h3>\n<p>\u067e\u06be\u0631 \u0631\u0648\u0632\u0645\u0631\u06c1 \u06a9\u06cc \u0645\u0627\u06cc\u0648\u0633\u06cc\u0627\u06ba \u06c1\u06cc\u06ba\u06d4 \u0622\u067e \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06cc \u067e\u0627\u0644\u06cc\u0633\u06cc\u0648\u06ba \u06a9\u0648 \u0645\u0633\u0644\u0633\u0644 \u062c\u0648\u0691 \u0631\u06c1\u06d2 \u06c1\u06cc\u06ba (1 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0639\u0644\u0627\u0645\u062a \u0646\u06c1\u06cc\u06ba\u060c 16 \u062d\u0631\u0648\u0641 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0646\u06c1\u06cc\u06ba\u060c \u0648\u063a\u06cc\u0631\u06c1)\u060c \u06c1\u0631 \u0686\u0646\u062f \u0645\u0627\u06c1 \u0628\u0639\u062f \u06c1\u0627\u0631\u0688 \u0631\u06cc \u0633\u06cc\u0679\u060c \u0633\u06cc\u06a9\u06cc\u0648\u0631\u0679\u06cc \u0633\u0648\u0627\u0644\u0627\u062a\u060c \u062a\u0635\u062f\u06cc\u0642\u06cc \u06a9\u0648\u0688\u0632 \u0648\u063a\u06cc\u0631\u06c1\u06d4 \u0641\u06c1\u0631\u0633\u062a \u062c\u0627\u0631\u06cc \u06c1\u06d2\u06d4 \u0622\u067e \u062c\u0648 \u0628\u06be\u06cc \u0646\u06cc\u0627 \u0627\u06a9\u0627\u0624\u0646\u0679 \u0628\u0646\u0627\u0626\u06cc\u06ba \u06af\u06d2 \u0648\u06c1 \u0627\u0633 \u0645\u06cc\u06ba \u0634\u0627\u0645\u0644 \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u06af\u0627\u06d4<\/p>\n<p>\u06cc\u06c1 \u062a\u06be\u06a9\u0627\u0648\u0679 \u062a\u06cc\u0632\u06cc \u0633\u06d2 \u0627\u06cc\u0633\u06d2 \u0631\u0648\u06cc\u0648\u06ba \u06a9\u06cc \u0637\u0631\u0641 \u0644\u06d2 \u062c\u0627\u062a\u06cc \u06c1\u06d2 \u062c\u0648 \u0644\u0648\u06af\u0648\u06ba \u06a9\u0648 \u0627\u067e\u0646\u06d2 \u067e\u0627\u0633 \u0648\u0631\u0688\u0632 \u06a9\u06d2 \u0628\u0627\u0631\u06d2 \u0645\u06cc\u06ba \u0628\u06c1\u062a \u0632\u06cc\u0627\u062f\u06c1 \u063a\u06cc\u0631 \u0645\u062d\u0641\u0648\u0638 \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062c\u06cc\u0633\u06d2 \u06a9\u06c1 \u0645\u062e\u062a\u0635\u0631 \u067e\u0627\u0633 \u0648\u0631\u0688\u060c \u0627\u06cc\u06a9 \u06c1\u06cc \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06cc \u0686\u06be\u0648\u0679\u06cc \u062a\u0628\u062f\u06cc\u0644\u06cc\u0627\u06ba\u060c \u0627\u0648\u0631 \u0686\u067e\u0686\u067e\u0627 \u0646\u0648\u0679\u0648\u06ba \u067e\u0631 \u0644\u06a9\u06be\u06d2 \u06af\u0626\u06d2 \u067e\u0627\u0633 \u0648\u0631\u0688\u06d4 \u06a9\u0627\u0631\u0648\u0628\u0627\u0631\u06cc \u0627\u062e\u0631\u0627\u062c\u0627\u062a \u0628\u06be\u06cc \u06c1\u06cc\u06ba\u06d4 \u0644\u0648\u06af \u0633\u0627\u0626\u0646 \u0627\u067e \u06a9\u06d2 \u0639\u0645\u0644 \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646 \u0686\u0644\u06d2 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u067e\u0646\u06d2 \u0627\u06a9\u0627\u0624\u0646\u0679 \u0633\u06d2 \u0644\u0627\u06a9 \u0622\u0624\u0679 \u06c1\u0648 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u067e\u06be\u0631 \u0627\u067e\u0646\u0627 \u0628\u06be\u0648\u0644\u0627 \u06c1\u0648\u0627 \u067e\u0627\u0633 \u0648\u0631\u0688 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0633\u067e\u0648\u0631\u0679 \u0633\u06d2 \u0631\u0627\u0628\u0637\u06c1 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<p>\u067e\u0627\u0633\u06a9\u06cc \u0645\u0634\u062a\u0631\u06a9\u06c1 \u0631\u0627\u0632 \u06a9\u0648 \u0645\u06a9\u0645\u0644 \u0637\u0648\u0631 \u067e\u0631 \u06c1\u0679\u0627 \u062f\u06cc\u062a\u06cc \u06c1\u06d2\u06d4 passkeys.dev \u0627\u0633\u06d2 \u0628\u062f\u06cc\u06c1\u06cc\u060c \u062e\u0648\u062f \u0628\u062e\u0648\u062f \u0645\u0646\u0641\u0631\u062f\u060c \u0627\u0648\u0631 \u062e\u0644\u0627\u0641 \u0648\u0631\u0632\u06cc \u0627\u0648\u0631 \u0627\u06cc\u0646\u0679\u06cc \u0641\u0634\u0646\u06af \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0628\u06cc\u0627\u0646 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06c1\u0631 \u0645\u0633\u0626\u0644\u06d2 \u06a9\u06cc \u062a\u0641\u0635\u06cc\u0644 \u062f\u0631\u062c \u0630\u06cc\u0644 \u06c1\u06d2:<\/p>\n<table>\n<thead>\n<tr>\n<th>\u0645\u0633\u0626\u0644\u06c1<\/th>\n<th>\u067e\u0627\u0633\u06a9\u06cc \u0622\u067e \u06a9\u06d2 \u0645\u0633\u0626\u0644\u06d2 \u06a9\u0648 \u06a9\u06cc\u0633\u06d2 \u062d\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\u0641\u0634\u0646\u06af \u062d\u0645\u0644\u06c1<\/td>\n<td>\u0628\u0631\u0627\u0624\u0632\u0631\u0632 \u0627\u0648\u0631 \u0622\u067e\u0631\u06cc\u0679\u0646\u06af \u0633\u0633\u0679\u0645 \u0635\u0631\u0641 \u0627\u0633 \u0633\u0627\u0626\u0679 \u06a9\u06cc \u0627\u0646\u06a9\u0631\u067e\u0634\u0646 \u06a9\u06cc\u0632 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0633 \u0646\u06d2 \u0627\u0646\u06c1\u06cc\u06ba \u0628\u0646\u0627\u06cc\u0627 \u06c1\u06d2\u06d4 \u062c\u0639\u0644\u06cc \u0688\u0648\u0645\u06cc\u0646\u0632\u060c \u0686\u0627\u06c1\u06d2 \u0648\u06c1 \u06a9\u062a\u0646\u06d2 \u06c1\u06cc \u0642\u0627\u0626\u0644 \u06a9\u06cc\u0648\u06ba \u0646\u06c1 \u06c1\u0648\u06ba\u060c \u0622\u067e \u06a9\u0648 \u06a9\u06c1\u06cc\u06ba \u0646\u06c1\u06cc\u06ba \u0645\u0644\u06d2 \u06af\u0627\u06d4<\/td>\n<\/tr>\n<tr>\n<td>\u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u0627 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644<\/td>\n<td>\u062a\u0645\u0627\u0645 \u0627\u0646\u06a9\u0631\u067e\u0634\u0646 \u06a9\u06cc\u0632 \u0633\u0627\u0626\u0679 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0628\u0646\u0627\u0626\u06d2 \u06af\u0626\u06d2 \u0646\u0626\u06d2 \u06a9\u0644\u06cc\u062f\u06cc \u062c\u0648\u0691\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0633 \u0644\u06cc\u06d2 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0686\u06be \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4<\/td>\n<\/tr>\n<tr>\n<td>\u0688\u06cc\u0679\u0627 \u06a9\u06cc \u062e\u0644\u0627\u0641 \u0648\u0631\u0632\u06cc<\/td>\n<td>\u0633\u0631\u0648\u0631 \u0635\u0631\u0641 \u0639\u0648\u0627\u0645\u06cc \u06a9\u0644\u06cc\u062f \u06a9\u0648 \u0630\u062e\u06cc\u0631\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u06cc\u06a9 \u0644\u06cc\u06a9 \u0634\u062f\u06c1 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u062d\u0645\u0644\u06c1 \u0622\u0648\u0631\u0648\u06ba \u06a9\u0648 \u0644\u0627\u06af \u0627\u0646 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0686\u06be \u0628\u06be\u06cc \u0641\u0631\u0627\u06c1\u0645 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/td>\n<\/tr>\n<tr>\n<td>\u0631\u0627\u0632\u062f\u0627\u0631\u06cc \u06a9\u06cc \u06a9\u0645\u06cc<\/td>\n<td>\u0633\u0627\u0626\u0679 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u0634\u062a\u0631\u0627\u06a9 \u06a9\u0631\u062f\u06c1 \u06a9\u0648\u0626\u06cc \u0631\u0627\u0632 \u0646\u06c1\u06cc\u06ba \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0686\u0627\u0628\u06cc\u0627\u06ba \u0633\u0627\u0626\u0679 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0645\u062e\u0635\u0648\u0635 \u06c1\u06cc\u06ba\u06d4 \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679 \u0627\u0648\u0631 \u0686\u06c1\u0631\u06d2 \u06a9\u0627 \u0688\u06cc\u0679\u0627 \u0688\u06cc\u0648\u0627\u0626\u0633 \u06a9\u06d2 \u0628\u0627\u06c1\u0631 \u0644\u06cc\u06a9 \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4<\/td>\n<\/tr>\n<tr>\n<td>\u0633\u0646\u062f\u06cc \u062a\u06be\u06a9\u0627\u0648\u0679<\/td>\n<td>\u0628\u0646\u0627\u0646\u06d2 \u06cc\u0627 \u06cc\u0627\u062f \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0686\u06be \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0635\u0627\u0631\u0641\u06cc\u0646 \u0648\u06c1\u06cc \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679\u060c \u0686\u06c1\u0631\u06c1 \u06cc\u0627 \u0627\u0633\u06a9\u0631\u06cc\u0646 \u0644\u0627\u06a9 \u0686\u06cc\u06a9 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0633\u06d2 \u0648\u06c1 \u062f\u0646 \u0645\u06cc\u06ba \u06a9\u0626\u06cc \u0628\u0627\u0631 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u0628\u0646\u06cc\u0627\u062f\u06cc \u062a\u0628\u062f\u06cc\u0644\u06cc \u0648\u06c1 \u06c1\u06d2 \u062c\u06c1\u0627\u06ba \u0627\u0639\u062a\u0645\u0627\u062f \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06cc \u062d\u0641\u0627\u0638\u062a \u0622\u067e \u06a9\u06cc \u062f\u06be\u0648\u06a9\u06c1 \u062f\u06c1\u06cc \u0648\u0627\u0644\u06cc \u0633\u0627\u0626\u0679\u0648\u06ba \u06a9\u0648 \u062a\u0644\u0627\u0634 \u06a9\u0631\u0646\u06d2 \u0627\u0648\u0631 \u0645\u0636\u0628\u0648\u0637 \u0627\u0633\u0646\u0627\u062f \u0645\u0646\u062a\u062e\u0628 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0635\u0644\u0627\u062d\u06cc\u062a \u067e\u0631 \u0645\u0646\u062d\u0635\u0631 \u06c1\u06d2\u06d4 \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u0648\u06ba \u06a9\u06d2 \u0633\u0627\u062a\u06be\u060c \u06cc\u06c1 \u0628\u0631\u0627\u0624\u0632\u0631 \u0627\u0648\u0631 \u0622\u067e\u0631\u06cc\u0679\u0646\u06af \u0633\u0633\u0679\u0645 \u06c1\u06d2 \u062c\u0648 \u0642\u0648\u0627\u0646\u06cc\u0646 \u06a9\u0648 \u0646\u0627\u0641\u0630 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u0635\u0631\u0641 \u0627\u067e\u0646\u06cc \u0634\u0646\u0627\u062e\u062a \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-prerequisites\">\u0634\u0631\u0637\u06cc\u06ba<\/h2>\n<p>\u0633\u0627\u062a\u06be \u0686\u0644\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2\u060c \u0622\u067e \u06a9\u0648 TypeScript \u0633\u06d2 \u0648\u0627\u0642\u0641 \u06c1\u0648\u0646\u0627 \u0627\u0648\u0631 React \u06a9\u0627 \u062a\u062c\u0631\u0628\u06c1 \u06c1\u0648\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4 \u0622\u067e \u06a9\u0648 NestJS \u06a9\u0648 \u0627\u0686\u06be\u06cc \u0637\u0631\u062d \u062c\u0627\u0646\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0627\u0633 \u0633\u06d2 \u06cc\u06c1 \u062c\u0627\u0646\u0646\u06d2 \u0645\u06cc\u06ba \u0645\u062f\u062f \u0645\u0644\u062a\u06cc \u06c1\u06d2 \u06a9\u06c1 \u06a9\u0646\u0679\u0631\u0648\u0644\u0631\u0632 \u0627\u0648\u0631 \u062e\u062f\u0645\u0627\u062a \u06a9\u06cc\u0627 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u062f\u0631\u062c \u0630\u06cc\u0644 \u0679\u0648\u0644\u0632 \u0628\u06be\u06cc \u0627\u0646\u0633\u0679\u0627\u0644 \u06c1\u0648\u0646\u06d2 \u0686\u0627\u06c1\u0626\u06cc\u06ba:<\/p>\n<ul>\n<li>Node.js \u0648\u0631\u0698\u0646 22 \u06cc\u0627 \u0627\u0633 \u0633\u06d2 \u0627\u0648\u067e\u0631<\/li>\n<li>\u067e\u0648\u0633\u0679\u06af\u0631\u06cc \u0627\u06cc\u0633 \u06a9\u06cc\u0648 \u0627\u06cc\u0644\u06d4 macOS \u067e\u0631\u060c Postgres.app \u0633\u0628 \u0633\u06d2 \u0622\u0633\u0627\u0646 \u0622\u067e\u0634\u0646 \u06c1\u06d2\u06d4 \u0627\u06af\u0631 \u0622\u067e \u06af\u0631\u0627\u0641\u06cc\u06a9\u0644 \u0679\u0648\u0644\u0632 \u06a9\u0648 \u062a\u0631\u062c\u06cc\u062d \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 pgAdmin \u0622\u0633\u0627\u0646 \u06c1\u06d2\u06d4<\/li>\n<li>\u0627\u06cc\u06a9 \u0627\u06cc\u0633\u0627 \u0622\u0644\u06c1 \u062c\u0648 \u06a9\u0631\u067e\u0679\u0648\u06af\u0631\u0627\u0641\u06a9 \u06a9\u06cc\u0632 \u06a9\u0648 \u0633\u067e\u0648\u0631\u0679 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u062a\u0642\u0631\u06cc\u0628\u0627 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u062c\u062f\u06cc\u062f \u0644\u06cc\u067e \u0679\u0627\u067e \u06cc\u0627 \u0641\u0648\u0646 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0628\u0634\u0645\u0648\u0644 \u0679\u0686 \u0622\u0626\u06cc \u0688\u06cc \u0648\u0627\u0644\u0627 \u0645\u06cc\u06a9\u060c \u0648\u0646\u0688\u0648\u0632 \u06c1\u06cc\u0644\u0648 \u0648\u0627\u0644\u0627 \u0648\u0646\u0688\u0648\u0632 \u067e\u06cc \u0633\u06cc\u060c \u0627\u0648\u0631 \u0627\u06cc\u0646\u0688\u0631\u0627\u0626\u06cc\u0688 \u0641\u0648\u0646 \u06cc\u0627 \u0622\u0626\u06cc \u0641\u0648\u0646\u06d4<\/li>\n<\/ul>\n<h2 id=\"heading-what-are-passkeys\">\u067e\u0627\u0633\u06a9\u06cc \u06a9\u06cc\u0627 \u06c1\u06d2\u061f<\/h2>\n<p>\u0627\u06cc\u06a9 \u067e\u0627\u0633\u06a9\u06cc \u0639\u0648\u0627\u0645\u06cc \u06a9\u0644\u06cc\u062f \u06a9\u06cc \u062e\u0641\u06cc\u06c1 \u0646\u06af\u0627\u0631\u06cc \u067e\u0631 \u0645\u0628\u0646\u06cc \u0627\u06cc\u06a9 \u0633\u0646\u062f \u06c1\u06d2\u06d4 \u06a9\u0644\u06cc\u062f \u0628\u0646\u0627\u0646\u06d2 \u0633\u06d2 \u0622\u067e \u06a9\u06d2 \u0622\u0644\u06d2 \u067e\u0631 \u06a9\u0644\u06cc\u062f\u06cc \u062c\u0648\u0691\u0627 \u0628\u0646\u062a\u0627 \u06c1\u06d2\u06d4 \u0622\u067e \u06a9\u06cc \u0646\u062c\u06cc \u06a9\u0644\u06cc\u062f\u06cc\u06ba \u0622\u067e \u06a9\u06d2 \u0622\u0644\u06d2 \u067e\u0631 \u0622\u067e \u06a9\u06d2 \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679\u060c \u0686\u06c1\u0631\u06d2\u060c \u06cc\u0627 \u0627\u0633\u06a9\u0631\u06cc\u0646 \u0644\u0627\u06a9 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0645\u0642\u0641\u0644 \u0631\u06c1\u062a\u06cc \u06c1\u06cc\u06ba\u06d4 \u0622\u067e \u06a9\u06cc \u0639\u0648\u0627\u0645\u06cc \u06a9\u0644\u06cc\u062f \u0648\u06cc\u0628 \u0633\u0627\u0626\u0679 \u067e\u0631 \u062c\u0627\u0626\u06d2 \u06af\u06cc \u0627\u0648\u0631 \u0622\u067e \u06a9\u06d2 \u0627\u06a9\u0627\u0624\u0646\u0679 \u06a9\u06d2 \u0622\u06af\u06d2 \u0645\u062d\u0641\u0648\u0638 \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u06af\u06cc\u06d4<\/p>\n<p>\u067e\u0627\u0633\u06a9\u06cc \u06a9\u0648 Web Authentication API (WebAuthn) \u067e\u0631 \u0628\u0646\u0627\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u060c \u06cc\u06c1 \u0627\u06cc\u06a9 W3C \u0645\u0639\u06cc\u0627\u0631 \u06c1\u06d2 \u062c\u0633\u06d2 \u062a\u0645\u0627\u0645 \u0628\u0691\u06d2 \u0628\u0631\u0627\u0624\u0632\u0631\u0632 \u0646\u06d2 \u0633\u067e\u0648\u0631\u0679 \u06a9\u06cc\u0627 \u06c1\u06d2\u06d4 &quot;\u067e\u0627\u0633\u06a9\u06cc&#8221; \u06a9\u06cc \u0627\u0635\u0637\u0644\u0627\u062d WebAuthn \u0627\u0633\u0646\u0627\u062f \u06a9\u06d2 \u0644\u06cc\u06d2 \u0635\u0646\u0639\u062a \u06a9\u06d2 \u0644\u06cc\u06d2 \u0645\u0648\u0632\u0648\u06ba \u0646\u0627\u0645 \u06c1\u06d2 \u062c\u0633\u06d2 \u062a\u0645\u0627\u0645 \u0622\u0644\u0627\u062a \u067e\u0631 \u06c1\u0645 \u0622\u06c1\u0646\u06af \u06a9\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u06af\u0631 \u0622\u067e \u0645\u0632\u06cc\u062f \u06af\u06c1\u0631\u0627\u0626\u06cc \u0633\u06d2 \u062a\u0639\u0627\u0631\u0641 \u0686\u0627\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 passkeys.dev \u0627\u06cc\u06a9 \u0628\u06c1\u062a\u0631\u06cc\u0646 \u0630\u0631\u06cc\u0639\u06c1 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06cc\u06a9 \u062a\u0641\u0635\u06cc\u0644 \u0627\u06a9\u062b\u0631 \u0688\u0648\u06cc\u0644\u067e\u0631\u0632 \u06a9\u0648 \u062d\u06cc\u0631\u0627\u0646 \u06a9\u0631 \u062f\u06cc\u062a\u06cc \u06c1\u06d2\u06d4 \u0627\u06cc\u067e \u0622\u067e \u06a9\u0648 \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679\u060c \u0686\u06c1\u0631\u06d2 \u06a9\u06cc \u0634\u0646\u0627\u062e\u062a\u060c \u06cc\u0627 \u067e\u0646 \u06a9\u0648\u0688 \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u0646\u06c1\u06cc\u06ba \u062f\u06cc\u062a\u06cc \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0622\u067e\u0631\u06cc\u0679\u0646\u06af \u0633\u0633\u0679\u0645 \u06c1\u06d2 \u062c\u0648 \u0622\u0644\u06c1 \u06a9\u06cc \u0635\u0644\u0627\u062d\u06cc\u062a\u0648\u06ba \u0627\u0648\u0631 \u0622\u067e \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628 \u06a9\u0631\u062f\u06c1 \u062a\u0631\u062a\u06cc\u0628\u0627\u062a \u06a9\u06cc \u0628\u0646\u06cc\u0627\u062f \u067e\u0631 \u0641\u06cc\u0635\u0644\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06cc\u06c1\u0627\u06ba \u0648\u06c1 \u06c1\u06d2 \u062c\u0648 \u0635\u0627\u0631\u0641\u06cc\u0646 \u0639\u0627\u0645 \u0637\u0648\u0631 \u067e\u0631 \u062f\u06cc\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba:<\/p>\n<table>\n<thead>\n<tr>\n<th>\u0622\u0644\u06c1<\/th>\n<th>\u0686\u06cc\u06a9 \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0637\u0631\u06cc\u0642\u06c1<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\u0633\u06a9\u0627\u0679\u0633 \u0645\u06cc\u0646<\/td>\n<td>ID \u06cc\u0627 \u0645\u06cc\u06a9 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u0648 \u0679\u0686 \u06a9\u0631\u06cc\u06ba\u06d4<\/td>\n<\/tr>\n<tr>\n<td>\u0622\u0626\u06cc \u0641\u0648\u0646 \u06cc\u0627 \u0622\u0626\u06cc \u067e\u06cc\u0688<\/td>\n<td>\u0641\u06cc\u0633 \u0622\u0626\u06cc \u0688\u06cc\u060c \u0679\u0686 \u0622\u0626\u06cc \u0688\u06cc\u060c \u06cc\u0627 \u067e\u0627\u0633 \u06a9\u0648\u0688<\/td>\n<\/tr>\n<tr>\n<td>\u0627\u06cc\u0646\u0688\u0631\u0648\u0626\u06cc\u0688<\/td>\n<td>\u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679\u060c \u0686\u06c1\u0631\u06d2 \u06a9\u06cc \u0634\u0646\u0627\u062e\u062a \u06a9\u0627 \u0627\u0646\u0644\u0627\u06a9\u060c \u067e\u0646\u060c \u067e\u06cc\u0679\u0631\u0646\u060c \u067e\u0627\u0633 \u0648\u0631\u0688<\/td>\n<\/tr>\n<tr>\n<td>\u06a9\u06be\u0691\u06a9\u06cc\u0627\u06ba<\/td>\n<td>\u0648\u0646\u0688\u0648\u0632 \u06c1\u06cc\u0644\u0648 \u0686\u06c1\u0631\u06c1\u060c \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679\u060c \u06cc\u0627 \u067e\u0646<\/td>\n<\/tr>\n<tr>\n<td>\u0627\u06cc\u06a9 \u0627\u0648\u0631 \u06a9\u0645\u067e\u06cc\u0648\u0679\u0631<\/td>\n<td>QR \u06a9\u0648\u0688 \u0627\u0633\u06a9\u06cc\u0646 \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u0627\u0633\u06d2 \u0627\u067e\u0646\u06d2 \u0641\u0648\u0646 \u067e\u0631 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u0633\u0631\u0648\u0631 \u06cc\u06c1 \u062f\u0639\u0648\u06cc\u0670 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u06a9\u0686\u06be \u0645\u0642\u0627\u0645\u06cc \u0686\u06cc\u06a9\u0646\u06af \u06c1\u0648\u0626\u06cc \u06c1\u06d2\u06d4 \u0622\u067e \u06a9\u0648 \u0627\u06cc\u06a9 \u0644\u0645\u062d\u06d2 \u0645\u06cc\u06ba \u067e\u062a\u06c1 \u0686\u0644 \u062c\u0627\u0626\u06d2 \u06af\u0627 \u06a9\u06c1 \u06a9\u06cc\u0633\u06d2\u06d4<\/p>\n<h2 id=\"heading-how-passkey-authentication-works\">\u06a9\u0631\u067e\u0679\u0648\u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u06cc\u0633\u06d2 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/h2>\n<p>\u0633\u0627\u0626\u0646 \u0627\u067e \u06a9\u0631\u0646\u0627 \u0627\u0648\u0631 \u0644\u0627\u06af \u0627\u0646 \u06a9\u0631\u0646\u0627 \u062f\u0648\u0646\u0648\u06ba \u0627\u06cc\u06a9 \u06c1\u06cc \u062a\u06cc\u0646 \u0642\u062f\u0645\u06cc \u067e\u06cc\u0679\u0631\u0646 \u06a9\u06cc \u067e\u06cc\u0631\u0648\u06cc \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<ol>\n<li>\u0633\u0631\u0648\u0631 \u0627\u06cc\u06a9 \u0628\u06d2 \u062a\u0631\u062a\u06cc\u0628 \u0686\u06cc\u0644\u0646\u062c \u062a\u06cc\u0627\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0633\u06d2 \u06a9\u0686\u06be \u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0628\u0631\u0627\u0624\u0632\u0631 \u06a9\u0648 \u0628\u06be\u06cc\u062c\u062a\u0627 \u06c1\u06d2\u06d4<\/li>\n<li>\u0628\u0631\u0627\u0624\u0632\u0631 \u0688\u06cc\u0648\u0627\u0626\u0633 \u0633\u06d2 \u0635\u0627\u0631\u0641 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u0646\u06d2 \u0627\u0648\u0631 \u0686\u06cc\u0644\u0646\u062c \u067e\u0631 \u062f\u0633\u062a\u062e\u0637 \u06a9\u0631\u0646\u06d2 \u06a9\u0648 \u06a9\u06c1\u062a\u0627 \u06c1\u06d2\u06d4<\/li>\n<li>\u0628\u0631\u0627\u0624\u0632\u0631 \u0627\u06cc\u06a9 \u062f\u0633\u062a\u062e\u0637 \u0634\u062f\u06c1 \u062c\u0648\u0627\u0628 \u0648\u0627\u067e\u0633 \u0628\u06be\u06cc\u062c\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0633\u0631\u0648\u0631 \u0627\u0633 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/li>\n<\/ol>\n<p>\u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646 (WebAuthn \u0627\u0633\u06d2 &quot;\u0627\u0646\u062f\u0631\u0627\u062c&#8221; \u06a9\u06c1\u062a\u0627 \u06c1\u06d2)\u060c \u0688\u06cc\u0648\u0627\u0626\u0633 \u0627\u06cc\u06a9 \u0646\u06cc\u0627 \u06a9\u0644\u06cc\u062f \u062c\u0648\u0691\u0627 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u06cc\u06a9 \u0639\u0648\u0627\u0645\u06cc \u06a9\u0644\u06cc\u062f \u0648\u0627\u067e\u0633 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0633\u0631\u0648\u0631 \u067e\u06be\u0631 \u062c\u0648\u0627\u0628 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0639\u0648\u0627\u0645\u06cc \u06a9\u0644\u06cc\u062f \u06a9\u0648 \u0630\u062e\u06cc\u0631\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0644\u0627\u06af \u0627\u0646 (\u062a\u0635\u062f\u06cc\u0642) \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646\u060c \u0622\u0644\u06c1 \u0627\u06cc\u06a9 \u0646\u0626\u06d2 \u0633\u0648\u0627\u0644 \u067e\u0631 \u062f\u0633\u062a\u062e\u0637 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0645\u0648\u062c\u0648\u062f\u06c1 \u0646\u062c\u06cc \u06a9\u0644\u06cc\u062f \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0633\u0631\u0648\u0631 \u067e\u06be\u0631 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0630\u062e\u06cc\u0631\u06c1 \u0634\u062f\u06c1 \u0639\u0648\u0627\u0645\u06cc \u06a9\u0644\u06cc\u062f \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u062f\u0633\u062a\u062e\u0637 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u067e\u0648\u0631\u06d2 \u06a9\u0648\u0688 \u0645\u06cc\u06ba \u062f\u0648 \u0627\u0648\u0631 \u062a\u0635\u0648\u0631\u0627\u062a \u0638\u0627\u06c1\u0631 \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u06a9\u06c1 <strong>\u0627\u0646\u062d\u0635\u0627\u0631 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u06cc \u067e\u0627\u0631\u0679\u06cc ID<\/strong> (RP ID) \u0648\u06c1 \u0688\u0648\u0645\u06cc\u0646 \u06c1\u06d2 \u062c\u0633 \u0633\u06d2 \u067e\u0627\u0633\u06a9\u06cc \u06a9\u0627 \u062a\u0639\u0644\u0642 \u06c1\u06d2\u06d4 <code>example.com<\/code>. \u062a\u0631\u0642\u06cc \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646\u060c <code>localhost<\/code>. \u0628\u0631\u0627\u0624\u0632\u0631 \u062f\u0648\u0633\u0631\u06d2 \u0688\u0648\u0645\u06cc\u0646\u0632 \u0633\u06d2 \u0622\u067e \u06a9\u06cc \u062e\u0641\u06cc\u06c1 \u0686\u0627\u0628\u06cc\u0627\u06ba \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u0627\u0646\u06a9\u0627\u0631 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062c\u0633 \u0633\u06d2 \u0622\u067e \u06a9\u06cc \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u06cc\u06ba \u0641\u0634\u0646\u06af \u06a9\u06d2 \u062e\u0644\u0627\u0641 \u0645\u0632\u0627\u062d\u0645 \u0628\u0646 \u062c\u0627\u062a\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u06a9\u06c1 <strong>\u0635\u0627\u0631\u0641 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 (UV) \u067e\u0631\u0686\u0645<\/strong> \u062f\u0633\u062a\u062e\u0637 \u0634\u062f\u06c1 \u062c\u0648\u0627\u0628 \u06a9\u06d2 \u0627\u0646\u062f\u0631 \u062a\u06be\u0648\u0691\u0627 \u0633\u0627 \u06c1\u06d2. \u06cc\u06c1 \u0635\u0631\u0641 \u0627\u06cc\u06a9 \u0688\u06cc\u0648\u0627\u0626\u0633 \u067e\u0631 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2 \u062c\u0628 \u0635\u0627\u0631\u0641 \u0648\u0627\u0642\u0639\u06cc \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679\u060c \u0686\u06c1\u0631\u06d2\u060c \u06cc\u0627 \u0627\u0633\u06a9\u0631\u06cc\u0646 \u0644\u0627\u06a9 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u0645\u06a9\u0645\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0633\u0631\u0648\u0631 \u0627\u0633 \u062c\u06be\u0646\u0688\u06d2 \u06a9\u0648 \u06cc\u06c1 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u06cc\u06a9\u06be\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u06cc\u06c1 \u06a9\u0648\u0626\u06cc \u0628\u06d2 \u062a\u0631\u062a\u06cc\u0628 \u0635\u0627\u0631\u0641 \u06a9\u0644\u06cc\u062f \u062f\u0628\u0627\u0646\u06d2 \u06cc\u0627 \u0628\u0679\u0646 \u067e\u0631 \u06a9\u0644\u06a9 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u0627 \u0646\u06c1\u06cc\u06ba \u062a\u06be\u0627\u06d4<\/p>\n<h2 id=\"heading-project-structure\">\u0645\u0646\u0635\u0648\u0628\u06d2 \u06a9\u06cc \u0633\u0627\u062e\u062a<\/h2>\n<p>\u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u0630\u062e\u06cc\u0631\u06c1 \u0645\u06cc\u06ba \u062f\u0648 \u0627\u0644\u06af \u0627\u0644\u06af \u0627\u06cc\u067e\u0633 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-text\">passwordless-auth\/\n\u251c\u2500\u2500 client\/   # Next.js frontend, runs on port 3000\n\u2514\u2500\u2500 server\/   # NestJS API, runs on port 4000\n<\/code><\/pre>\n<p>\u0686\u0648\u0646\u06a9\u06c1 \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679\u0633 \u067e\u0631 \u0627\u0646\u062d\u0635\u0627\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u06c1\u0645 \u067e\u06c1\u0644\u06d2 \u0627\u06cc\u06a9 \u0633\u0631\u0648\u0631 \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-how-to-set-up-the-nestjs-backend\">NestJS \u0628\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u06a9\u0648 \u06a9\u06cc\u0633\u06d2 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u0627 \u062c\u0627\u0626\u06d2\u06d4<\/h2>\n<p>Nest CLI \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0627\u06cc\u06a9 \u0646\u06cc\u0627 NestJS \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0628\u0646\u0627 \u06a9\u0631 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-bash\">npx @nestjs\/cli new server\ncd server\n<\/code><\/pre>\n<p>\u067e\u06be\u0631 WebAuthn\u060c \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633\u060c \u06a9\u0646\u0641\u06cc\u06af\u0631\u06cc\u0634\u0646\u060c \u0627\u0648\u0631 JSON \u0648\u06cc\u0628 \u0679\u0648\u06a9\u0646 (JWT) \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0646\u062d\u0635\u0627\u0631 \u0627\u0646\u0633\u0679\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-bash\">npm install @simplewebauthn\/server @nestjs\/typeorm typeorm pg @nestjs\/config @nestjs\/jwt @nestjs\/passport passport passport-jwt\n<\/code><\/pre>\n<h3 id=\"heading-create-the-database\">\u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0628\u0646\u0627\u0626\u06cc\u06ba<\/h3>\n<p>\u0646\u0627\u0645\u06cc \u0627\u06cc\u06a9 \u062e\u0627\u0644\u06cc \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0628\u0646\u0627\u0626\u06cc\u06ba <code>auth<\/code>. \u0679\u0631\u0645\u06cc\u0646\u0644 \u0645\u06cc\u06ba \u062f\u0631\u062c \u0630\u06cc\u0644 \u06a9\u0648 \u0686\u0644\u0627\u0626\u06cc\u06ba:<\/p>\n<pre><code class=\"language-bash\">createdb -h localhost -U postgres auth\n<\/code><\/pre>\n<p>\u0627\u06af\u0631 \u0622\u067e pgAdmin \u06a9\u0648 \u062a\u0631\u062c\u06cc\u062d \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 \u0627\u0633 \u067e\u0631 \u062f\u0627\u0626\u06cc\u06ba \u06a9\u0644\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4 <strong>\u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633<\/strong>\u0645\u0646\u062a\u062e\u0628 \u06a9\u0631\u06cc\u06ba <strong>\u0628\u0646\u0627\u0646\u0627<\/strong>\u067e\u06be\u0631 <strong>\u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633<\/strong>\u0627\u0633\u06d2 \u0646\u0627\u0645 \u062f\u06cc\u06ba\u06d4 <code>auth<\/code>.<\/p>\n<p>\u0627\u06af\u0631 \u0622\u067e \u0627\u0633 \u0645\u0631\u062d\u0644\u06c1 \u06a9\u0648 \u0686\u06be\u0648\u0691 \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062a\u0648 NestJS \u0634\u0631\u0648\u0639 \u06c1\u0648\u0646\u06d2 \u067e\u0631 \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u06af\u0627\u06d4 <code>error: database \"auth\" does not exist<\/code>. TypeORM \u0679\u06cc\u0628\u0644 \u0628\u0646\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u06cc\u06c1 \u062e\u0648\u062f \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0646\u06c1\u06cc\u06ba \u0628\u0646\u0627\u062a\u0627\u06d4<\/p>\n<h3 id=\"heading-add-environment-variables\">\u0645\u0627\u062d\u0648\u0644\u06cc\u0627\u062a\u06cc \u0645\u062a\u063a\u06cc\u0631 \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>.env<\/code> \u0641\u0627\u0626\u0644 <code>server<\/code> \u0641\u0648\u0644\u0688\u0631:<\/p>\n<pre><code class=\"language-bash\">JWT_SECRET=replace-with-a-long-random-string\n\nWEBAUTHN_RP_ID=localhost\nWEBAUTHN_ORIGIN=http:\/\/localhost:3000\n\nDB_HOST=localhost\nDB_PORT=5432\nDB_USERNAME=postgres\nDB_PASSWORD=your-database-password\nDB_NAME=auth\n<\/code><\/pre>\n<p><code>WEBAUTHN_RP_ID<\/code>    \u0635\u0631\u0641 \u0627\u06cc\u06a9 \u0688\u0648\u0645\u06cc\u0646 \u06c1\u06d2\u060c \u06a9\u0648\u0626\u06cc \u067e\u0631\u0648\u0679\u0648\u06a9\u0648\u0644 \u06cc\u0627 \u0628\u0646\u062f\u0631\u06af\u0627\u06c1\u06cc\u06ba \u0646\u06c1\u06cc\u06ba \u06c1\u06cc\u06ba\u06d4 <code>WEBAUTHN_ORIGIN<\/code> \u06cc\u06c1 \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u06a9\u0627 \u0639\u06cc\u0646 \u0645\u0637\u0627\u0628\u0642 URL \u06c1\u06d2\u06d4 \u0633\u0631\u0648\u0631 \u062f\u0648\u0633\u0631\u06d2 \u0630\u0631\u0627\u0626\u0639 \u0633\u06d2 \u0622\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u062a\u0645\u0627\u0645 \u062c\u0648\u0627\u0628\u0627\u062a \u06a9\u0648 \u0645\u0633\u062a\u0631\u062f \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0628\u0631\u0627\u0624\u0632\u0631\u0632 \u0635\u0631\u0641 HTTPS \u0633\u0627\u0626\u0679\u0648\u06ba \u0633\u06d2 \u06cc\u0627 \u06cc\u06c1\u0627\u06ba \u0633\u06d2 WebAuthn \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba: <code>localhost<\/code>\u0644\u06c1\u0630\u0627 \u06cc\u06c1 \u062a\u0631\u062a\u06cc\u0628 \u0628\u063a\u06cc\u0631 \u06a9\u0633\u06cc \u0633\u0646\u062f \u06a9\u06d2 \u062a\u0631\u0642\u06cc \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-connect-to-postgresql\">PostgreSQL \u0633\u06d2 \u062c\u0691\u06cc\u06ba\u06d4<\/h3>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>src\/auth\/config\/database.config.ts<\/code> \u06af\u0631\u0648\u067e \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628\u0627\u062a \u06a9\u06d2 \u0644\u06cc\u06d2:<\/p>\n<pre><code class=\"language-typescript\">import { registerAs } from '@nestjs\/config';\n\nexport default registerAs('database', () => ({\n  type: 'postgres',\n  host: process.env.DB_HOST,\n  port: parseInt(process.env.DB_PORT, 10),\n  username: process.env.DB_USERNAME,\n  password: process.env.DB_PASSWORD,\n  database: process.env.DB_NAME,\n  entities: [__dirname + '\/..\/**\/*.entity{.ts,.js}'],\n  synchronize: process.env.NODE_ENV !== 'production',\n}));\n<\/code><\/pre>\n<p>\u062c\u0628 \u062a\u0645 \u06c1\u0648 <code>config<\/code> \u0641\u0648\u0644\u0688\u0631\u060c \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba <code>src\/auth\/config\/jwt.config.ts<\/code> \u0679\u0648\u06a9\u0646 \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628\u0627\u062a \u06a9\u06d2 \u0644\u06cc\u06d2:<\/p>\n<pre><code class=\"language-typescript\">import { registerAs } from '@nestjs\/config';\n\nexport default registerAs('jwt', () => ({\n  secret: process.env.JWT_SECRET,\n  expiresIn: '1h',\n}));\n<\/code><\/pre>\n<p>\u06a9\u06c1 <code>synchronize<\/code> \u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a TypeORM \u06a9\u0648 \u0627\u062f\u0627\u0631\u0648\u06ba \u06a9\u06cc \u0628\u0646\u06cc\u0627\u062f \u067e\u0631 \u0679\u06cc\u0628\u0644 \u0628\u0646\u0627\u0646\u06d2 \u0627\u0648\u0631 \u0627\u067e \u0688\u06cc\u0679 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u06c1\u062f\u0627\u06cc\u062a \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06cc\u06c1 \u062a\u0631\u0642\u06cc \u06a9\u06d2 \u0644\u06cc\u06d2 \u0622\u0633\u0627\u0646 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0645\u06cc\u06ba \u062c\u0627\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0622\u067e \u06a9\u0648 \u06c1\u062c\u0631\u062a \u067e\u0631 \u0633\u0648\u0626\u0686 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u06af\u06cc\u06d4<\/p>\n<p>\u067e\u06be\u0631 \u0633\u0628 \u06a9\u0686\u06be \u062c\u0648\u0691\u06cc\u06ba\u06d4 <code>src\/app.module.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { Module } from '@nestjs\/common';\nimport { ConfigModule, ConfigService } from '@nestjs\/config';\nimport { TypeOrmModule } from '@nestjs\/typeorm';\nimport { AuthModule } from '.\/auth\/auth.module';\nimport databaseConfig from '.\/auth\/config\/database.config';\nimport jwtConfig from '.\/auth\/config\/jwt.config';\nimport { User, Authenticator } from '.\/auth\/entities\/auth.entity';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot({\n      isGlobal: true,\n      load: [databaseConfig, jwtConfig],\n    }),\n    TypeOrmModule.forRootAsync({\n      imports: [ConfigModule],\n      useFactory: (configService: ConfigService) => ({\n        type: 'postgres',\n        host: configService.get('database.host'),\n        port: configService.get('database.port'),\n        username: configService.get('database.username'),\n        password: configService.get('database.password'),\n        database: configService.get('database.database'),\n        entities: [User, Authenticator],\n        synchronize: configService.get('database.synchronize'),\n      }),\n      inject: [ConfigService],\n    }),\n    AuthModule,\n  ],\n})\nexport class AppModule {}\n<\/code><\/pre>\n<p>\u0622\u062e\u0631 \u0645\u06cc\u06ba\u060c CORS \u06a9\u0648 \u0641\u0639\u0627\u0644 \u06a9\u0631\u06cc\u06ba: <code>src\/main.ts<\/code> \u0644\u06c1\u0630\u0627 \u067e\u0648\u0631\u0679 3000 \u067e\u0631 \u0627\u06cc\u06a9 \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u067e\u0648\u0631\u0679 4000 \u067e\u0631 API \u06a9\u0648 \u06a9\u0627\u0644 \u06a9\u0631\u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">import { NestFactory } from '@nestjs\/core';\nimport { ValidationPipe } from '@nestjs\/common';\nimport { AppModule } from '.\/app.module';\n\nasync function bootstrap() {\n  const app = await NestFactory.create(AppModule);\n  app.useGlobalPipes(new ValidationPipe());\n  app.enableCors({\n    origin: true,\n    credentials: true,\n    allowedHeaders: ['Content-Type', 'Authorization'],\n  });\n  await app.listen(4000);\n  console.log('App running on port 4000');\n}\nbootstrap();\n<\/code><\/pre>\n<p><code>origin: true<\/code>    \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0630\u0631\u06cc\u0639\u06c1 \u0633\u06d2 \u062f\u0631\u062e\u0648\u0627\u0633\u062a\u06cc\u06ba \u0642\u0628\u0648\u0644 \u06a9\u0631\u06a9\u06d2 \u0645\u0642\u0627\u0645\u06cc \u062a\u0631\u0642\u06cc \u06a9\u0648 \u0622\u0633\u0627\u0646 \u0628\u0646\u0627\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u062a\u0639\u06cc\u0646\u0627\u062a \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0627\u0633\u06d2 \u0627\u067e\u0646\u06d2 \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u06a9\u06d2 URL \u0633\u06d2 \u0628\u062f\u0644 \u062f\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-how-to-define-the-database-entities\">\u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0627\u062f\u0627\u0631\u0648\u06ba \u06a9\u06cc \u0648\u0636\u0627\u062d\u062a \u06a9\u06cc\u0633\u06d2 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u0627\u0633 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0648 \u0645\u06cc\u0632\u06cc\u06ba \u062f\u0631\u06a9\u0627\u0631 \u06c1\u06cc\u06ba\u06d4 \u06cc\u0648\u0632\u0631 \u0679\u06cc\u0628\u0644 \u0627\u06a9\u0627\u0624\u0646\u0679\u0633 \u067e\u0631 \u0645\u0634\u062a\u0645\u0644 \u06c1\u06d2 \u0627\u0648\u0631 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0646\u0646\u062f\u06c1 \u0679\u06cc\u0628\u0644 \u0645\u06cc\u06ba \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u06cc\u06ba \u06c1\u06cc\u06ba\u06d4 \u0627\u06cc\u06a9 \u0635\u0627\u0631\u0641 \u06a9\u06d2 \u067e\u0627\u0633 \u0645\u062a\u0639\u062f\u062f \u067e\u0627\u0633 \u06a9\u06cc\u0632 \u06c1\u0648 \u0633\u06a9\u062a\u06cc \u06c1\u06cc\u06ba (\u0645\u062b\u0627\u0644 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631\u060c \u0627\u06cc\u06a9 \u0627\u0646 \u06a9\u06d2 \u0644\u06cc\u067e \u0679\u0627\u067e \u067e\u0631 \u0627\u0648\u0631 \u0627\u06cc\u06a9 \u0627\u0646 \u06a9\u06d2 \u0641\u0648\u0646 \u067e\u0631)\u06d4<\/p>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>src\/auth\/entities\/auth.entity.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import {\n  Entity,\n  Column,\n  PrimaryGeneratedColumn,\n  ManyToOne,\n  OneToMany,\n  CreateDateColumn,\n  UpdateDateColumn,\n} from 'typeorm';\nimport type {\n  CredentialDeviceType,\n  Base64URLString,\n} from '@simplewebauthn\/server';\n\n@Entity()\nexport class User {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column({ unique: true })\n  email: string;\n\n  @Column({ unique: true })\n  webauthnId: Base64URLString;\n\n  @Column({ type: 'varchar', nullable: true })\n  currentChallenge?: string | null;\n\n  @OneToMany(() => Authenticator, (authenticator) => authenticator.user)\n  authenticators: Authenticator[];\n\n  @CreateDateColumn()\n  createdAt: Date;\n\n  @UpdateDateColumn()\n  updatedAt: Date;\n}\n\n@Entity()\nexport class Authenticator {\n  @PrimaryGeneratedColumn('uuid')\n  id: string;\n\n  @Column({ unique: true })\n  credentialId: Base64URLString;\n\n  @Column({ type: 'bytea' })\n  credentialPublicKey: Uint8Array;\n\n  @ManyToOne(() => User, (user) => user.authenticators, { onDelete: 'CASCADE' })\n  user: User;\n\n  @Column()\n  webauthnUserId: Base64URLString;\n\n  @Column({ type: 'bigint' })\n  counter: number;\n\n  @Column({\n    type: 'varchar',\n    length: 32,\n  })\n  deviceType: CredentialDeviceType;\n\n  @Column()\n  backedUp: boolean;\n\n  @Column('simple-array', { nullable: true })\n  transports?: string[];\n\n  @CreateDateColumn()\n  createdAt: Date;\n\n  @UpdateDateColumn()\n  updatedAt: Date;\n}\n<\/code><\/pre>\n<p>\u0622\u0626\u06cc\u06d2 \u0627\u0646 \u0634\u0639\u0628\u0648\u06ba \u0645\u06cc\u06ba \u0633\u06d2 \u06a9\u0686\u06be \u06a9\u0648 \u0642\u0631\u06cc\u0628 \u0633\u06d2 \u062f\u06cc\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0633\u0628 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 <code>webauthnId<\/code> \u0627\u06cc\u06a9 \u0635\u0627\u0631\u0641 \u06a9\u0627 \u06c1\u06cc\u0646\u0688\u0644 \u062c\u0648 \u0622\u0644\u06c1 \u067e\u0631 \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0645\u062d\u0641\u0648\u0638 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 WebAuthn \u06a9\u06cc \u062a\u0641\u0635\u06cc\u0644\u0627\u062a \u0628\u062a\u0627\u062a\u06cc \u06c1\u06cc\u06ba \u06a9\u06c1 \u0627\u0633 \u0645\u06cc\u06ba \u0630\u0627\u062a\u06cc \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u0646\u06cc \u0686\u0627\u06c1\u0626\u06cc\u06ba\u060c \u0627\u0633 \u0644\u06cc\u06d2 \u0627\u0633\u06d2 \u0627\u06cc \u0645\u06cc\u0644\u0632 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0628\u06d2 \u062a\u0631\u062a\u06cc\u0628 \u0628\u0627\u0626\u0679\u0633 \u0633\u06d2 \u0628\u06be\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<p>\u0627\u06af\u0644\u0627\u060c <code>currentChallenge<\/code> \u0633\u0631\u0648\u0631 \u06a9\u06d2 \u067e\u0627\u0633 \u0627\u06cc\u06a9 \u0686\u06cc\u0644\u0646\u062c \u0622\u067e \u06a9\u0627 \u0645\u0646\u062a\u0638\u0631 \u06c1\u06d2\u06d4 \u0622\u067e\u0634\u0646 \u0628\u0646\u0627\u062a\u06d2 \u0648\u0642\u062a \u0633\u06cc\u0679 \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u06a9\u0627\u0645\u06cc\u0627\u0628 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u06d2 \u0628\u0639\u062f \u06a9\u0644\u06cc\u0626\u0631 \u06c1\u0648 \u062c\u0627\u0626\u06cc\u06ba\u06d4 \u062a\u0648\u062c\u06c1 \u0641\u0631\u0645\u0627\u0626\u06cc\u06ba <code>string | null<\/code> \u0632\u0645\u0631\u06c1 \u06cc\u06c1 \u0627\u06c1\u0645 \u06c1\u06d2 \u0627\u0648\u0631 \u0622\u067e \u0633\u06cc\u06a9\u06cc\u0648\u0631\u0679\u06cc \u0633\u06cc\u06a9\u0634\u0646 \u0645\u06cc\u06ba \u062f\u06cc\u06a9\u06be \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p><code>counter<\/code>    \u062f\u0633\u062a\u062e\u0637\u06cc \u06a9\u0627\u0624\u0646\u0679\u0631\u06d4 \u06a9\u0686\u06be \u0645\u0633\u062a\u0646\u062f \u06c1\u0631 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u0633 \u0645\u06cc\u06ba \u0627\u0636\u0627\u0641\u06c1 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0633\u0631\u0648\u0631 \u06a9\u0648 \u06a9\u0644\u0648\u0646 \u0634\u062f\u06c1 \u0622\u0644\u0627\u062a \u06a9\u0627 \u067e\u062a\u06c1 \u0644\u06af\u0627\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0645\u0637\u0627\u0628\u0642\u062a \u067e\u0630\u06cc\u0631 \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u06cc\u06ba \u0639\u0627\u0645 \u0637\u0648\u0631 \u067e\u0631 \u06a9\u0627\u0624\u0646\u0679\u0631 \u06a9\u0648 0 \u067e\u0631 \u0631\u06a9\u06be\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 SimpleWebAuthn \u062f\u0648\u0646\u0648\u06ba \u0645\u0646\u0638\u0631\u0646\u0627\u0645\u0648\u06ba \u06a9\u06cc \u062d\u0645\u0627\u06cc\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p><code>deviceType<\/code>    \u0627\u0648\u0631 <code>backedUp<\/code> \u06cc\u06c1 \u0622\u067e \u06a9\u0648 \u0628\u062a\u0627\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0622\u06cc\u0627 \u0622\u067e \u06a9\u06cc \u0627\u0646\u06a9\u0631\u067e\u0634\u0646 \u06a9\u06cc\u0632 \u06a9\u0648 \u062a\u0645\u0627\u0645 \u0622\u0644\u0627\u062a \u067e\u0631 \u06c1\u0645 \u0622\u06c1\u0646\u06af \u06a9\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u06a9\u06cc\u0627 \u0627\u0646 \u06a9\u0627 \u0641\u06cc \u0627\u0644\u062d\u0627\u0644 \u0628\u06cc\u06a9 \u0627\u067e \u0644\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2 (\u062c\u06cc\u0633\u06d2 iCloud \u06a9\u06cc\u0686\u06cc\u0646 \u0645\u06cc\u06ba)\u06d4<\/p>\n<p>\u0627\u0648\u0631 \u0622\u062e\u0631 \u0645\u06cc\u06ba\u060c <code>transports<\/code> \u0631\u06cc\u06a9\u0627\u0631\u0688 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0628\u0631\u0627\u0624\u0632\u0631 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0646\u0646\u062f\u06c1 \u062a\u06a9 \u06a9\u06cc\u0633\u06d2 \u0631\u0633\u0627\u0626\u06cc \u062d\u0627\u0635\u0644 \u06a9\u0631\u0633\u06a9\u062a\u0627 \u06c1\u06d2 (\u0622\u0644\u06c1 \u0645\u06cc\u06ba \u0628\u0646\u0627\u06cc\u0627 \u06af\u06cc\u0627\u060c USB\u060c \u0628\u0644\u0648\u0679\u0648\u062a\u06be \u06cc\u0627 \u0641\u0648\u0646 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2)\u06d4<\/p>\n<h2 id=\"heading-how-to-register-a-passkey-on-the-server\">\u0633\u0631\u0648\u0631 \u067e\u0631 \u0627\u06cc\u06a9 \u0627\u0646\u06a9\u0631\u067e\u0634\u0646 \u06a9\u0644\u06cc\u062f \u06a9\u0648 \u06a9\u06cc\u0633\u06d2 \u0631\u062c\u0633\u0679\u0631 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>src\/auth\/auth.service.ts<\/code>. \u0627\u067e\u0646\u06cc \u06a9\u0644\u0627\u0633 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06d2 \u06a9\u0631 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-typescript\">import {\n  Injectable,\n  UnauthorizedException,\n  ConflictException,\n  Logger,\n} from '@nestjs\/common';\nimport { ConfigService } from '@nestjs\/config';\nimport { randomBytes } from 'crypto';\nimport { JwtService } from '@nestjs\/jwt';\nimport { InjectRepository } from '@nestjs\/typeorm';\nimport { Repository } from 'typeorm';\nimport { User, Authenticator } from '.\/entities\/auth.entity';\nimport {\n  generateRegistrationOptions,\n  generateAuthenticationOptions,\n  verifyRegistrationResponse,\n  verifyAuthenticationResponse,\n} from '@simplewebauthn\/server';\nimport type {\n  AuthenticationResponseJSON,\n  PublicKeyCredentialCreationOptionsJSON,\n  PublicKeyCredentialRequestOptionsJSON,\n  RegistrationResponseJSON,\n} from '@simplewebauthn\/server';\n\n@Injectable()\nexport class AuthService {\n  private readonly logger = new Logger(AuthService.name);\n  private readonly rpName=\"Passwordless Auth\";\n  private readonly rpID: string;\n  private readonly origin: string;\n\n  constructor(\n    @InjectRepository(User)\n    private readonly userRepository: Repository<user>,\n    @InjectRepository(Authenticator)\n    private readonly authenticatorRepository: Repository<authenticator>,\n    private readonly jwtService: JwtService,\n    private readonly configService: ConfigService,\n  ) {\n    this.rpID = this.configService.get<string>('WEBAUTHN_RP_ID');\n    this.origin = this.configService.get<string>('WEBAUTHN_ORIGIN');\n  }\n<\/string><\/string><\/authenticator><\/user><\/code><\/pre>\n<p><code>rpName<\/code>    \u0627\u06cc\u06a9 \u0627\u0646\u0633\u0627\u0646\u06cc \u067e\u0691\u06be\u0646\u06d2 \u06a9\u06d2 \u0642\u0627\u0628\u0644 \u0627\u06cc\u067e \u06a9\u0627 \u0646\u0627\u0645\u06d4 \u0635\u0627\u0631\u0641\u06cc\u0646 \u0627\u0633 \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u06a9\u0648 \u0622\u067e\u0631\u06cc\u0679\u0646\u06af \u0633\u0633\u0679\u0645 \u06a9\u06d2 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06cc \u067e\u0631\u0627\u0645\u067e\u0679 \u0627\u0648\u0631 \u0628\u0639\u062f \u0645\u06cc\u06ba \u067e\u0627\u0633 \u0648\u0631\u0688 \u0645\u06cc\u0646\u06cc\u062c\u0631 \u0645\u06cc\u06ba \u062f\u06cc\u06a9\u06be \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-generate-registration-options\">\u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u06d2 \u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a \u0628\u0646\u0627\u0626\u06cc\u06ba<\/h3>\n<p>\u067e\u06c1\u0644\u0627 \u0637\u0631\u06cc\u0642\u06c1 \u0635\u0627\u0631\u0641 \u06a9\u0648 \u062a\u0644\u0627\u0634 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u06cc\u0627 \u062a\u062e\u0644\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u067e\u06be\u0631 SimpleWebAuthn \u0633\u06d2 \u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u06d2 \u0622\u067e\u0634\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u067e\u0648\u0686\u06be\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0633\u06d2 \u0627\u067e\u0646\u06cc \u06a9\u0644\u0627\u0633 \u0645\u06cc\u06ba \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba:<\/p>\n<pre><code class=\"language-typescript\">async generateRegistrationOptions(\n    email: string,\n): Promise<publickeycredentialcreationoptionsjson> {\n  let user = await this.userRepository.findOne({ where: { email } });\n\n  if (!user) {\n    user = this.userRepository.create({\n      email,\n      webauthnId: randomBytes(32).toString('base64url'),\n    });\n    await this.userRepository.save(user);\n  }\n\n  const authenticators = await this.authenticatorRepository.find({\n    where: { user: { id: user.id } },\n  });\n\n  if (authenticators.length > 0) {\n    throw new ConflictException(\n      'An account with this email already exists. Please sign in.',\n    );\n  }\n\n  const options = await generateRegistrationOptions({\n    rpName: this.rpName,\n    rpID: this.rpID,\n    userID: Buffer.from(user.webauthnId, 'base64url'),\n    userName: user.email,\n    attestationType: 'none',\n    authenticatorSelection: {\n      residentKey: 'required',\n      userVerification: 'required',\n    },\n    excludeCredentials: authenticators.map((authenticator) => ({\n      id: authenticator.credentialId,\n      transports: authenticator.transports,\n    })),\n  });\n\n  \/\/ Save the current challenge\n  user.currentChallenge = options.challenge;\n  await this.userRepository.save(user);\n\n  return options;\n}\n<\/publickeycredentialcreationoptionsjson><\/code><\/pre>\n<p>\u06a9\u06c1 <code>authenticatorSelection<\/code> \u0628\u0644\u0627\u06a9 \u0648\u06c1 \u062c\u06af\u06c1 \u06c1\u06d2 \u062c\u06c1\u0627\u06ba \u0622\u067e \u0641\u06cc\u0635\u0644\u06c1 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 \u0622\u067e \u06a9\u0633 \u0642\u0633\u0645 \u06a9\u06cc \u067e\u0627\u0633\u06a9\u06cc \u0686\u0627\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p><code>residentKey: 'required'<\/code>    \u0642\u0627\u0628\u0644 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u0627\u0633\u0646\u0627\u062f \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u06cc\u06ba\u06d4 \u06cc\u06c1\u06cc \u0686\u06cc\u0632 \u0627\u0633\u06d2 \u0627\u06cc\u06a9 \u062d\u0642\u06cc\u0642\u06cc \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u0628\u0646\u0627\u062a\u06cc \u06c1\u06d2 ( \u0627\u0633\u0646\u0627\u062f \u0688\u06cc\u0648\u0627\u0626\u0633 \u067e\u0631 \u06cc\u0627 \u0635\u0627\u0631\u0641 \u06a9\u06d2 \u067e\u0627\u0633 \u0648\u0631\u0688 \u0645\u06cc\u0646\u06cc\u062c\u0631 \u0645\u06cc\u06ba \u0645\u062d\u0641\u0648\u0638 \u06a9\u06cc \u062c\u0627\u062a\u06cc \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u067e\u06be\u0631 \u062f\u0648\u0633\u0631\u06d2 \u0622\u0644\u0627\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0645\u0637\u0627\u0628\u0642\u062a \u067e\u0630\u06cc\u0631 \u06c1\u0648 \u0633\u06a9\u062a\u06cc \u06c1\u06cc\u06ba)\u06d4<\/p>\n<p><code>userVerification: 'required'<\/code>    \u0622\u0644\u06c1 \u06a9\u0648 \u0645\u0637\u0644\u0639 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0627\u0633\u06d2 \u0635\u0627\u0631\u0641 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2 (\u06cc\u0639\u0646\u06cc \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679\u060c \u0686\u06c1\u0631\u06c1\u060c \u06cc\u0627 \u0627\u0633\u06a9\u0631\u06cc\u0646 \u0644\u0627\u06a9 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0631\u06cc\u06ba)\u06d4 \u0628\u0635\u0648\u0631\u062a \u062f\u06cc\u06af\u0631\u060c \u06a9\u0686\u06be \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0646\u0646\u062f\u06af\u0627\u0646 \u0635\u0631\u0641 \u0648\u062c\u0648\u062f \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u0631\u06cc\u06ba \u06af\u06d2 \u0627\u0648\u0631 \u0627\u0635\u0644 \u0645\u06cc\u06ba \u0635\u0627\u0631\u0641 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<p>\u062c\u0648 \u063a\u0627\u0626\u0628 \u06c1\u06d2 \u0648\u06c1 \u06c1\u06d2 \u0645\u0633\u062a\u0646\u062f \u06a9\u0646\u06a9\u0634\u0646 \u06a9\u0627 \u0627\u062e\u062a\u06cc\u0627\u0631\u06d4 \u0627\u06af\u0631 \u0645\u0642\u0631\u0631 \u06a9\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4 <code>'platform'<\/code>\u06cc\u06c1 \u0635\u0627\u0631\u0641 \u06a9\u0648 \u0627\u067e\u0646\u06d2 \u0645\u0648\u062c\u0648\u062f\u06c1 \u0688\u06cc\u0648\u0627\u0626\u0633 \u067e\u0631 \u0633\u06cc\u0646\u0633\u0631 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u0645\u06cc\u06ba \u0645\u0624\u062b\u0631 \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u0644\u0627\u06a9 \u06a9\u0631 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u06af\u0631 \u0622\u067e \u0627\u0633\u06d2 \u0686\u06be\u0648\u0691 \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062a\u0648 \u0622\u067e \u0627\u067e\u0646\u06d2 \u0641\u0648\u0646 \u06a9\u0648 QR \u06a9\u0648\u0688 \u06cc\u0627 \u06c1\u0627\u0631\u0688\u0648\u06cc\u0626\u0631 \u0633\u06cc\u06a9\u06cc\u0648\u0631\u0679\u06cc \u06a9\u0644\u06cc\u062f \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba (passkeys.dev \u06a9\u06cc \u0637\u0631\u0641 \u0633\u06d2 \u062a\u062c\u0648\u06cc\u0632 \u06a9\u0631\u062f\u06c1)\u06d4<\/p>\n<p><code>attestationType: 'none'<\/code>    \u0627\u0633 \u06a9\u0627 \u0645\u0637\u0644\u0628 \u06c1\u06d2 \u06a9\u06c1 \u06c1\u0645 \u0622\u067e \u06a9\u06d2 \u0622\u0644\u06d2 \u06a9\u0648 \u0627\u0633 \u06a9\u0627 \u0645\u06cc\u06a9 \u0627\u0648\u0631 \u0645\u0627\u0688\u0644 \u062b\u0627\u0628\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0646\u06c1\u06cc\u06ba \u06a9\u06c1\u06cc\u06ba \u06af\u06d2\u06d4 \u0632\u06cc\u0627\u062f\u06c1 \u062a\u0631 \u0635\u0627\u0631\u0641 \u0627\u06cc\u067e\u0633 \u06a9\u0648 \u0627\u0633 \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u06a9\u06cc \u0628\u0627\u0644\u06a9\u0644 \u0628\u06be\u06cc \u0636\u0631\u0648\u0631\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0627\u0633 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0646\u062a\u06cc\u062c\u06c1 \u062f\u0631\u062d\u0642\u06cc\u0642\u062a \u0627\u0636\u0627\u0641\u06cc \u0631\u0627\u0632\u062f\u0627\u0631\u06cc \u06a9\u06d2 \u067e\u06cc\u063a\u0627\u0645\u0627\u062a \u06a9\u0627 \u0628\u0627\u0639\u062b \u0628\u0646 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p><code>excludeCredentials<\/code>    \u0686\u0648\u0646\u06a9\u06c1 \u06cc\u06c1 \u0635\u0627\u0631\u0641 \u06a9\u06d2 \u067e\u0627\u0633 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0645\u0648\u062c\u0648\u062f \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u0648\u06ba \u06a9\u06cc \u0641\u06c1\u0631\u0633\u062a \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0633 \u0644\u06cc\u06d2 \u0622\u0644\u06c1 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0627\u0646\u062f\u0631\u0627\u062c \u0634\u062f\u06c1 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0646\u0646\u062f\u06af\u0627\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679\u0633 \u0646\u06c1\u06cc\u06ba \u0628\u0646\u0627\u062a\u0627\u06d4 \u0627\u06af\u0631 \u0622\u067e \u0627\u0648\u067e\u0631 \u06a9\u06d2 \u0686\u06cc\u06a9 \u06a9\u0648 \u062f\u06cc\u06a9\u06be\u06cc\u06ba \u062a\u0648 \u0627\u0633 \u0645\u0639\u0627\u0645\u0644\u06d2 \u0645\u06cc\u06ba \u0641\u06c1\u0631\u0633\u062a \u06c1\u0645\u06cc\u0634\u06c1 \u062e\u0627\u0644\u06cc \u0631\u06c1\u062a\u06cc \u06c1\u06d2\u06d4 \u0627\u06af\u0631 \u0622\u067e \u0628\u0639\u062f \u0645\u06cc\u06ba \u0644\u0627\u06af \u0627\u0646 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u06cc\u06ba \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u0646\u0627 \u0686\u0627\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 \u06cc\u06c1 \u0645\u0641\u06cc\u062f \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u067e\u0646\u06d2 \u0645\u0648\u062c\u0648\u062f\u06c1 \u0645\u0633\u062a\u0646\u062f \u06a9\u0648 \u0686\u06cc\u06a9 \u06a9\u0631\u0646\u0627 \u0628\u06be\u06cc \u0636\u0631\u0648\u0631\u06cc \u06c1\u06d2\u06d4 \u0686\u0648\u0646\u06a9\u06c1 \u06cc\u06c1 \u0627\u062e\u062a\u062a\u0627\u0645\u06cc \u0646\u0642\u0637\u06c1 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u0644\u0627\u06af \u0627\u0646 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u0646\u06c1\u06cc\u06ba \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0633 \u0644\u06cc\u06d2 \u06cc\u06c1 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u06a9\u0633\u06cc \u0627\u06cc\u0633\u06d2 \u0627\u06a9\u0627\u0624\u0646\u0679 \u0645\u06cc\u06ba \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u0646\u06c1\u06cc\u06ba \u062f\u06d2 \u0633\u06a9\u062a\u0627 \u062c\u0633 \u06a9\u06d2 \u067e\u0627\u0633 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0645\u0648\u062c\u0648\u062f \u06c1\u06d2\u06d4 \u0628\u0635\u0648\u0631\u062a \u062f\u06cc\u06af\u0631\u060c \u062c\u0648 \u0628\u06be\u06cc \u0622\u067e \u06a9\u0627 \u0627\u06cc \u0645\u06cc\u0644 \u067e\u062a\u06c1 \u062c\u0627\u0646\u062a\u0627 \u06c1\u06d2 \u0648\u06c1 \u0622\u067e \u06a9\u06d2 \u0627\u06a9\u0627\u0624\u0646\u0679 \u0633\u06d2 \u0627\u067e\u0646\u06cc \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u0645\u0646\u0633\u0644\u06a9 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-verify-the-registration-response\">\u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u0627 \u062c\u0648\u0627\u0628 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u062c\u0628 \u0635\u0627\u0631\u0641 \u0688\u06cc\u0648\u0627\u0626\u0633 \u067e\u0631 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0628\u0631\u0627\u0624\u0632\u0631 \u062c\u0648\u0627\u0628 \u0628\u06be\u06cc\u062c\u062a\u0627 \u06c1\u06d2\u06d4 \u062f\u0648\u0633\u0631\u0627 \u0637\u0631\u06cc\u0642\u06c1 \u0627\u0633 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0646\u0626\u06cc \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">async verifyRegistration(email: string, response: RegistrationResponseJSON) {\n  const user = await this.userRepository.findOne({\n    where: { email },\n    select: ['id', 'email', 'currentChallenge', 'webauthnId'],\n  });\n\n  if (!user) {\n    throw new UnauthorizedException('User not found');\n  }\n\n  const verification = await verifyRegistrationResponse({\n    response,\n    expectedChallenge: user.currentChallenge,\n    expectedOrigin: this.origin,\n    expectedRPID: this.rpID,\n    requireUserVerification: true,\n  });\n\n  const { verified, registrationInfo } = verification;\n\n  if (verified && registrationInfo) {\n    const { credential, credentialDeviceType, credentialBackedUp } =\n      registrationInfo;\n\n    const newAuthenticator = this.authenticatorRepository.create({\n      credentialId: credential.id,\n      credentialPublicKey: credential.publicKey,\n      counter: credential.counter,\n      user: user,\n      webauthnUserId: user.webauthnId,\n      deviceType: credentialDeviceType,\n      backedUp: credentialBackedUp,\n      transports: response.response.transports,\n    });\n\n    await this.authenticatorRepository.save(newAuthenticator);\n\n    user.currentChallenge = null;\n    await this.userRepository.save(user);\n\n    return {\n      verified,\n      user: { id: user.id, email: user.email },\n    };\n  }\n\n  throw new UnauthorizedException('Registration verification failed');\n}\n<\/code><\/pre>\n<p><code>verifyRegistrationResponse<\/code>    \u06cc\u06c1 \u0622\u067e \u06a9\u06d2 \u06a9\u0648\u0688 \u0645\u06cc\u06ba \u0633\u062e\u062a \u0645\u062d\u0646\u062a \u06a9\u0631 \u0631\u06c1\u0627 \u06c1\u06d2\u06d4 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u06cc\u06ba \u06a9\u06c1 \u0686\u06cc\u0644\u0646\u062c \u0622\u067e \u06a9\u06d2 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u062f\u06c1 \u0633\u06d2 \u0645\u06cc\u0644 \u06a9\u06be\u0627\u062a\u0627 \u06c1\u06d2\u060c \u06a9\u06c1 \u062c\u0648\u0627\u0628 \u0645\u0627\u062e\u0630 \u0627\u0648\u0631 RP IDs \u0633\u06d2 \u0622\u06cc\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u06cc\u06c1 \u06a9\u06c1 \u062f\u0633\u062a\u062e\u0637 \u062f\u0631\u0633\u062a \u06c1\u06d2\u06d4 \u06a9\u06d2 \u0633\u0627\u062a\u06be <code>requireUserVerification: true<\/code> \u0627\u06af\u0631 UV \u067e\u0631\u0686\u0645 \u0633\u06cc\u0679 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2 \u062a\u0648 \u06cc\u06c1 \u062c\u0648\u0627\u0628 \u062f\u06cc\u0646\u06d2 \u0633\u06d2 \u0628\u06be\u06cc \u0627\u0646\u06a9\u0627\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u062c\u06be\u0646\u0688\u0627 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0627 \u062b\u0628\u0648\u062a \u06c1\u06d2 \u06a9\u06c1 \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679\u060c \u0686\u06c1\u0631\u06d2\u060c \u06cc\u0627 \u0627\u0633\u06a9\u0631\u06cc\u0646 \u0644\u0627\u06a9 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06c1\u0648 \u06af\u0626\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06af\u0631 \u0633\u0628 \u06a9\u0686\u06be \u0679\u06be\u06cc\u06a9 \u06c1\u0648 \u062c\u0627\u062a\u0627 \u06c1\u06d2 \u062a\u0648\u060c \u06a9\u0631\u06cc\u0688\u06cc\u0646\u0634\u0644 ID \u0627\u0648\u0631 \u0639\u0648\u0627\u0645\u06cc \u06a9\u0644\u06cc\u062f \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u06cc\u06ba\u060c \u067e\u06be\u0631 \u0686\u06cc\u0644\u0646\u062c \u06a9\u0648 \u0635\u0627\u0641 \u06a9\u0631\u06cc\u06ba \u062a\u0627\u06a9\u06c1 \u0627\u0646\u06c1\u06cc\u06ba \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0646\u06c1 \u06a9\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u06d2\u06d4<\/p>\n<h2 id=\"heading-how-to-sign-in-with-a-passkey-on-the-server\">\u0633\u0631\u0648\u0631 \u067e\u0631 \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0644\u0627\u06af \u0627\u0646 \u06a9\u06cc\u0633\u06d2 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u0644\u0627\u06af \u0627\u0646 \u0627\u0633\u06cc \u0637\u0631\u062d \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u0639\u0646\u06cc \u0622\u067e \u0627\u06cc\u06a9 \u0622\u067e\u0634\u0646 \u062a\u06cc\u0627\u0631 \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u067e\u06be\u0631 \u062c\u0648\u0627\u0628 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-generate-authentication-options\">\u062a\u0635\u062f\u06cc\u0642 \u06a9\u06d2 \u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a \u0628\u0646\u0627\u0626\u06cc\u06ba<\/h3>\n<pre><code class=\"language-typescript\">async generateAuthenticationOptions(\n    email: string,\n): Promise<publickeycredentialrequestoptionsjson> {\n  const user = await this.userRepository.findOne({ where: { email } });\n\n  if (!user) {\n    throw new UnauthorizedException('User not found');\n  }\n\n  const authenticators = await this.authenticatorRepository.find({\n    where: { user: { id: user.id } },\n  });\n\n  if (authenticators.length === 0) {\n    throw new UnauthorizedException(\n      'No passkey registered for this account. Please sign up.',\n    );\n  }\n\n  const options = await generateAuthenticationOptions({\n    rpID: this.rpID,\n    allowCredentials: authenticators.map((authenticator) => ({\n      id: authenticator.credentialId,\n      transports: authenticator.transports,\n    })),\n    userVerification: 'required',\n  });\n\n  \/\/ Save the current challenge\n  user.currentChallenge = options.challenge;\n  await this.userRepository.save(user);\n\n  return options;\n}\n<\/publickeycredentialrequestoptionsjson><\/code><\/pre>\n<p><code>allowCredentials<\/code>    \u0627\u0633 \u0635\u0627\u0631\u0641 \u06a9\u06cc \u0645\u0644\u06a9\u06cc\u062a\u06cc \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u0648\u06ba \u06a9\u06cc \u0641\u06c1\u0631\u0633\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u0628\u0631\u0627\u0624\u0632\u0631 \u0627\u0633 \u0641\u06c1\u0631\u0633\u062a \u06a9\u0648 \u0622\u0644\u06c1 \u067e\u0631 \u0635\u062d\u06cc\u062d \u0641\u06c1\u0631\u0633\u062a \u062a\u0644\u0627\u0634 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <code>transports<\/code> \u0627\u0634\u0627\u0631\u06d2 \u0622\u067e \u06a9\u0648 \u06cc\u06c1 \u0641\u06cc\u0635\u0644\u06c1 \u06a9\u0631\u0646\u06d2 \u0645\u06cc\u06ba \u0645\u062f\u062f \u06a9\u0631\u06cc\u06ba \u06af\u06d2 \u06a9\u06c1 \u0622\u06cc\u0627 \u0627\u0633\u06d2 \u0645\u0642\u0627\u0645\u06cc \u0637\u0648\u0631 \u067e\u0631 \u062f\u06cc\u06a9\u06be\u0646\u0627 \u06c1\u06d2\u060c \u0627\u067e\u0646\u06cc \u0633\u06cc\u06a9\u06cc\u0648\u0631\u0679\u06cc \u06a9\u0644\u06cc\u062f \u0645\u06cc\u06ba\u060c \u06cc\u0627 \u0622\u067e \u06a9\u06d2 \u0641\u0648\u0646 \u067e\u0631\u06d4<\/p>\n<h3 id=\"heading-verify-the-authentication-response\">\u062a\u0635\u062f\u06cc\u0642 \u06a9\u0627 \u062c\u0648\u0627\u0628 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<pre><code class=\"language-typescript\">async verifyAuthentication(\n  email: string,\n  response: AuthenticationResponseJSON,\n) {\n  const user = await this.userRepository.findOne({\n    where: { email },\n    select: ['id', 'email', 'currentChallenge'],\n  });\n\n  if (!user) {\n    throw new UnauthorizedException('User not found');\n  }\n\n  const authenticator = await this.authenticatorRepository.findOne({\n    where: { credentialId: response.id, user: { id: user.id } },\n  });\n\n  if (!authenticator) {\n    throw new UnauthorizedException('Authenticator not found');\n  }\n\n  const verification = await verifyAuthenticationResponse({\n    response,\n    expectedChallenge: user.currentChallenge,\n    expectedOrigin: this.origin,\n    expectedRPID: this.rpID,\n    credential: {\n      id: authenticator.credentialId,\n      publicKey: new Uint8Array(authenticator.credentialPublicKey),\n      counter: Number(authenticator.counter),\n      transports: authenticator.transports,\n    },\n    requireUserVerification: true,\n  });\n\n  const { verified } = verification;\n\n  if (verified) {\n    authenticator.counter = verification.authenticationInfo.newCounter;\n    authenticator.backedUp =\n      verification.authenticationInfo.credentialBackedUp;\n    await this.authenticatorRepository.save(authenticator);\n\n    user.currentChallenge = null;\n    await this.userRepository.save(user);\n\n    \/\/ Generate JWT token\n    const payload = { sub: user.id, email: user.email };\n    return {\n      accessToken: this.jwtService.sign(payload),\n      user: { id: user.id, email: user.email },\n    };\n  }\n\n  throw new UnauthorizedException('Authentication verification failed');\n}\n<\/code><\/pre>\n<p>\u0627\u0633\u062a\u0641\u0633\u0627\u0631 \u0627\u0633\u0646\u0627\u062f \u06a9\u06cc ID \u0627\u0648\u0631 \u0635\u0627\u0631\u0641 ID \u062f\u0648\u0646\u0648\u06ba \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0628\u0631\u0627\u06c1 \u06a9\u0631\u0645 \u0627\u067e\u0646\u06cc \u0635\u0627\u0631\u0641 \u06a9\u06cc \u0634\u0631\u0627\u0626\u0637 \u06a9\u0648 \u062d\u0630\u0641 \u0646\u06c1 \u06a9\u0631\u06cc\u06ba\u06d4 \u0627\u0633 \u06a9\u06cc \u0648\u062c\u0648\u06c1\u0627\u062a \u0633\u06cc\u06a9\u0648\u0631\u0679\u06cc \u0633\u06cc\u06a9\u0634\u0646 \u0645\u06cc\u06ba \u0628\u06cc\u0627\u0646 \u06a9\u06cc \u062c\u0627\u0626\u06cc\u06ba \u06af\u06cc\u06d4<\/p>\n<p>\u06a9\u06c1 <code>Number()<\/code> \u06a9\u06cc\u0648\u0646\u06a9\u06c1 \u06a9\u0627\u0624\u0646\u0679\u0631 \u06a9\u06d2 \u0622\u0633 \u067e\u0627\u0633 \u0641\u0648\u0646 \u06c1\u06cc\u06ba\u06d4 <code>pg<\/code> \u0688\u0631\u0627\u0626\u06cc\u0648\u0631 \u0648\u0627\u067e\u0633 <code>bigint<\/code> \u06a9\u0627\u0644\u0645 \u0679\u0648 \u0633\u0679\u0631\u0646\u06af\u06d4 SimpleWebAuthn \u06a9\u0648 \u0627\u06cc\u06a9 \u0646\u0645\u0628\u0631 \u062f\u0631\u06a9\u0627\u0631 \u06c1\u06d2\u06d4<\/p>\n<p>\u062f\u0633\u062a\u062e\u0637 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06c1\u0648\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f\u060c \u06c1\u0645 \u06a9\u0627\u0624\u0646\u0679\u0631 \u06a9\u0648 \u0628\u0691\u06be\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0686\u06cc\u0644\u0646\u062c \u06a9\u0648 \u0635\u0627\u0641 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 JWT \u062c\u0627\u0631\u06cc \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0627\u0633 \u0648\u0642\u062a \u0633\u06d2\u060c \u0627\u06cc\u067e \u0622\u067e \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0648\u06c1\u06cc \u0633\u0644\u0648\u06a9 \u06a9\u0631\u06d2 \u06af\u06cc \u062c\u0648 \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0644\u0627\u06af \u0627\u0646 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0635\u0627\u0631\u0641 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4 \u0641\u0631\u0642 \u0635\u0631\u0641 \u0627\u062a\u0646\u0627 \u06c1\u06d2 \u06a9\u06c1 \u06a9\u0648\u0626\u06cc \u067e\u0627\u0633 \u0648\u0631\u0688 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0646\u06c1\u06cc\u06ba \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627\u06d4<\/p>\n<h2 id=\"heading-how-to-expose-the-auth-endpoints\">\u062a\u0648\u062b\u06cc\u0642 \u06a9\u06d2 \u0627\u062e\u062a\u062a\u0627\u0645\u06cc \u0646\u0642\u0637\u06c1 \u06a9\u0648 \u06a9\u06cc\u0633\u06d2 \u0628\u06d2 \u0646\u0642\u0627\u0628 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>src\/auth\/auth.controller.ts<\/code>. \u0627\u0633 \u06a9\u06d2 \u067e\u0627\u0633 \u0633\u0627\u0626\u0646 \u0627\u067e \u0627\u0648\u0631 \u0644\u0627\u06af \u0627\u0646 \u06a9\u06d2 \u0628\u06c1\u0627\u0624 \u0645\u06cc\u06ba \u06c1\u0631 \u0642\u062f\u0645 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0631\u0627\u0633\u062a\u06c1 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0627\u06cc\u06a9 \u0645\u062d\u0641\u0648\u0638 \u0631\u0627\u0633\u062a\u06c1 \u062c\u0648 \u0635\u0627\u0631\u0641 \u06a9\u06cc \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u06a9\u0648 \u062f\u0631\u062c \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">import { Controller, Post, Body, Get, Query, UseGuards } from '@nestjs\/common';\nimport { AuthService } from '.\/auth.service';\nimport { JwtAuthGuard } from '.\/guards\/jwt-auth.guard';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(private readonly authService: AuthService) {}\n\n  @Post('register\/options')\n  async getRegistrationOptions(\n    @Body() body: { email: string },\n  ): Promise<publickeycredentialcreationoptionsjson> {\n    return this.authService.generateRegistrationOptions(body.email);\n  }\n\n  @Post('register\/verify')\n  async verifyRegistration(\n    @Body() body: { email: string; response: any },\n  ) {\n    return this.authService.verifyRegistration(body.email, body.response);\n  }\n\n  @Post('login\/options')\n  async getAuthenticationOptions(\n    @Body() body: { email: string },\n  ): Promise<publickeycredentialrequestoptionsjson> {\n    return this.authService.generateAuthenticationOptions(body.email);\n  }\n\n  @Post('login\/verify')\n  async verifyAuthentication(\n    @Body() body: { email: string; response: any },\n  ) {\n    return this.authService.verifyAuthentication(body.email, body.response);\n  }\n\n  @Get('authenticators')\n  @UseGuards(JwtAuthGuard)\n  async getAuthenticators(@Query('email') email: string) {\n    return this.authService.getAuthenticators(email);\n  }\n}\n<\/publickeycredentialrequestoptionsjson><\/publickeycredentialcreationoptionsjson><\/code><\/pre>\n<p>\u06a9\u06c1 <code>response<\/code> \u062c\u0633\u0645 \u0645\u0646\u062f\u0631\u062c\u06c1 \u0630\u06cc\u0644 \u0637\u0648\u0631 \u067e\u0631 \u062f\u0627\u062e\u0644 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2: <code>any<\/code> \u0627\u0633 \u06a9\u06cc \u0648\u062c\u06c1 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u062e\u062f\u0645\u062a \u06a9\u06d2 \u0637\u0631\u06cc\u0642\u06c1 \u06a9\u0627\u0631 \u0646\u06d2 \u067e\u06c1\u0644\u06d2 \u06c1\u06cc \u062f\u0631\u0633\u062a SimpleWebAuthn \u0642\u0633\u0645 \u06a9\u0627 \u0627\u0639\u0644\u0627\u0646 \u06a9\u0631 \u062f\u06cc\u0627 \u06c1\u06d2 \u062c\u0633 \u06a9\u06cc \u0627\u0633\u06d2 \u062a\u0648\u0642\u0639 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-how-to-protect-routes-with-a-jwt\">JWT \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0631\u0627\u0633\u062a\u06d2 \u06a9\u06cc \u062d\u0641\u0627\u0638\u062a \u06a9\u06cc\u0633\u06d2 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u0622\u062e\u0631\u06cc \u0631\u0627\u0633\u062a\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2:<code>JwtAuthGuard<\/code>\u0644\u06c1\u0630\u0627\u060c \u0635\u0631\u0641 \u0644\u0627\u06af \u0627\u0646 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06c1\u06cc \u06a9\u0627\u0644 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0627\u0633 \u06a9\u06cc \u062d\u0645\u0627\u06cc\u062a \u0686\u06be\u0648\u0679\u06d2 \u0633\u0631\u0648\u0633 \u0627\u0646\u062a\u0638\u0627\u0645\u0627\u062a \u0633\u06d2 \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u06d4 \u0627\u0633\u06d2 \u0627\u06af\u0644\u06cc \u0628\u0627\u0631 \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4 <code>AuthService<\/code>:<\/p>\n<pre><code class=\"language-typescript\">async getAuthenticators(email: string) {\n  const user = await this.userRepository.findOne({ where: { email } });\n  if (!user) {\n    throw new UnauthorizedException('User not found');\n  }\n  const authenticators = await this.authenticatorRepository.find({\n    where: { user: { id: user.id } },\n  });\n  return authenticators;\n}\n<\/code><\/pre>\n<p>\u0627\u06af\u0644\u0627\u060c \u06c1\u0645 \u067e\u0627\u0633\u067e\u0648\u0631\u0679 \u06a9\u06cc \u062d\u06a9\u0645\u062a \u0639\u0645\u0644\u06cc \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0648 \u0679\u0648\u06a9\u0646 \u06a9\u0648 \u067e\u0691\u06be\u062a\u0627 \u0627\u0648\u0631 \u0627\u0633 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <code>src\/auth\/strategies\/jwt.strategy.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { Injectable } from '@nestjs\/common';\nimport { ConfigService } from '@nestjs\/config';\nimport { PassportStrategy } from '@nestjs\/passport';\nimport { ExtractJwt, Strategy } from 'passport-jwt';\n\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy) {\n  constructor(private configService: ConfigService) {\n    super({\n      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n      ignoreExpiration: false,\n      secretOrKey: configService.get('JWT_SECRET'),\n    });\n  }\n\n  async validate(payload: any) {\n    return { userId: payload.sub, email: payload.email };\n  }\n}\n<\/code><\/pre>\n<p>\u067e\u06be\u0631 \u0627\u06cc\u06a9 \u06af\u0627\u0631\u0688 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4 <code>src\/auth\/guards\/jwt-auth.guard.ts<\/code>. \u06cc\u06c1 \u067e\u0627\u0633\u067e\u0648\u0631\u0679 \u06a9\u06d2 \u0628\u0644\u0679 \u0627\u0646 \u06af\u0627\u0631\u0688\u0632 \u06a9\u0648 \u0644\u067e\u06cc\u0679\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u06cc\u06a9 \u0648\u0627\u0636\u062d \u063a\u0644\u0637\u06cc \u06a9\u0627 \u067e\u06cc\u063a\u0627\u0645 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">import {\n  ExecutionContext,\n  Injectable,\n  UnauthorizedException,\n} from '@nestjs\/common';\nimport { AuthGuard } from '@nestjs\/passport';\nimport { JsonWebTokenError, TokenExpiredError } from 'jsonwebtoken';\n\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {\n  constructor() {\n    super();\n  }\n\n  handleRequest(err: any, user: any, info: any) {\n    if (info instanceof TokenExpiredError) {\n      throw new UnauthorizedException('Token has expired');\n    }\n\n    if (info instanceof JsonWebTokenError) {\n      throw new UnauthorizedException('Invalid token');\n    }\n\n    if (err || !user) {\n      throw new UnauthorizedException('Authentication failed');\n    }\n\n    return user;\n  }\n\n  \/\/ Optional: Override canActivate if you need custom logic before JWT validation\n  async canActivate(context: ExecutionContext): Promise<boolean> {\n    const request = context.switchToHttp().getRequest();\n\n    const authHeader = request.headers.authorization;\n    if (!authHeader) {\n      throw new UnauthorizedException('No token provided');\n    }\n\n    const [type] = authHeader.split(' ');\n    if (type !== 'Bearer') {\n      throw new UnauthorizedException('Invalid token format');\n    }\n    return super.canActivate(context) as Promise<boolean>;\n  }\n}\n<\/boolean><\/boolean><\/code><\/pre>\n<h3 id=\"heading-how-to-register-the-auth-module\">\u062a\u0635\u062f\u06cc\u0642\u06cc \u0645\u0627\u0688\u06cc\u0648\u0644 \u06a9\u0648 \u06a9\u06cc\u0633\u06d2 \u0631\u062c\u0633\u0679\u0631 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u0622\u062e\u0631 \u0645\u06cc\u06ba\u060c \u0633\u0628 \u06a9\u0686\u06be \u0627\u06cc\u06a9 \u0633\u0627\u062a\u06be \u0631\u06a9\u06be\u0648. <code>src\/auth\/auth.module.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { Module } from '@nestjs\/common';\nimport { ConfigModule, ConfigService } from '@nestjs\/config';\nimport { JwtModule } from '@nestjs\/jwt';\nimport { TypeOrmModule } from '@nestjs\/typeorm';\nimport { AuthController } from '.\/auth.controller';\nimport { AuthService } from '.\/auth.service';\nimport { User, Authenticator } from '.\/entities\/auth.entity';\nimport { JwtStrategy } from '.\/strategies\/jwt.strategy';\n\n@Module({\n  imports: [\n    TypeOrmModule.forFeature([User, Authenticator]),\n    JwtModule.registerAsync({\n      imports: [ConfigModule],\n      useFactory: async (configService: ConfigService) => ({\n        secret: configService.get('JWT_SECRET'),\n        signOptions: {\n          expiresIn: '1d',\n        },\n      }),\n      inject: [ConfigService],\n    }),\n  ],\n  controllers: [AuthController],\n  providers: [AuthService, JwtStrategy],\n})\nexport class AuthModule {}\n<\/code><\/pre>\n<p>\u06a9\u06c1 <code>signOptions<\/code> \u06cc\u06c1 \u0648\u06c1 \u062c\u06af\u06c1 \u06c1\u06d2 \u062c\u06c1\u0627\u06ba \u0622\u067e \u0633\u0631\u0648\u0633 \u06a9\u06d2 \u0645\u0633\u0627\u0626\u0644 \u06a9\u0648 \u0679\u0648\u06a9\u0646 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0644\u06c1\u0630\u0627 \u06c1\u0631 \u0644\u0627\u06af \u0627\u0646 \u0627\u06cc\u06a9 \u062f\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0631\u0633\u062a \u06c1\u06d2\u06d4<\/p>\n<p>\u0633\u0631\u0648\u0631 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba:<\/p>\n<pre><code class=\"language-bash\">npm run start:dev\n<\/code><\/pre>\n<p>TypeORM \u06c1\u06d2\u06d4 <code>user<\/code> \u0627\u0648\u0631 <code>authenticator<\/code> \u0622\u067e \u06a9\u06cc \u0645\u06cc\u0632 <code>auth<\/code> \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0622\u067e pgAdmin \u06a9\u06be\u0648\u0644 \u06a9\u0631 \u0631\u06cc\u0641\u0631\u06cc\u0634 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <strong>\u0645\u06cc\u0632<\/strong> \u0646\u0648\u0688 \u062f\u06cc\u06a9\u06be\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-how-to-set-up-the-nextjs-frontend\">Next.js \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u06a9\u0648 \u06a9\u06cc\u0633\u06d2 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u0627 \u062c\u0627\u0626\u06d2\u06d4<\/h2>\n<p>TypeScript\u060c Tailwind CSS\u060c App Router\u060c \u0627\u0648\u0631 <code>src<\/code> \u0641\u0648\u0644\u0688\u0631:<\/p>\n<pre><code class=\"language-bash\">npx create-next-app@latest client --typescript --tailwind --app --src-dir\ncd client\nnpm install @simplewebauthn\/browser axios\n<\/code><\/pre>\n<p>\u0627\u0636\u0627\u0641\u06c1 <code>.env<\/code> \u0641\u0627\u0626\u0644 <code>client<\/code> API \u06a9\u06cc \u0637\u0631\u0641 \u0627\u0634\u0627\u0631\u06c1 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u0627 \u0641\u0648\u0644\u0688\u0631:<\/p>\n<pre><code class=\"language-bash\">NEXT_PUBLIC_API_URL=http:\/\/localhost:4000\n<\/code><\/pre>\n<p>\u067e\u06be\u0631 \u06c1\u0645 \u0627\u06cc\u06a9 \u0686\u06be\u0648\u0679\u0627 API \u06a9\u0644\u0627\u0626\u0646\u0679 \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>client\/src\/services\/api.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">\/* eslint-disable @typescript-eslint\/no-explicit-any *\/\nimport axios from 'axios';\n\nconst api = axios.create({\n  baseURL: process.env.NEXT_PUBLIC_API_URL,\n  headers: {\n    'Content-Type': 'application\/json',\n  },\n});\n\nexport const webAuthnApi = {\n  getRegistrationOptions: async (email: string) => {\n    const response = await api.post('\/auth\/register\/options', { email });\n    return response.data;\n  },\n\n  verifyRegistration: async (email: string, response: any) => {\n    const res = await api.post('\/auth\/register\/verify', { email, response });\n    return res.data;\n  },\n\n  getAuthenticationOptions: async (email: string) => {\n    const response = await api.post('\/auth\/login\/options', { email });\n    return response.data;\n  },\n\n  verifyAuthentication: async (email: string, response: any) => {\n    const res = await api.post('\/auth\/login\/verify', { email, response });\n    return res.data;\n  },\n};\n\n\/\/ Add request interceptor to include JWT token\napi.interceptors.request.use((config) => {\n  const token = localStorage.getItem('token');\n  if (token) {\n    config.headers.Authorization = `Bearer ${token}`;\n  }\n  return config;\n});\n\nexport default api;\n<\/code><\/pre>\n<p>\u0635\u0627\u0631\u0641 \u06a9\u06d2 \u0644\u0627\u06af \u0627\u0646 \u06c1\u0648\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f \u0646\u06cc\u0686\u06d2 \u0648\u0627\u0644\u0627 \u0627\u0646\u0679\u0631\u0633\u06cc\u067e\u0679\u0631 \u06c1\u0631 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be JWT \u0645\u0646\u0633\u0644\u06a9 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <code>\/auth\/authenticators<\/code> \u0631\u0627\u0633\u062a\u06c1 \u0645\u062a\u0648\u0642\u0639 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-how-to-build-the-sign-up-page\">\u0633\u0627\u0626\u0646 \u0627\u067e \u067e\u06cc\u062c \u06a9\u06cc\u0633\u06d2 \u0628\u0646\u0627\u06cc\u0627 \u062c\u0627\u0626\u06d2\u06d4<\/h2>\n<p>WebAuthn \u06a9\u0627 \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u062d\u0635\u06c1 \u062d\u06cc\u0631\u062a \u0627\u0646\u06af\u06cc\u0632 \u0637\u0648\u0631 \u067e\u0631 \u0645\u062e\u062a\u0635\u0631 \u06c1\u06d2\u06d4 SimpleWebAuthn <code>startRegistration<\/code> \u0641\u0646\u06a9\u0634\u0646 \u0633\u0631\u0648\u0631 \u0633\u06d2 \u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a \u062d\u0627\u0635\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0628\u0631\u0627\u0624\u0632\u0631 \u06a9\u06d2 WebAuthn API \u06a9\u0648 \u06a9\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 JSON \u0641\u0627\u0631\u0645\u06cc\u0679 \u0645\u06cc\u06ba \u062c\u0648\u0627\u0628 \u062f\u06cc\u062a\u0627 \u06c1\u06d2 \u062c\u0633\u06d2 \u0633\u0631\u0648\u0631 \u0633\u0645\u062c\u06be \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>client\/src\/app\/signup\/page.tsx<\/code>:<\/p>\n<pre><code class=\"language-tsx\">\/* eslint-disable @typescript-eslint\/no-explicit-any *\/\n'use client';\n\nimport React, { useState } from 'react';\nimport { startRegistration, browserSupportsWebAuthn } from '@simplewebauthn\/browser';\nimport { webAuthnApi } from '@\/services\/api';\nimport { getPasskeyErrorMessage } from '@\/services\/passkey';\nimport Link from 'next\/link';\nimport { useRouter } from 'next\/navigation';\n\nexport default function SignupPage() {\n  const [email, setEmail] = useState('');\n  const [loading, setLoading] = useState(false);\n  const [error, setError] = useState('');\n  const router = useRouter();\n\n  const handleRegistration = async (e: React.FormEvent) => {\n    e.preventDefault();\n    setLoading(true);\n    setError('');\n\n    if (!browserSupportsWebAuthn()) {\n      setError('This browser does not support passkeys.');\n      setLoading(false);\n      return;\n    }\n\n    try {\n      const options = await webAuthnApi.getRegistrationOptions(email);\n\n      const regResult = await startRegistration({ optionsJSON: options });\n\n      const verificationResult = await webAuthnApi.verifyRegistration(email, regResult);\n\n      if (verificationResult.verified) {\n        router.push('\/welcome');\n      }\n    } catch (err: any) {\n      console.error('Registration error:', err);\n      setError(getPasskeyErrorMessage(err, 'Registration failed. Please try again.'));\n    } finally {\n      setLoading(false);\n    }\n  };\n\n  return (\n    <main classname=\"min-h-screen flex items-center justify-center bg-gray-300\">\n      <div classname=\"bg-white p-8 rounded-lg shadow-sm w-full max-w-md\">\n        <div classname=\"space-y-6\">\n          \n\n          <form onsubmit=\"{handleRegistration}\" classname=\"space-y-4\">\n            <p>\n              <label htmlfor=\"email\" classname=\"block text-sm font-medium text-gray-700\">\n                Email\n              <\/label>\n              <input id=\"email\" type=\"email\" required=\"\" value=\"{email}\" onchange=\"{(e)\"\/> setEmail(e.target.value)}\n                className=\"w-full px-3 py-2 border border-gray-200 rounded-md text-sm placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent\"\n                placeholder=\"Type your email\"\n              \/>\n            <\/p>\n\n            {error && (\n              <p>\n                {error}\n              <\/p>\n            )}\n\n            <button type=\"submit\" disabled=\"{loading}\" classname=\"w-full flex justify-center py-2.5 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-[#3B97B6] hover:bg-[#2d7591] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 transition-colors\">\n              {loading ? 'Creating passkey...' : 'Create a passkey'}\n            <\/button>\n            <p classname=\"text-xs text-center text-gray-500\">\n              You'll confirm with your fingerprint, face, or screen lock.\n            <\/p>\n          <\/form>\n\n          <p>\n            <span classname=\"text-gray-600\">Already have an account?<\/span>{' '}\n            <link href=\"https:\/\/www.freecodecamp.org\/signin\" classname=\"text-[#3B97B6] hover:text-[#2d7591] font-medium transition-colors\"\/>\n              Sign in\n            \n          <\/p>\n        <\/div>\n      <\/div>\n    <\/main>\n  );\n}\n<\/code><\/pre>\n<p>\u06a9\u06c1 <code>handleRegistration<\/code> \u0641\u0646\u06a9\u0634\u0646 \u067e\u0686\u06be\u0644\u06d2 \u062a\u06cc\u0646 \u0645\u0631\u0627\u062d\u0644 \u06a9\u06cc \u067e\u06cc\u0631\u0648\u06cc \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0633\u0631\u0648\u0631 \u0633\u06d2 \u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a \u062d\u0627\u0635\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0646\u06c1\u06cc\u06ba \u0633\u0631\u0648\u0631 \u062a\u06a9 \u067e\u06c1\u0646\u0686\u0627\u062a\u0627 \u06c1\u06d2\u06d4<code>startRegistration<\/code>\u062a\u0635\u062f\u06cc\u0642 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0646\u062a\u0627\u0626\u062c \u0648\u0627\u067e\u0633 \u0628\u06be\u06cc\u062c\u06cc\u06ba\u06d4<\/p>\n<p>\u06a9\u0627\u0644 \u06a9\u0631\u06cc\u06ba <code>startRegistration<\/code> \u06cc\u06c1 \u0648\u06c1 \u062c\u06af\u06c1 \u06c1\u06d2 \u062c\u06c1\u0627\u06ba \u062c\u0627\u062f\u0648 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0628\u0631\u0627\u0624\u0632\u0631 \u0622\u067e\u0631\u06cc\u0679\u0646\u06af \u0633\u0633\u0679\u0645 \u06a9\u0627 \u067e\u0627\u0633 \u06a9\u06cc \u0688\u0627\u0626\u06cc\u0644\u0627\u06af \u06a9\u06be\u0648\u0644\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0635\u0627\u0631\u0641 Touch ID\u060c Face ID\u060c Windows Hello\u060c \u06cc\u0627 \u0627\u067e\u0646\u06d2 \u0641\u0648\u0646 \u0633\u06d2 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0622\u067e \u06a9\u0627 \u06a9\u0648\u0688 \u0648\u0639\u062f\u06c1 \u06a9\u06d2 \u062d\u0644 \u06c1\u0648\u0646\u06d2 \u06a9\u0627 \u0627\u0646\u062a\u0638\u0627\u0631 \u06a9\u0631 \u0631\u06c1\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0628\u0631\u0627\u06c1 \u06a9\u0631\u0645 \u0627\u0633 \u06a9\u0627 \u062d\u0648\u0627\u0644\u06c1 \u062f\u06cc\u06ba\u06d4 <code>{ optionsJSON: options }<\/code> \u062a\u0646\u0627\u0632\u0639\u06c1 SimpleWebAuthn \u06a9\u06d2 \u067e\u0631\u0627\u0646\u06d2 \u0648\u0631\u0698\u0646 \u0646\u06d2 \u0622\u067e\u0634\u0646 \u06a9\u0648 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0642\u0628\u0648\u0644 \u06a9\u06cc\u0627\u060c \u0627\u0648\u0631 \u0628\u06c1\u062a \u0633\u06d2 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644\u0632 \u0627\u0628 \u0628\u06be\u06cc \u0627\u0633\u06d2 \u0627\u0633\u06cc \u0637\u0631\u062d \u067e\u06cc\u0634 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0648\u0631\u0698\u0646 13 \u0627\u0628 \u0628\u06be\u06cc \u067e\u0631\u0627\u0646\u06d2 \u0637\u0631\u0632 \u06a9\u06cc \u062d\u0645\u0627\u06cc\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0627\u06cc\u06a9 \u0627\u0646\u062a\u0628\u0627\u06c1 \u0644\u0627\u06af \u0627\u0646 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06c1\u0630\u0627 \u0622\u0628\u062c\u06cc\u06a9\u0679 \u06a9\u06cc \u0642\u0633\u0645 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-how-to-build-the-sign-in-page\">\u0644\u0627\u06af \u0627\u0646 \u067e\u06cc\u062c \u06a9\u06cc\u0633\u06d2 \u0628\u0646\u0627\u06cc\u0627 \u062c\u0627\u0626\u06d2\u06d4<\/h2>\n<p>\u06a9\u06c1 <code>Sign in<\/code> \u0635\u0641\u062d\u06c1 \u06c1\u06d2\u06d4 <code>Sign up<\/code> \u0635\u0641\u062d\u06c1 \u0628\u0646\u0627\u0646\u0627 <code>client\/src\/app\/signin\/page.tsx<\/code>\u0633\u0627\u0626\u0646 \u0627\u067e \u0635\u0641\u062d\u06c1 \u06a9\u0648 \u06a9\u0627\u067e\u06cc \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u0646\u06cc\u0686\u06d2 \u06a9\u06cc \u0637\u0631\u0641 \u0627\u0634\u0627\u0631\u06c1 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0639\u0646\u0648\u0627\u0646 \u0627\u0648\u0631 \u0644\u0646\u06a9 \u06a9\u0648 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u06cc\u06ba: <code>\/signup<\/code>. \u067e\u06be\u0631 \u062f\u0631\u0622\u0645\u062f \u06a9\u0631\u06cc\u06ba\u06d4 <code>startAuthentication<\/code> \u0627\u0633 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 <code>startRegistration<\/code>\u062c\u0645\u0639 \u06a9\u0631\u0627\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u06a9\u0648 \u062f\u0631\u062c \u0630\u06cc\u0644 \u06c1\u06cc\u0646\u0688\u0644\u0631 \u0633\u06d2 \u0628\u062f\u0644\u06cc\u06ba:<\/p>\n<pre><code class=\"language-tsx\">const handleAuthentication = async (e: React.FormEvent) => {\n  e.preventDefault();\n  setLoading(true);\n  setError('');\n\n  if (!browserSupportsWebAuthn()) {\n    setError('This browser does not support passkeys.');\n    setLoading(false);\n    return;\n  }\n\n  try {\n    const options = await webAuthnApi.getAuthenticationOptions(email);\n\n    const authResult = await startAuthentication({ optionsJSON: options });\n\n    const verificationResult = await webAuthnApi.verifyAuthentication(email, authResult);\n\n    if (verificationResult.accessToken) {\n      localStorage.setItem('token', verificationResult.accessToken);\n      router.push('\/welcome');\n    }\n  } catch (err: any) {\n    console.error('Authentication error:', err);\n    setError(getPasskeyErrorMessage(err, 'Authentication failed. Please try again.'));\n  } finally {\n    setLoading(false);\n  }\n};\n<\/code><\/pre>\n<p>\u067e\u0627\u0633 \u06a9\u0631\u0646\u0627 \u06cc\u0627\u062f \u0631\u06a9\u06be\u06cc\u06ba <code>handleAuthentication<\/code> \u0641\u0627\u0631\u0645 \u067e\u0631 <code>onSubmit<\/code>. \u0622\u067e \u06c1\u0645\u0627\u0631\u06d2 GitHub \u0630\u062e\u06cc\u0631\u06c1 \u0645\u06cc\u06ba \u0645\u06a9\u0645\u0644 \u0635\u0641\u062d\u06c1 \u062f\u06cc\u06a9\u06be \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u06af\u0631 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0627\u0645\u06cc\u0627\u0628 \u06c1\u0648 \u062c\u0627\u062a\u06cc \u06c1\u06d2\u060c \u062a\u0648 \u0633\u0631\u0648\u0631 JWT \u0648\u0627\u067e\u0633 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0635\u0641\u062d\u06c1 JWT \u06a9\u0648 \u0631\u06cc \u0688\u0627\u0626\u0631\u06cc\u06a9\u0679 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0627\u0633\u0679\u0648\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0679\u0648\u06a9\u0646 \u0627\u0633\u0679\u0648\u0631\u06cc\u062c <code>localStorage<\/code> \u0622\u0626\u06cc\u06d2 \u0627\u0633 \u0688\u06cc\u0645\u0648 \u06a9\u0648 \u0633\u0627\u062f\u06c1 \u0631\u06a9\u06be\u06cc\u06ba\u06d4 \u067e\u0631\u0648\u0688\u06a9\u0634\u0646 \u0627\u06cc\u067e\u0633 \u0645\u06cc\u06ba <code>httpOnly<\/code> \u0633\u0631\u0648\u0631 \u06a9\u06cc \u0637\u0631\u0641 \u0633\u06d2 \u0633\u06cc\u0679 \u06a9\u06cc \u06af\u0626\u06cc \u06a9\u0648\u06a9\u06cc\u0632 \u0627\u06cc\u06a9 \u0645\u062d\u0641\u0648\u0638 \u0627\u0646\u062a\u062e\u0627\u0628 \u06c1\u06cc\u06ba \u06a9\u06cc\u0648\u0646\u06a9\u06c1 \u0648\u06c1 \u0635\u0641\u062d\u06c1 \u067e\u0631 \u0686\u0644\u0646\u06d2 \u0648\u0627\u0644\u06d2 JavaScript \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0646\u06c1\u06cc\u06ba \u067e\u0691\u06be \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/10\/1793133225_163_WebAuthn\u060c-Nextjs\u060c-\u0627\u0648\u0631-NestJS-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644-\u06a9\u0631\u062a\u06d2-\u06c1\u0648\u0626\u06d2-\u062e\u0641\u06cc\u06c1-\u06a9\u0644\u06cc\u062f.png\" alt=\"\u0622\u067e\u0631\u06cc\u0679\u0646\u06af \u0633\u0633\u0679\u0645 \u067e\u0627\u0633\u06a9\u06cc \u067e\u0631\u0627\u0645\u067e\u0679 \u0635\u0627\u0631\u0641 \u0633\u06d2 \u0679\u0686 \u0622\u0626\u06cc \u0688\u06cc \u06a9\u06d2 \u0633\u0627\u062a\u06be \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u0646\u06d2 \u06a9\u0648 \u06a9\u06c1\u062a\u0627 \u06c1\u06d2\u06d4\" style=\"display: block;\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<h2 id=\"heading-how-to-show-helpful-error-messages\">\u06a9\u0627\u0631\u0622\u0645\u062f \u0627\u06cc\u0631\u0631 \u0645\u06cc\u0633\u06cc\u062c\u0632 \u06a9\u0648 \u06a9\u06cc\u0633\u06d2 \u0688\u0633\u067e\u0644\u06d2 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u0627\u06af\u0631 \u0627\u0646\u06a9\u0631\u067e\u0634\u0646 \u06a9\u0644\u06cc\u062f\u06cc \u0645\u0634\u0642 \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646 \u06a9\u0648\u0626\u06cc \u0645\u0633\u0626\u0644\u06c1 \u067e\u06cc\u0634 \u0622\u062c\u0627\u0626\u06d2 \u062a\u0648 \u0628\u0631\u0627\u0624\u0632\u0631 <code>DOMException<\/code> \u0627\u0648\u0631 <code>name<\/code> \u06cc\u06c1 \u0622\u067e \u06a9\u0648 \u0628\u062a\u0627\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u06a9\u06cc\u0627 \u06c1\u0648\u0627 \u06c1\u06d2\u06d4 \u062e\u0627\u0645 \u067e\u06cc\u063a\u0627\u0645\u0627\u062a \u0628\u06c1\u062a \u062f\u0648\u0633\u062a\u0627\u0646\u06c1 \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0644\u06c1\u0630\u0627 \u0639\u0627\u0645 \u067e\u06cc\u063a\u0627\u0645\u0627\u062a \u06a9\u0627 \u062a\u0631\u062c\u0645\u06c1 \u06a9\u0631\u0646\u0627 \u0627\u0686\u06be\u0627 \u062e\u06cc\u0627\u0644 \u06c1\u06d2\u06d4<\/p>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>client\/src\/services\/passkey.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">\/* eslint-disable @typescript-eslint\/no-explicit-any *\/\n\n\/\/ Turn errors from the browser's WebAuthn API and our backend into readable messages\nexport function getPasskeyErrorMessage(err: any, fallback: string): string {\n  if (err?.response?.data?.message) {\n    return err.response.data.message;\n  }\n  switch (err?.name) {\n    case 'NotAllowedError':\n      \/\/ User cancelled the fingerprint\/face\/screen-lock prompt, or it timed out\n      return 'The passkey prompt was cancelled or timed out. Please try again.';\n    case 'InvalidStateError':\n      \/\/ A passkey for this account already exists on this authenticator\n      return 'This device already has a passkey for this account. Please sign in instead.';\n    case 'NotSupportedError':\n      return 'This device does not support passkeys.';\n    case 'SecurityError':\n      return 'Passkeys are not allowed on this domain. Check the WebAuthn RP ID and origin settings.';\n    default:\n      return fallback;\n  }\n}\n<\/code><\/pre>\n<p><code>NotAllowedError<\/code>    \u06cc\u06c1 \u0648\u06c1\u06cc \u06c1\u06d2 \u062c\u0648 \u0622\u067e \u0633\u0628 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u062f\u06cc\u06a9\u06be\u06cc\u06ba \u06af\u06d2\u06d4 \u0641\u0627\u0626\u0631 \u0627\u0633 \u0648\u0642\u062a \u06c1\u0648\u062a\u0627 \u06c1\u06d2 \u062c\u0628 \u0635\u0627\u0631\u0641 \u067e\u0631\u0627\u0645\u067e\u0679 \u0628\u0646\u062f \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0628\u06c1\u062a \u0632\u06cc\u0627\u062f\u06c1 \u0627\u0646\u062a\u0638\u0627\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u06cc\u0627 \u0628\u0627\u0626\u06cc\u0648 \u0645\u06cc\u0679\u0631\u06a9 \u0686\u06cc\u06a9 \u0645\u06cc\u06ba \u0646\u0627\u06a9\u0627\u0645 \u06c1\u0648\u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>SecurityError<\/code> \u0627\u0633 \u06a9\u0627 \u0639\u0627\u0645 \u0637\u0648\u0631 \u067e\u0631 \u0645\u0637\u0644\u0628 \u06cc\u06c1 \u06c1\u0648\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 RP ID \u0627\u0633 \u0688\u0648\u0645\u06cc\u0646 \u0633\u06d2 \u0645\u0645\u0627\u062b\u0644 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2 \u062c\u0633 \u067e\u0631 \u0635\u0641\u062d\u06c1 \u0686\u0644 \u0631\u06c1\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u06a9\u0646\u0641\u06cc\u06af\u0631\u06cc\u0634\u0646 \u06a9\u0627 \u0645\u0633\u0626\u0644\u06c1 \u06c1\u06d2\u060c \u0635\u0627\u0631\u0641 \u06a9\u0627 \u0645\u0633\u0626\u0644\u06c1 \u0646\u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-how-to-test-your-app\">\u0627\u067e\u0646\u06cc \u0627\u06cc\u067e \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u06cc\u0633\u06d2 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u062f\u0648\u0646\u0648\u06ba \u0627\u06cc\u067e\u0633 \u06a9\u0648 \u0627\u0644\u06af \u0627\u0644\u06af \u0679\u0631\u0645\u06cc\u0646\u0644\u0632 \u0645\u06cc\u06ba \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-bash\"># Terminal 1\ncd server\nnpm run start:dev\n<\/code><\/pre>\n<pre><code class=\"language-bash\"># Terminal 2\ncd client\nnpm run dev\n<\/code><\/pre>\n<p>\u062a\u062d\u0631\u06cc\u06a9 <code>http:\/\/localhost:3000\/signup<\/code>\u0627\u067e\u0646\u0627 \u0627\u06cc \u0645\u06cc\u0644 \u062f\u0631\u062c \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u0628\u0679\u0646 \u067e\u0631 \u06a9\u0644\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4 \u0622\u067e \u06a9\u0627 \u0622\u0644\u06c1 \u0622\u067e \u06a9\u0648 \u067e\u0627\u0633 \u06a9\u06cc \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0634\u0627\u0631\u06c1 \u06a9\u0631\u06d2 \u06af\u0627\u06d4 Touch ID \u06a9\u0648 \u0633\u067e\u0648\u0631\u0679 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u06d2 Macs \u067e\u0631\u060c \u0622\u067e \u06a9\u0648 \u0633\u06cc\u0646\u0633\u0631 \u06a9\u0648 \u0686\u06be\u0648\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u06c1\u0627 \u062c\u0627\u0626\u06d2 \u06af\u0627\u06d4 \u0628\u0635\u0648\u0631\u062a \u062f\u06cc\u06af\u0631\u060c \u0622\u067e \u06a9\u0648 \u0627\u067e\u0646\u06d2 MacBook \u0635\u0627\u0631\u0641 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0641\u0627\u0631\u0645 \u067e\u064f\u0631 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u06af\u06cc\u06d4 Windows \u0645\u06cc\u06ba\u060c Windows Hello \u0622\u067e \u06a9\u06d2 \u0686\u06c1\u0631\u06d2\u060c \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679\u060c \u06cc\u0627 PIN \u06a9\u06d2 \u0628\u0627\u0631\u06d2 \u0645\u06cc\u06ba \u067e\u0648\u0686\u06be\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u06af\u0631 \u0622\u067e \u06a9\u0648\u0626\u06cc \u062f\u0648\u0633\u0631\u0627 \u0622\u0644\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062a\u0648 \u0622\u067e \u06a9\u0627 \u0628\u0631\u0627\u0624\u0632\u0631 \u0627\u06cc\u06a9 QR \u06a9\u0648\u0688 \u062f\u06a9\u06be\u0627\u0626\u06d2 \u06af\u0627 \u062c\u0633\u06d2 \u0622\u067e \u0627\u067e\u0646\u06d2 \u0641\u0648\u0646 \u0633\u06d2 \u0627\u0633\u06a9\u06cc\u0646 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u062a\u0635\u062f\u06cc\u0642 \u06c1\u0648\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f\u060c \u0627\u06cc\u06a9 \u062e\u0648\u0634 \u0622\u0645\u062f\u06cc\u062f \u0635\u0641\u062d\u06c1 \u0638\u0627\u06c1\u0631 \u06c1\u0648 \u06af\u0627\u06d4 \u0627\u0628 \u062c\u0627\u0626\u06cc\u06ba: <code>\/signin<\/code>\u0628\u0631\u0627\u06c1 \u06a9\u0631\u0645 \u0648\u06c1\u06cc \u0627\u06cc \u0645\u06cc\u0644 \u062f\u0631\u062c \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4 \u0627\u0633 \u0628\u0627\u0631 \u0633\u0631\u0648\u0631 JWT \u0648\u0627\u067e\u0633 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06af\u0631 \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u067e\u0627\u0633 \u06a9\u0644\u06cc\u062f \u0633\u06d2 \u0686\u0644\u0646\u06d2 \u0648\u0627\u0644\u0627 \u0622\u0644\u06c1 \u062f\u0633\u062a\u06cc\u0627\u0628 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2 \u062a\u0648\u060c \u06a9\u0631\u0648\u0645 \u06a9\u06d2 \u067e\u0627\u0633 \u0628\u0644\u0679 \u0627\u0646 \u0648\u0631\u0686\u0648\u0626\u0644 \u0622\u062a\u06be\u0646\u0679\u06cc\u06a9\u06cc\u0679\u0631 \u06c1\u06d2\u06d4 DevTools \u06a9\u06be\u0648\u0644\u06cc\u06ba\u060c \u067e\u06be\u0631 \u062a\u06be\u0631\u06cc \u0688\u0627\u0679 \u0645\u06cc\u0646\u0648 \u067e\u0631 \u06a9\u0644\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4 <strong>\u0645\u0632\u06cc\u062f \u0627\u0648\u0632\u0627\u0631<\/strong> \u0627\u0648\u0631 \u0645\u0646\u062a\u062e\u0628 \u06a9\u0631\u06cc\u06ba <strong>\u0648\u06cc\u0628 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642<\/strong>. \u0648\u0631\u0686\u0648\u0626\u0644 \u0645\u0633\u062a\u0646\u062f \u0645\u0627\u062d\u0648\u0644 \u06a9\u0648 \u0641\u0639\u0627\u0644 \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u0645\u0633\u062a\u0646\u062f \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba: <strong>&quot;\u0635\u0627\u0631\u0641 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u06cc \u062d\u0645\u0627\u06cc\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2&#8221;<\/strong> \u062a\u0635\u062f\u06cc\u0642 \u0634\u062f\u06c1\u06d4 \u0627\u0633 \u06a9\u06d2 \u0628\u0639\u062f \u06a9\u0631\u0648\u0645 \u0627\u06cc\u06a9 \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u06cc \u0688\u06cc\u0648\u0627\u0626\u0633 \u06a9\u06cc \u062a\u0642\u0644\u06cc\u062f \u06a9\u0631\u06d2 \u06af\u0627\u06d4<\/p>\n<p>\u0622\u067e pgAdmin \u0628\u06be\u06cc \u06a9\u06be\u0648\u0644 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u062f\u06cc\u06a9\u06be \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba: <code>authenticator<\/code> \u0645\u06cc\u0632 \u0622\u067e \u06a9\u0648 \u06a9\u0631\u06cc\u0688\u06cc\u0646\u0634\u0644 \u0622\u0626\u06cc \u0688\u06cc\u060c \u0628\u0627\u0626\u0679\u0633 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u062f\u06c1 \u0639\u0648\u0627\u0645\u06cc \u06a9\u0644\u06cc\u062f \u0627\u0648\u0631 \u0688\u06cc\u0648\u0627\u0626\u0633 \u06a9\u06cc \u0642\u0633\u0645 \u0646\u0638\u0631 \u0622\u0626\u06d2 \u06af\u06cc\u06d4 \u06a9\u0648\u0626\u06cc \u067e\u0627\u0633 \u0648\u0631\u0688 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u060c \u06a9\u0648\u0626\u06cc \u0631\u0627\u0632 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-security-mistakes-to-avoid\">\u062d\u0641\u0627\u0638\u062a\u06cc \u063a\u0644\u0637\u06cc\u0648\u06ba \u0633\u06d2 \u0628\u0686\u0646\u0627 \u06c1\u06d2\u06d4<\/h2>\n<p>\u0627\u06af\u0631\u0686\u06c1 \u067e\u0627\u0633 \u06a9\u06cc\u0632 \u0688\u06cc\u0632\u0627\u0626\u0646 \u06a9\u06d2 \u0644\u062d\u0627\u0638 \u0633\u06d2 \u0645\u062d\u0641\u0648\u0638 \u06c1\u06cc\u06ba\u060c \u0644\u06cc\u06a9\u0646 \u0627\u0646 \u06a9\u06d2 \u0627\u0631\u062f \u06af\u0631\u062f \u06a9\u0627 \u0633\u0631\u0648\u0631 \u06a9\u0648\u0688 \u0627\u0628 \u0628\u06be\u06cc \u062f\u0631\u0633\u062a \u06c1\u0648\u0646\u0627 \u0636\u0631\u0648\u0631\u06cc \u06c1\u06d2\u06d4 \u0627\u0633 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u06a9\u06cc \u062a\u0639\u0645\u06cc\u0631 \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646\u060c \u0645\u06cc\u06ba \u0646\u06d2 \u0630\u06cc\u0644 \u0645\u06cc\u06ba \u0633\u06d2 \u06c1\u0631 \u0627\u06cc\u06a9 \u06a9\u0627 \u0633\u0627\u0645\u0646\u0627 \u06a9\u06cc\u0627\u06d4 \u0627\u0646 \u0645\u06cc\u06ba \u0633\u06d2 \u06a9\u0686\u06be \u062e\u0637\u0631\u0646\u0627\u06a9 \u06c1\u06cc\u06ba \u06a9\u06cc\u0648\u0646\u06a9\u06c1 \u0648\u06c1 \u063a\u0644\u0637\u06cc\u0627\u06ba \u0646\u06c1\u06cc\u06ba \u067e\u06be\u06cc\u0646\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-encoding-the-credential-id-twice\">\u0627\u0633\u0646\u0627\u062f \u06a9\u06cc \u0634\u0646\u0627\u062e\u062a \u06a9\u0648 \u062f\u0648 \u0628\u0627\u0631 \u0627\u0646\u06a9\u0648\u0688 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u062a\u0627\u0632\u06c1 \u062a\u0631\u06cc\u0646 \u0648\u0631\u0698\u0646 \u0645\u06cc\u06ba <strong>\u0633\u0627\u062f\u06c1 \u0648\u06cc\u0628 \u062a\u0635\u062f\u06cc\u0642<\/strong>\u06cc\u06c1\u0627\u06ba \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u0634\u062f\u06c1 \u0648\u0631\u0698\u0646 14 \u0633\u0645\u06cc\u062a\u06d4 <code>credential.id<\/code> \u06cc\u06c1 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u06c1\u06cc \u0627\u06cc\u06a9 base64url \u0633\u0679\u0631\u0646\u06af \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0645\u06cc\u0631\u0627 \u067e\u06c1\u0644\u0627 \u06a9\u0648\u0688 \u0648\u0631\u0698\u0646 \u06c1\u06d2:<\/p>\n<pre><code class=\"language-typescript\">\/\/ Wrong: encodes an already-encoded string\ncredentialId: Buffer.from(credential.id).toString('base64url'),\n<\/code><\/pre>\n<p><code>Buffer.from<\/code>    \u0686\u0648\u0646\u06a9\u06c1 \u0627\u0633\u0679\u0631\u0646\u06af \u06a9\u0648 UTF-8 \u0679\u06cc\u06a9\u0633\u0679 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0633\u0645\u062c\u06be\u0627 \u062c\u0627 \u0631\u06c1\u0627 \u06c1\u06d2\u060c \u0627\u0633 \u06a9\u0627 \u0646\u062a\u06cc\u062c\u06c1 base64url \u0633\u0679\u0631\u0646\u06af \u06a9\u06cc \u0627\u06cc\u06a9 base64url \u0627\u0646\u06a9\u0648\u0688\u0646\u06af \u06c1\u06d2\u06d4 \u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u0627\u0645\u06cc\u0627\u0628 \u0631\u06c1\u06cc\u060c \u0644\u06cc\u06a9\u0646 \u0644\u0627\u06af \u0627\u0646 \u06a9\u0631\u062a\u06d2 \u0648\u0642\u062a \u0622\u067e \u06a9\u06cc \u0627\u0633\u0646\u0627\u062f \u0646\u06c1\u06cc\u06ba \u0645\u0644 \u0633\u06a9\u062a\u06cc\u06ba \u06a9\u06cc\u0648\u0646\u06a9\u06c1 \u0628\u0631\u0627\u0624\u0632\u0631 \u0627\u0635\u0644 ID \u0628\u06be\u06cc\u062c\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0633\u0679\u0648\u0631 <code>credential.id<\/code> \u0627\u0633 \u0637\u0631\u062d<\/p>\n<h3 id=\"heading-clearing-the-challenge-with-undefined\">\u062e\u0627\u0645 \u0686\u06cc\u0644\u0646\u062c \u06a9\u0648 \u0635\u0627\u0641 \u06a9\u0631\u06cc\u06ba\u06d4 <code>undefined<\/code><\/h3>\n<p>\u062a\u0645\u0627\u0645 \u0686\u06cc\u0644\u0646\u062c\u0632 \u06a9\u0648 \u0635\u0631\u0641 \u0627\u06cc\u06a9 \u0628\u0627\u0631 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc\u0627 \u062c\u0627\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4 \u0627\u06cc\u0633\u0627 \u0644\u06af\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u06cc\u06c1 \u0644\u0627\u0626\u0646 \u0627\u0633\u06d2 \u0635\u0627\u0641 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-typescript\">user.currentChallenge = undefined;\n<\/code><\/pre>\n<p>\u062a\u0627\u06c1\u0645\u060c TypeORM \u06a9\u0648 \u0686\u06be\u0648\u0691 \u062f\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4 <code>undefined<\/code> \u062c\u0628 \u0622\u067e \u06a9\u0633\u06cc \u06c1\u0633\u062a\u06cc \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062a\u0648 \u0622\u067e \u0627\u0633 \u06a9\u06cc \u062e\u0635\u0648\u0635\u06cc\u0627\u062a \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0633 \u0644\u06cc\u06d2 \u067e\u0686\u06be\u0644\u06d2 \u0686\u06cc\u0644\u0646\u062c\u0632 \u0688\u06cc\u0679\u0627 \u0628\u06cc\u0633 \u0645\u06cc\u06ba \u06c1\u06cc \u0631\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06a9\u0648\u0626\u06cc \u0628\u06be\u06cc \u062c\u0648 \u062f\u0631\u0633\u062a \u062c\u0648\u0627\u0628 \u062d\u0627\u0635\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0648\u06c1 \u0627\u0633\u06d2 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0686\u0644\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 \u0642\u062f\u0631 \u06a9\u0648 \u0627\u0633 \u067e\u0631 \u0633\u06cc\u0679 \u06a9\u0631\u06cc\u06ba: <code>null<\/code> \u0627\u0633 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba \u06a9\u06c1 \u0622\u06cc\u0627 \u0622\u067e \u06a9\u06d2 \u06a9\u0627\u0644\u0645 \u06a9\u06cc \u0642\u0633\u0645 \u0627\u0633 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-looking-up-a-credential-without-checking-its-owner\">\u0645\u0627\u0644\u06a9 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u0627\u0633\u0646\u0627\u062f \u06a9\u06cc \u062a\u0644\u0627\u0634<\/h3>\n<p>\u06c1\u0645 \u0635\u0631\u0641 \u06a9\u0631\u06cc\u0688\u06cc\u0646\u0634\u0644 ID \u06a9\u06cc \u0628\u0646\u06cc\u0627\u062f \u067e\u0631 \u0627\u06cc\u06a9 \u0645\u0633\u062a\u0646\u062f \u062a\u0644\u0627\u0634 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u062a\u062c\u0648\u06cc\u0632 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-typescript\">\/\/ Wrong: any user's passkey matches\nwhere: { credentialId: response.id }\n<\/code><\/pre>\n<p><strong>\u0644\u06cc\u06a9\u0646 \u0645\u0633\u0626\u0644\u06c1 \u06cc\u06c1 \u06c1\u06d2:<\/strong> \u062d\u0645\u0644\u06c1 \u0622\u0648\u0631 \u0622\u067e \u06a9\u06d2 \u0627\u06cc \u0645\u06cc\u0644 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0644\u0627\u06af \u0627\u0646 \u06a9\u06d2 \u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u067e\u0646\u06cc \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u0633\u06d2 \u0686\u06cc\u0644\u0646\u062c \u067e\u0631 \u062f\u0633\u062a\u062e\u0637 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u067e\u06be\u0631 \u0633\u0631\u0648\u0631 \u062d\u0645\u0644\u06c1 \u0622\u0648\u0631 \u06a9\u06cc \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0639\u0648\u0627\u0645\u06cc \u06a9\u0644\u06cc\u062f \u06a9\u06d2 \u062e\u0644\u0627\u0641 \u062f\u0633\u062a\u062e\u0637 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0627\u06a9\u0627\u0624\u0646\u0679 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0679\u0648\u06a9\u0646 \u062c\u0627\u0631\u06cc \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u067e\u0686\u06be\u0644\u06cc \u0645\u062b\u0627\u0644 \u06a9\u06d2 \u0628\u0639\u062f\u060c \u06c1\u0645 \u06c1\u0645\u06cc\u0634\u06c1 \u0635\u0627\u0631\u0641 \u06a9\u0648 \u0627\u0633\u062a\u0641\u0633\u0627\u0631 \u0645\u06cc\u06ba \u0634\u0627\u0645\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-letting-sign-up-add-passkeys-to-existing-accounts\">\u0633\u0627\u0626\u0646 \u0627\u067e \u06a9\u0631\u062a\u06d2 \u0648\u0642\u062a \u0645\u0648\u062c\u0648\u062f\u06c1 \u0627\u06a9\u0627\u0624\u0646\u0679\u0633 \u0645\u06cc\u06ba \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u06cc\u06ba \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u06ba\u06d4<\/h3>\n<p>\u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u0627 \u0627\u062e\u062a\u062a\u0627\u0645\u06cc \u0646\u0642\u0637\u06c1 \u0639\u0648\u0627\u0645\u06cc \u06c1\u06d2\u06d4 \u0627\u06af\u0631 \u0622\u067e \u06a9\u0633\u06cc \u0627\u06cc\u0633\u06d2 \u0627\u06a9\u0627\u0624\u0646\u0679 \u0645\u06cc\u06ba \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0648 \u0622\u067e \u06a9\u06d2 \u0627\u06cc \u0645\u06cc\u0644 \u0633\u06d2 \u0645\u0645\u0627\u062b\u0644 \u06c1\u0648\u060c \u062a\u0648 \u06a9\u0648\u0626\u06cc \u0628\u06be\u06cc \u062c\u0648 \u0622\u067e \u06a9\u06d2 \u0627\u06cc \u0645\u06cc\u0644 \u06a9\u0648 \u062c\u0627\u0646\u062a\u0627 \u06c1\u06d2 \u0648\u06c1 \u0627\u067e\u0646\u06cc \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f \u06a9\u0648 \u0631\u062c\u0633\u0679\u0631 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0622\u067e \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0644\u0627\u06af \u0627\u0646 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06af\u0631 \u0622\u067e \u06a9\u06d2 \u0627\u06a9\u0627\u0624\u0646\u0679 \u0645\u06cc\u06ba \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u06c1\u06cc \u067e\u0627\u0633 \u06a9\u06cc \u06c1\u06d2 \u062a\u0648 \u0631\u062c\u0633\u0679\u0631\u06cc\u0634\u0646 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u0646\u06c1 \u062f\u06cc\u06ba\u06d4 \u0627\u06af\u0631 \u0622\u067e \u0644\u0648\u06af\u0648\u06ba \u06a9\u0648 \u0645\u0632\u06cc\u062f \u06a9\u0644\u06cc\u062f\u06cc\u06ba \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u0646\u0627 \u0686\u0627\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062a\u0648 \u0622\u067e \u0627\u06cc\u06a9 \u0639\u0644\u06cc\u062d\u062f\u06c1 \u062e\u0635\u0648\u0635\u06cc\u062a \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0633 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0644\u0627\u06af \u0627\u0646 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-asking-for-verification-without-requiring-it\">\u062a\u0635\u062f\u06cc\u0642 \u06a9\u06d2 \u0644\u06cc\u06d2 \u067e\u0648\u0686\u06be\u06d2 \u0628\u063a\u06cc\u0631 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u062f\u0631\u062e\u0648\u0627\u0633\u062a \u067e\u0631 <code>userVerification: 'preferred'<\/code>\u0622\u067e \u06a9\u0627 \u0622\u0644\u06c1 \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679 \u06cc\u0627 \u067e\u0646 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0648 \u0686\u06be\u0648\u0691 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4 \u067e\u06be\u0631 \u0627\u06af\u0631 \u0622\u067e \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4 <code>requireUserVerification: true<\/code>SimpleWebAuthn \u06a9\u06d2 \u0688\u06cc\u0641\u0627\u0644\u0679 \u06a9\u06d2 \u0646\u062a\u06cc\u062c\u06d2 \u0645\u06cc\u06ba \u0627\u0646 \u0622\u0644\u0627\u062a \u06a9\u0648 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0645\u0628\u06c1\u0645 \u063a\u0644\u0637\u06cc \u06c1\u0648 \u06af\u06cc\u06d4 \u0645\u0646\u062a\u062e\u0628 \u06a9\u0631\u06cc\u06ba <code>'required'<\/code> \u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a \u0627\u0648\u0631 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u06d2 \u0645\u06cc\u0686 \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0648\u0646\u0648\u06ba \u0637\u0631\u0641 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-where-to-go-from-here\">\u0645\u06cc\u06ba \u06cc\u06c1\u0627\u06ba \u0633\u06d2 \u06a9\u06c1\u0627\u06ba \u062c\u0627\u0624\u06ba\u061f<\/h2>\n<p>\u06c1\u0645 \u0646\u06d2 \u062c\u0648 \u0627\u06cc\u067e \u0628\u0646\u0627\u0626\u06cc \u06c1\u06d2 \u0648\u06c1 \u0628\u0646\u06cc\u0627\u062f\u06cc \u06a9\u0631\u067e\u0679\u0648\u06af\u0631\u0627\u0641\u06a9 \u06a9\u0644\u06cc\u062f \u06a9\u06d2 \u0628\u06c1\u0627\u0624 \u06a9\u0627 \u0627\u062d\u0627\u0637\u06c1 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4 \u0644\u06cc\u06a9\u0646 \u0627\u06af\u0631 \u0622\u067e \u0645\u0632\u06cc\u062f \u062c\u0627\u0646\u0627 \u0686\u0627\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 \u0622\u067e \u06a9\u0686\u06be \u0628\u06c1\u062a\u0631\u06cc \u0644\u0627 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0633\u06cc\u06a9\u0631\u0679 \u06a9\u0644\u06cc\u062f \u062e\u0648\u062f\u06a9\u0627\u0631 \u062a\u06a9\u0645\u06cc\u0644 (\u062c\u0633\u06d2 \u0645\u0634\u0631\u0648\u0637 UI \u0628\u06be\u06cc \u06a9\u06c1\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2) \u0628\u0631\u0627\u0624\u0632\u0631 \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u062f\u06c1 \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u0648\u06ba \u06a9\u0648 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0627\u06cc \u0645\u06cc\u0644 \u0641\u06cc\u0644\u0688 \u0645\u06cc\u06ba \u062a\u062c\u0648\u06cc\u0632 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u060c \u062c\u06cc\u0633\u0627 \u06a9\u06c1 \u06cc\u06c1 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u062f\u06c1 \u067e\u0627\u0633 \u0648\u0631\u0688 \u062a\u062c\u0648\u06cc\u0632 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 SimpleWebAuthn \u0627\u0633 \u06a9\u06cc \u062d\u0645\u0627\u06cc\u062a \u06a9\u0631\u062a\u0627 \u06c1\u06d2: <code>useBrowserAutofill<\/code> \u0627\u062e\u062a\u06cc\u0627\u0631\u0627\u062a <code>startAuthentication<\/code>.<\/p>\n<p>\u0635\u0627\u0631\u0641\u06cc\u0646 \u062f\u0648\u0633\u0631\u06d2 \u0622\u0644\u0627\u062a \u06a9\u06d2 \u0644\u06cc\u06d2 \u067e\u0627\u0633 \u06a9\u06cc\u0632 \u0628\u06be\u06cc \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06ba \u06af\u06d2 \u0627\u0648\u0631 \u067e\u0631\u0627\u0646\u06cc \u067e\u0627\u0633 \u06a9\u06cc\u0632 \u06a9\u0648 \u06c1\u0679\u0627\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06ba \u06af\u06d2\u06d4 \u06c1\u0645 \u0627\u0633\u06d2 JWT \u06af\u0627\u0631\u0688 \u06a9\u06d2 \u067e\u06cc\u0686\u06be\u06d2 \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679\u0633 \u06a9\u06d2 \u0627\u06cc\u06a9 \u062c\u0648\u0691\u06d2 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0622\u062e\u0631 \u0645\u06cc\u06ba\u060c \u0686\u06cc\u0644\u0646\u062c \u062e\u062a\u0645 \u06c1\u0648\u0646\u0627 \u0636\u0631\u0648\u0631\u06cc \u06c1\u06d2. \u0627\u06cc\u0633\u0627 \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0627\u06cc\u06a9 \u0622\u0633\u0627\u0646 \u0637\u0631\u06cc\u0642\u06c1 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u0627\u0633 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u0627\u0633\u0679\u0648\u0631 \u06a9\u0631\u06cc\u06ba\u06d4 <code>currentChallenge<\/code> \u0627\u0633 \u06a9\u06d2 \u0628\u0639\u062f \u06cc\u06c1 \u0686\u0646\u062f \u0645\u0646\u0679 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u067e\u0631\u0627\u0646\u06cc \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0686\u06cc\u0632 \u06a9\u0648 \u0645\u0633\u062a\u0631\u062f \u06a9\u0631 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u0628\u0691\u06cc \u0627\u06cc\u067e\u0633 \u0645\u0645\u06a9\u0646\u06c1 \u0637\u0648\u0631 \u067e\u0631 \u0686\u06cc\u0644\u0646\u062c\u0632 \u06a9\u0648 \u0635\u0627\u0631\u0641 \u06a9\u06cc \u0633\u0631\u06af\u0632\u0634\u062a \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0633\u06cc\u0634\u0646 \u06cc\u0627 \u06a9\u06cc\u0634\u06d2 (\u062c\u06cc\u0633\u06d2 Redis) \u0645\u06cc\u06ba \u0627\u0633\u0679\u0648\u0631 \u06a9\u0631\u06cc\u06ba \u06af\u06cc\u06d4<\/p>\n<h2 id=\"heading-conclusion\">\u0646\u062a\u06cc\u062c\u06c1<\/h2>\n<p>\u0627\u0633 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0645\u06cc\u06ba\u060c \u06c1\u0645 \u0646\u06d2 \u062e\u0641\u06cc\u06c1 \u06a9\u0644\u06cc\u062f\u0648\u06ba \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0645\u06a9\u0645\u0644 \u0637\u0648\u0631 \u067e\u0631 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06d2 \u0628\u063a\u06cc\u0631 \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0627 \u0646\u0638\u0627\u0645 \u0628\u0646\u0627\u06cc\u0627 \u06c1\u06d2\u06d4 \u0627\u06cc\u06a9 \u0645\u06a9\u0645\u0644 NestJS API \u06c1\u06d2 \u062c\u0648 \u0622\u067e \u06a9\u0648 WebAuthn \u0686\u06cc\u0644\u0646\u062c\u0632 \u0628\u0646\u0627\u0646\u06d2\u060c SimpleWebAuthn \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u062f\u0633\u062a\u062e\u0637 \u0634\u062f\u06c1 \u062c\u0648\u0627\u0628\u0627\u062a \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u0646\u06d2 \u0627\u0648\u0631 PostgreSQL \u0645\u06cc\u06ba \u067e\u0628\u0644\u06a9 \u06a9\u06cc\u0632 \u06a9\u0648 \u0627\u0633\u0679\u0648\u0631 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0633 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 Next.js \u0641\u0631\u0646\u0679 \u0627\u06cc\u0646\u0688 \u0628\u06be\u06cc \u06c1\u06d2 \u062c\u0648 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u0627\u067e\u0646\u06d2 \u0622\u0644\u06d2 \u067e\u0631 \u0641\u0646\u06af\u0631 \u067e\u0631\u0646\u0679\u060c \u0686\u06c1\u0631\u06c1\u060c \u06cc\u0627 \u0627\u0633\u06a9\u0631\u06cc\u0646 \u0644\u0627\u06a9 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06a9\u06d2 \u0633\u0627\u0626\u0646 \u0627\u067e \u06a9\u0631\u0646\u06d2 \u0627\u0648\u0631 \u0644\u0627\u06af \u0627\u0646 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0628 \u0622\u067e \u062c\u0627\u0646\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 \u062a\u0648\u062b\u06cc\u0642 \u0627\u0648\u0631 \u062f\u0633\u062a\u062e\u0637 \u06a9\u0627 \u0628\u06c1\u0627\u0624 \u06a9\u06cc\u0633\u06d2 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0635\u0627\u0631\u0641 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u06d2 \u062c\u06be\u0646\u0688\u06d2 \u06a9\u06cc\u0648\u06ba \u0627\u06c1\u0645 \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u0633\u0631\u0648\u0631 \u06a9\u06cc\u0648\u06ba \u06cc\u06c1 \u062a\u0639\u06cc\u0646 \u0646\u06c1\u06cc\u06ba \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06a9\u06c1 \u0635\u0627\u0631\u0641 \u06a9\u0648 \u06a9\u0648\u0646 \u0633\u0627 \u0628\u0627\u0626\u06cc\u0648 \u0645\u06cc\u0679\u0631\u06a9 \u0637\u0631\u06cc\u0642\u06c1 \u067e\u06cc\u0634 \u06a9\u06cc\u0627 \u062c\u0627\u0626\u06d2\u06d4 \u06c1\u0645 \u0646\u06d2 \u06a9\u0686\u06be \u0627\u06cc\u0633\u06d2 \u0628\u0627\u0631\u06cc\u06a9 \u0628\u06af\u0632 \u06a9\u06cc \u0628\u06be\u06cc \u0646\u0634\u0627\u0646\u062f\u06c1\u06cc \u06a9\u06cc \u06c1\u06d2 \u062c\u0648 \u0644\u0627\u06af \u0627\u0646 \u0645\u06cc\u06ba \u0646\u0627\u06a9\u0627\u0645\u06cc \u06cc\u0627 \u0627\u06a9\u0627\u0624\u0646\u0679 \u0679\u06cc\u06a9 \u0627\u0648\u0648\u0631 \u06a9\u0627 \u0633\u0628\u0628 \u0628\u0646 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u0627\u0646 \u0633\u06d2 \u06a9\u06cc\u0633\u06d2 \u0628\u0686\u0646\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0648\u0642\u062a \u062c\u0644\u062f \u062e\u062a\u0645 \u0646\u06c1\u06cc\u06ba \u06c1\u0648 \u0631\u06c1\u06d2 \u06c1\u06cc\u06ba\u06d4 \u062a\u0627\u06c1\u0645\u060c \u067e\u0627\u0633\u06a9\u06cc \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u06c1\u06cc \u0622\u067e \u06a9\u06cc \u0645\u0644\u06a9\u06cc\u062a \u06a9\u06d2 \u062a\u0642\u0631\u06cc\u0628\u0627\u064b \u06c1\u0631 \u0688\u06cc\u0648\u0627\u0626\u0633 \u067e\u0631 \u062a\u0639\u0627\u0648\u0646 \u06cc\u0627\u0641\u062a\u06c1 \u06c1\u06d2\u06d4 \u0627\u0628 \u0622\u067e \u062c\u0627\u0646\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 \u0627\u0633\u06d2 \u0627\u067e\u0646\u06cc \u0627\u06cc\u067e \u0645\u06cc\u06ba \u06a9\u06cc\u0633\u06d2 \u0634\u0627\u0645\u0644 \u06a9\u0631\u0646\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0645\u06a9\u0645\u0644 \u0633\u0648\u0631\u0633 \u06a9\u0648\u0688 GitHub \u067e\u0631 \u062f\u0633\u062a\u06cc\u0627\u0628 \u06c1\u06d2\u06d4 \u0627\u0633\u06d2 \u0646\u0642\u0644 \u06a9\u0631\u062a\u06d2 \u0631\u06c1\u06cc\u06ba\u060c \u0627\u0633\u06d2 \u0627\u0644\u06af \u06a9\u0631\u062a\u06d2 \u0631\u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u0627\u0633\u06d2 \u0627\u067e\u0646\u0627 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4 \u0627\u06af\u0631 \u0622\u067e \u06a9\u0648 \u06cc\u06c1 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0637\u0631\u062d \u0633\u06d2 \u06a9\u0627\u0631\u0622\u0645\u062f \u0644\u06af\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0628\u0631\u0627\u06c1 \u06a9\u0631\u0645 \u0627\u0633\u06d2 \u06a9\u0633\u06cc \u0627\u06cc\u0633\u06d2 \u0634\u062e\u0635 \u06a9\u0648 \u0628\u06be\u06cc\u062c \u062f\u06cc\u06ba \u062c\u0633 \u0633\u06d2 \u062c\u0644\u062f \u06c1\u06cc \u06cc\u06c1\u06cc \u0633\u0648\u0627\u0644 \u06c1\u0648 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u067e\u0627\u0633 \u0648\u0631\u0688 \u0635\u0627\u0631\u0641\u06cc\u0646 \u0627\u0648\u0631 \u0633\u0631\u0648\u0633 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u0648\u06ba \u062f\u0648\u0646\u0648\u06ba \u06a9\u06d2 \u0644\u06cc\u06d2 \u062f\u0631\u062f \u0633\u0631 \u06c1\u06cc\u06ba\u06d4 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u0627\u06a9\u062b\u0631 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06cc\u0627\u062f \u0631\u06a9\u06be\u0646\u06d2 \u0645\u06cc\u06ba \u062f\u0634\u0648\u0627\u0631\u06cc \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0645\u062a\u0639\u062f\u062f \u0648\u06cc\u0628 \u0633\u0627\u0626\u0679\u0633 \u067e\u0631 \u0641\u0634\u0646\u06af \u0627\u0648\u0631 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06a9\u06d2 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0627 \u0632\u06cc\u0627\u062f\u06c1 \u062e\u0637\u0631\u06c1 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0688\u0648\u06cc\u0644\u067e\u0631\u0632 \u06a9\u0648 \u067e\u0627\u0633 \u0648\u0631\u0688 \u06c1\u06cc\u0634 \u06a9\u0631\u0646\u0627 \u06c1\u0648\u06ba \u06af\u06d2\u060c \u0627\u0646 \u067e\u0631 \u0646\u0645\u06a9 \u0688\u0627\u0644\u0646\u0627 \u06c1\u0648\u06af\u0627\u060c [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":31508,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1],"tags":[],"class_list":["post-31507","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/posts\/31507","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/comments?post=31507"}],"version-history":[{"count":1,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/posts\/31507\/revisions"}],"predecessor-version":[{"id":31509,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/posts\/31507\/revisions\/31509"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/media\/31508"}],"wp:attachment":[{"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/media?parent=31507"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/categories?post=31507"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/umang.pk\/en_us\/wp-json\/wp\/v2\/tags?post=31507"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}