{"id":42148892,"url":"https://github.com/wmeints/webauthn-sample","last_synced_at":"2026-01-26T18:11:00.899Z","repository":{"id":56724600,"uuid":"524138573","full_name":"wmeints/webauthn-sample","owner":"wmeints","description":"Sample demonstrating how to use FIDO2 keys with ASP.NET Core using WebAuthn","archived":false,"fork":false,"pushed_at":"2022-08-13T14:10:33.000Z","size":1534,"stargazers_count":12,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-06T20:59:06.255Z","etag":null,"topics":["asp-net-core","csharp","dotnet","fido2","npm","nuget","react","security","typescript","webauthn"],"latest_commit_sha":null,"homepage":"","language":"CSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wmeints.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-08-12T15:32:46.000Z","updated_at":"2025-08-13T14:55:05.000Z","dependencies_parsed_at":"2022-08-16T00:30:37.215Z","dependency_job_id":null,"html_url":"https://github.com/wmeints/webauthn-sample","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/wmeints/webauthn-sample","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wmeints%2Fwebauthn-sample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wmeints%2Fwebauthn-sample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wmeints%2Fwebauthn-sample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wmeints%2Fwebauthn-sample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wmeints","download_url":"https://codeload.github.com/wmeints/webauthn-sample/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wmeints%2Fwebauthn-sample/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28784093,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T13:55:28.044Z","status":"ssl_error","status_checked_at":"2026-01-26T13:55:26.068Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asp-net-core","csharp","dotnet","fido2","npm","nuget","react","security","typescript","webauthn"],"created_at":"2026-01-26T18:10:59.742Z","updated_at":"2026-01-26T18:11:00.880Z","avatar_url":"https://github.com/wmeints.png","language":"CSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebAuthn sample\n\nThis sample demonstrates how to integrate WebAuthn with FIDO2 keys into ASP.NET Core. Please read the rest of this README \nto get a full picture of what's in the sample and how the various components work together.\n\n## System requirements\n\n* .NET SDK 6.0\n* Latest LTS release Node \n\n## Getting started\n\nYou can run this sample as a docker container using the following steps:\n\n* `git clone https://github.com/wmeints/webauthn-sample/`\n\nAfter cloning the repository, create a file `.env` with the following content:\n\n```text\nDB_PASSWORD=\u003cyour-password\u003e\n```\n\nYou can choose any password you like. Once you have the password set, perform the following steps from the root of the project directory:\n\n* `docker-compose up -d`\n* `cd src/WebAuthnSample`\n* `dotnet user-secrets set \"ConnectionStrings:DefaultDatabase\" \"data source=127.0.0.1;initial catalog=webauthn;user id=sa;password=\u003cyour-password\u003e\"`\n\nMake sure the password in the last step matches the password that was stored in the `.env` file. Now execute the following\ncommand from `src/WebAuthnSample` directory:\n\n* `dotnet run`\n\nOpen the browser to `https://localhost:7140` follow the on-screen instructions.\n\n## Documentation\n\n### Project structure\n\nThe project is made out of two parts:\n\n* `src/WebAuthnSample` - Contains the server-side application.\n* `src/WebAuthnSample/Client` - Contains the client-side scripts.\n\nThe server-side components are written in ASP.NET Core 6.\nFor the client-side components I've used webpack with React. I've found that typescript is great for this kind of\nmore complicated, but not too complicated stuff. And webpack is great, since it allows me to generate compact packages\nof client-side scripts.\n\n#### The client-side scripts\n\nThe client-side scripts use React. I've made a setup where each page gets its own dedicated script.\n\n* `src/WebAuthnSample/Pages/Login.cshtml` - Uses `src/WebAuthnSample/wwwroot/js/authentication.js`.\n* `src/WebAuthnSample/Pages/Register.cshtml` - Uses `src/WebAuthnSample/wwwroot/js/registration.js`.\n\nThe registration script is compiled from `src/WebAuthnSample/Client/registration/index.tsx` and related files.\nThe authentication script is compiled from `src/WebAuthnSample/Client/authentication/index.tsx` and related files.\n\nFor performance reasons, I've split the shared scripts into `src/WebAuthnSample/wwwroot/shared.js`. This script\nis contains react, react-dom, and the sources from `src/WebAuthnSample/Client/shared/`.\n\n#### The server-side components\n\nThe server-side part follows this layout:\n\n* `src/WebAuthnSample/Controllers` - Contains two API controllers for registration and authentication.\n* `src/WebAuthnSample/Services` - Contains business logic to implement the registration and authentication.\n* `src/WebAuthnSample/Models` - Contains models used in the application.\n* `src/WebAuthnSample/Data` - Contains persistence logic for the application.\n* `src/WebAuthnSample/Forms` - Contains the forms used in the controllers. \n* `src/WebAuthnSample/Pages` - Contains the pages for the application.\n\n### How does WebAuthn work?\n\nWebAuthn is a standard for authenticating users using public key cryptography. You can choose to use a platform\nkey or a cross-platform key. The former is usually a trusted platform module in your laptop or desktop. The latter\nis a USB key or a mobile phone. \n\nUsing WebAuthn, we can move away from passwords completely. But you can use it also as a second factor next to a\ntraditional password. In this example, we're using WebAuthn to replace passwords with a public key credential.\n\n#### Registering a user using WebAuthn\n\nTo set up authentication with a public key credential, we need to register a new account first.\nThe following flow demonstrates how this is done:\n\n```mermaid\nsequenceDiagram\n    actor User\n    participant Browser\n    participant Server\n    User-\u003e\u003eBrowser: navigate (/Identity/Account/Register)\n    activate Browser\n    Browser-\u003e\u003eServer: POST /api/registration/options\n    Server--\u003e\u003eBrowser: PublicKeyCredentialOptions\n    Browser-\u003e\u003eBrowser: Create new key pair + challenge response\n    Browser-\u003e\u003eServer: POST /api/registration/complete\n    Server-\u003e\u003eServer: verify challenge response\n    Server-\u003e\u003eServer: Create user + store credentials\n    Server--\u003e\u003eBrowser: HTTP 202\n    Browser-\u003e\u003eBrowser: Redirect to login page\n```\n\n1. When the user navigates to [the registration page][REGISTRATION_URL], we'll ask the user to fill out the registration\n   form. After filling out the form, they click on *Register* to start the registration process.\n2. Next, we need to get [a challenge][CHALLENGE_URL] from the server. This challenge includes a set of options under\n   which conditions the server accepts a new public key for registration. \n3. After that, the browser [generates a new key pair][KEYPAIR_URL] and answers the challenge. This ensures that the server knows who's\n   registering and we're not some rogue client to break into the website. Each challenge can be used once to register a\n   new key pair.\n4. The browser posts [the response to the challenge][COMPLETE_REGISTRATION_URL] to the server to complete the registration. The server needs to\n   [verify the challenge][VERIFY_REGISTRATION_URL] response against the challenge it generated earlier. We stored the challenge options in the\n   HTTP session earlier. You can choose to store this elsewhere on the server as necessary.\n5. When the challenge is verified and found to be correct, the server sends a HTTP 202 response back to the client.\n6. The browser will [redirect the user][REGISTRATION_REDIRECT_URL] to the login page.\n\nThe ceremony to verify a public key pair during the registration process is quite extensive. If you're interested in\nthe full spec, I can recommend to read [the WebAuthn spec](https://w3c.github.io/webauthn/#sctn-registering-a-new-credential).\n\nAfter we've registered the user, we can work on the login phase.\n\n#### Authenticating a user using WebAuthn\n\nThe following flow demonstrates how to authenticate a user using Webauthn:\n\n```mermaid\nsequenceDiagram\n    actor User\n    participant Browser\n    participant Server\n    User-\u003e\u003eBrowser: navigate (/Identity/Account/Login)\n    Browser-\u003e\u003eServer: POST /api/authentication/options\n    Server--\u003e\u003eBrowser: PublicKeyCredentialRequestOptions\n    Browser-\u003e\u003eBrowser: Get public key pair using opions\n    Browser-\u003e\u003eServer: POST /api/authentication/login\n    Server-\u003e\u003eServer: Verify challenge\n    Server-\u003e\u003eServer: Sign in user\n    Server-\u003e\u003eBrowser: HTTP 202\n    Browser-\u003e\u003eBrowser: Redirect to homepage\n```\n\n1. When the user navigates to [the login page][LOGIN_URL], fills out the login form, and clicks *Login* the login process is started.\n2. The browser will request an [authentication challenge][LOGIN_CHALLENGE_URL] from the server that includes all registered public keys for its\n   account. \n3. The server returns an authentication challenge that includes all the registered public keys for the user's account.\n4. The browser asks the user [to insert the USB key][LOGIN_CREDENTIAL_URL] they like to login with. If the key matches one of the registered\n   public keys, the browser asks the user to touch their key to confirm the login.\n5. The browser signs the authentication challenge and [sends this response][LOGIN_RESPONSE_URL] to the server.\n6. The server [verifies the challenge][VERIFY_LOGIN_URL], and signs in the user.\n7. The browser receives a HTTP 202, and redirects the user to the home page.\n\nIf you're interested in the ceremony to verify a login challenge, you can find a description [in the WebAuthn spec](https://w3c.github.io/webauthn/#sctn-verifying-assertion).\n\n### Compiling the solution\n\nIn case you want to change something in the solution, please follow the instructions in this section.\n\n#### Changing the client-side components\n\nAs we discussed earlier in the README, this project contains some components written in React.\nTo compile these components, you'll need to follow these steps:\n\n* `cd src/WebAuthnSample/Client`\n* `npm install`\n* `npm run build`\n\nThis produces a production-ready build of the scripts. You can't easily debug these. So if you're debugging an issue,\nyou should use the command `npm run build:debug` instead.\n\n#### Changing the server-side components\n\nThe server-side components are implemented in ASP.NET Core. You can change these just like any other .NET project.\nFor database migrations, we recommend that you use `dotnet-ef` to generate them. I'm assuming you know how to write\napplications in ASP.NET Core for the purpose of this sample.\n\n## Contributing\n\nIf you find an bug in the code, please submit an issue in this repo. Pull requests are welcome too!\n\n[REGISTRATION_URL]: https://github.com/wmeints/webauthn-sample/blob/d6683db6bf4ffb17b3b0784d2f46ed24e5398ac4/src/WebAuthnSample/Client/registration/RegistrationForm.tsx#L11\n[CHALLENGE_URL]: https://github.com/wmeints/webauthn-sample/blob/d6683db6bf4ffb17b3b0784d2f46ed24e5398ac4/src/WebAuthnSample/Controllers/RegistrationController.cs#L24\n[KEYPAIR_URL]: https://github.com/wmeints/webauthn-sample/blob/d6683db6bf4ffb17b3b0784d2f46ed24e5398ac4/src/WebAuthnSample/Client/registration/RegistrationForm.tsx#L49\n[COMPLETE_REGISTRATION_URL]: https://github.com/wmeints/webauthn-sample/blob/d6683db6bf4ffb17b3b0784d2f46ed24e5398ac4/src/WebAuthnSample/Client/registration/api.ts#L53\n[VERIFY_REGISTRATION_URL]: https://github.com/wmeints/webauthn-sample/blob/d6683db6bf4ffb17b3b0784d2f46ed24e5398ac4/src/WebAuthnSample/Controllers/RegistrationController.cs#L46\n[REGISTRATION_REDIRECT_URL]: https://github.com/wmeints/webauthn-sample/blob/d6683db6bf4ffb17b3b0784d2f46ed24e5398ac4/src/WebAuthnSample/Client/registration/RegistrationForm.tsx#L64\n[LOGIN_URL]: https://github.com/wmeints/webauthn-sample/blob/d6683db6bf4ffb17b3b0784d2f46ed24e5398ac4/src/WebAuthnSample/Client/authentication/LoginForm.tsx#L8\n[LOGIN_CHALLENGE_URL]: https://github.com/wmeints/webauthn-sample/blob/d6683db6bf4ffb17b3b0784d2f46ed24e5398ac4/src/WebAuthnSample/Controllers/AuthenticationController.cs#L23\n[LOGIN_CREDENTIAL_URL]: https://github.com/wmeints/webauthn-sample/blob/d6683db6bf4ffb17b3b0784d2f46ed24e5398ac4/src/WebAuthnSample/Client/authentication/LoginForm.tsx#L37\n[LOGIN_RESPONSE_URL]: https://github.com/wmeints/webauthn-sample/blob/d6683db6bf4ffb17b3b0784d2f46ed24e5398ac4/src/WebAuthnSample/Client/authentication/api.ts#L43\n[VERIFY_LOGIN_URL]: https://github.com/wmeints/webauthn-sample/blob/d6683db6bf4ffb17b3b0784d2f46ed24e5398ac4/src/WebAuthnSample/Controllers/AuthenticationController.cs#L44","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwmeints%2Fwebauthn-sample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwmeints%2Fwebauthn-sample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwmeints%2Fwebauthn-sample/lists"}