Skip to content

Commit 4d78241

Browse files
authored
feat(readme): Update README with latest changes (#606)
* feat(readme): Update README with latest changes The changes in this commit update the README file with the following improvements: 1. Update the build status and code coverage badges to point to the `main` branch instead of `master`. 2. Remove the release and changelog link from the main section and move it to the bottom. 3. Add installation instructions for the core library, ASP.NET Core helpers, and Blazor WebAssembly support. 4. Update the "What is FIDO2?" section to provide a more concise and up-to-date description of the FIDO2/WebAuthn standard and its benefits. These changes aim to provide a more informative and user-friendly README for the FIDO2 .NET Library. * Fix intro
1 parent 063303b commit 4d78241

File tree

1 file changed

+143
-71
lines changed

1 file changed

+143
-71
lines changed

README.md

Lines changed: 143 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
# FIDO2 .NET Library (WebAuthn)
2-
A working implementation library + demo for [FIDO2](https://fidoalliance.org/fido2/) and [WebAuthn](https://www.w3.org/TR/webauthn/) using [.NET](https://dotnet.microsoft.com/)
3-
[![Build Status](https://dev.azure.com/anders/Fido2/_apis/build/status/abergs.fido2-net-lib?branchName=master)](https://dev.azure.com/anders/Fido2/_build/latest?definitionId=10&branchName=master)
4-
[![codecov](https://codecov.io/gh/passwordless-lib/fido2-net-lib/branch/master/graph/badge.svg)](https://codecov.io/gh/passwordless-lib/fido2-net-lib)
1+
# Passkeys - FIDO2 .NET Library (WebAuthn)
2+
3+
A fully working and battle tested library for passkeys ([FIDO2](https://fidoalliance.org/fido2/) and [WebAuthn](https://www.w3.org/TR/webauthn/)) on [.NET](https://dotnet.microsoft.com/)
4+
5+
[![Build Status](https://dev.azure.com/anders/Fido2/_apis/build/status/abergs.fido2-net-lib?branchName=main)](https://dev.azure.com/anders/Fido2/_build/latest?definitionId=10&branchName=main)
6+
[![codecov](https://codecov.io/gh/passwordless-lib/fido2-net-lib/branch/main/graph/badge.svg)](https://codecov.io/gh/passwordless-lib/fido2-net-lib)
57
[![Financial Contributors on Open Collective](https://opencollective.com/passwordless/all/badge.svg?label=financial+contributors)](https://opencollective.com/passwordless)
6-
[![NuGet Status](http://img.shields.io/nuget/v/Fido2.svg?style=flat-square)](https://www.nuget.org/packages/Fido2/) [Releases & Change log](https://github.com/passwordless-lib/fido2-net-lib/releases)
8+
[![NuGet Status](http://img.shields.io/nuget/v/Fido2.svg?style=flat-square)](https://www.nuget.org/packages/Fido2/)
9+
10+
[Releases & Change log](https://github.com/passwordless-lib/fido2-net-lib/releases)
711

812
### 💡 Passwordless API now available!
913

@@ -20,23 +24,40 @@ To provide a developer friendly and well tested [.NET](https://dotnet.microsoft.
2024

2125
This project is part of the [.NET foundation](https://dotnetfoundation.org)
2226

27+
## Installation
28+
29+
**Requirements**: .NET 8.0 or later
30+
31+
```bash
32+
dotnet add package Fido2
33+
```
34+
35+
To use the ASP.NET Core helpers:
2336

24-
```Install-Package Fido2```
37+
```bash
38+
dotnet add package Fido2.AspNet
39+
```
2540

26-
To use the asp.net helpers, install the asp.net-package.
41+
For Blazor WebAssembly support:
42+
43+
```bash
44+
dotnet add package Fido2.BlazorWebAssembly
45+
```
2746

28-
```Install-Package Fido2.AspNet```
47+
> **⚠️ Breaking Changes**: If upgrading from v3.x, see the [Upgrade Guide](upgrade-guide.md) for migration instructions.
2948
3049
### Demo
31-
* **Online examples**: https://www.passwordless.dev
32-
* **Library website**: https://fido2-net-lib.passwordless.dev
33-
* [Code examples](#examples)
50+
51+
- **Library website**: https://fido2-net-lib.passwordless.dev
52+
- [Code examples](#examples)
3453

3554
## What is FIDO2?
36-
**The passwordless web is coming.**
37-
[FIDO2](https://fidoalliance.org/fido2/) / [WebAuthn](https://www.w3.org/TR/webauthn/) is a new open authentication standard, supported by [browsers](https://www.w3.org/Consortium/Member/List) and [many large tech companies](https://fidoalliance.org/members/) such as Microsoft, Google etc. The main driver is to allow a user to login without passwords, creating *passwordless flows* or strong MFA for user signup/login on websites. The standard is not limited to web applications with support coming to Active Directory and native apps. The technology builds on public/private keys, allowing authentication to happen without sharing a secret between the user & platform. This brings many benefits, such as easier and safer logins and makes phishing attempts extremely hard.
55+
56+
**The passwordless web is here.**
57+
[FIDO2](https://fidoalliance.org/fido2/) / [WebAuthn](https://www.w3.org/TR/webauthn/) is a modern, stable and open authentication standard, supported by [browsers](https://www.w3.org/Consortium/Member/List) and [many large tech companies](https://fidoalliance.org/members/) such as Microsoft, Google etc. The main driver is to allow a user to login without passwords, creating _passwordless flows_ or strong MFA for user signup/login on websites. The standard is not limited to web applications with support coming to native apps. The technology builds on public/private keys, allowing authentication to happen without sharing a secret between the user & website. This brings many benefits, such as easier and safer logins and makes phishing attempts extremely hard.
3858

3959
Read more:
60+
4061
- [Why it's exciting](http://ideasof.andersaberg.com/development/the-passwordless-web)
4162
- [Medium](https://medium.com/tokenring/fido-2-0-what-is-it-and-why-are-we-excited-31a66df6e113)
4263
- [FIDO Alliance](https://fidoalliance.org/fido2/)
@@ -58,32 +79,60 @@ Read more:
5879
- ✅ All currently referenced cryptographic algorithms for FIDO2 Server ([spec](https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#other))
5980
- ✅ All current attestation formats: "packed", "tpm", "android-key", "android-safetynet", "fido-u2f", "apple", "apple-appattest", and "none" ([spec](https://www.iana.org/assignments/webauthn/webauthn.xhtml))
6081
- ✅ FIDO2 Server attestation validation via FIDO Metadata Service V3 ([spec](https://fidoalliance.org/specs/mds/fido-metadata-service-v3.0-ps-20210518.html))
61-
- ✅ WebAuthn extensions ([spec](https://www.w3.org/TR/webauthn/#extensions))
62-
- ✅ Examples & demos
82+
- ✅ WebAuthn extensions ([spec](https://www.w3.org/TR/webauthn/#extensions)) including PRF, Large Blob, Credential Protection
83+
- ✅ Blazor WebAssembly support for client-side applications
84+
- ✅ Examples & demos (ASP.NET Core and Blazor WebAssembly)
6385
- ✅ Intellisense documentation
64-
- 💤 [Formal documentation](https://github.com/passwordless-lib/fido2-net-lib/issues/53)
65-
- 💤 Recommended [usage patterns](https://github.com/passwordless-lib/fido2-net-lib/issues/54)
6686

6787
## Configuration
6888

69-
*Only some options are mentioned here, see the [Configuration](https://github.com/passwordless-lib/fido2-net-lib/blob/master/Src/Fido2.Models/Fido2Configuration.cs) class for all options*
89+
_Only some options are mentioned here, see the [Configuration](https://github.com/passwordless-lib/fido2-net-lib/blob/master/Src/Fido2.Models/Fido2Configuration.cs) class for all options_
90+
91+
- `fido2:MDSCacheDirPath` - App Secret / environment variable that sets the cache path for the MDS. Defaults to "current user's temporary folder"/fido2mdscache. _Optional when using the default [MetadataService provider](https://fidoalliance.org/mds/)._
92+
93+
## Quick Start
7094

71-
* `fido2:MDSCacheDirPath` - App Secret / environment variable that sets the cache path for the MDS. Defaults to "current user's temporary folder"/fido2mdscache. *Optional when using the default [MetadataService provider](https://fidoalliance.org/mds/).*
95+
### 1. Configure Services (ASP.NET Core)
96+
97+
```csharp
98+
services.AddFido2(options =>
99+
{
100+
options.ServerDomain = "example.com";
101+
options.ServerName = "Example App";
102+
options.Origins = new HashSet<string> { "https://example.com" };
103+
});
104+
```
105+
106+
### 2. Inject IFido2 Service
107+
108+
```csharp
109+
public class AuthController : Controller
110+
{
111+
private readonly IFido2 _fido2;
112+
113+
public AuthController(IFido2 fido2)
114+
{
115+
_fido2 = fido2;
116+
}
117+
}
118+
```
72119

73120
## Examples
74121

75-
See the [demo controller](Demo/Controller.cs) for full examples of both [attestation](https://www.w3.org/TR/webauthn/#sctn-attestation) and [assertion](https://www.w3.org/TR/webauthn/#verifying-assertion).
122+
- **[ASP.NET Core Demo](Demo/)** - Complete implementation with registration and authentication
123+
- **[Blazor WebAssembly Demo](BlazorWasmDemo/)** - Client-side Blazor example
124+
- **[Test Controller](Demo/TestController.cs)** - Conformance test examples
76125

77-
See the [test controller](Demo/TestController.cs) for examples of how to pass the [conformance tests](#conformance-testing-tool).
126+
For integration patterns, see:
78127

79-
See the [Active Directory Store information](https://github.com/passwordless-lib/fido2-net-lib/issues/68#issuecomment-451758622) and [example credential store](https://github.com/passwordless-lib/fido2-net-lib/blob/ActiveDirectory/fido2-net-lib/ActiveDirectoryStore.cs) for ideas on how to integrate this library with an on-premises Active Directory.
128+
- [Active Directory Store information](https://github.com/passwordless-lib/fido2-net-lib/issues/68#issuecomment-451758622)
129+
- [Example credential store](https://github.com/passwordless-lib/fido2-net-lib/blob/ActiveDirectory/fido2-net-lib/ActiveDirectoryStore.cs)
80130

81-
### Create attestation Options
131+
### Create Attestation Options
82132

83-
To add FIDO2 credentials to an existing user account, we we perform a attestation process. It starts with returning options to the client.
133+
To add FIDO2 credentials to an existing user account, start by creating options for the client.
84134

85135
```csharp
86-
// file: Controller.cs
87136
// 1. Get user from DB by username (in our example, auto create missing users)
88137
var user = DemoStorage.GetOrAddUser(username, () => new User
89138
{
@@ -93,73 +142,91 @@ var user = DemoStorage.GetOrAddUser(username, () => new User
93142
});
94143

95144
// 2. Get user existing keys by username
96-
List<PublicKeyCredentialDescriptor> existingKeys = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList();
145+
var existingKeys = DemoStorage.GetCredentialsByUser(user)
146+
.Select(c => c.Descriptor)
147+
.ToList();
97148

98-
// 3. Create options
99-
var options = _lib.RequestNewCredential(user, existingKeys, AuthenticatorSelection.Default, AttestationConveyancePreference.Parse(attType));
149+
// 3. Create options using new parameter wrapper
150+
var options = _fido2.RequestNewCredential(new RequestNewCredentialParams
151+
{
152+
User = user,
153+
ExcludeCredentials = existingKeys,
154+
AuthenticatorSelection = AuthenticatorSelection.Default,
155+
AttestationPreference = AttestationConveyancePreference.Parse(attType),
156+
Extensions = new AuthenticationExtensionsClientInputs
157+
{
158+
CredProps = true // Enable credential properties extension
159+
}
160+
});
100161

101162
// 4. Temporarily store options, session/in-memory cache/redis/db
102163
HttpContext.Session.SetString("fido2.attestationOptions", options.ToJson());
103164

104-
// 5. return options to client
165+
// 5. Return options to client
105166
return Json(options);
106167
```
107168

108-
### Register credentials
169+
### Register Credentials
109170

110-
When the client returns a response, we verify and register the credentials.
171+
When the client returns a response, verify and register the credentials.
111172

112173
```csharp
113-
// file: Controller.cs
114-
// 1. get the options we sent the client and remove it from storage
174+
// 1. Get the options we sent the client and remove from storage
115175
var jsonOptions = HttpContext.Session.GetString("fido2.attestationOptions");
116176
HttpContext.Session.Remove("fido2.attestationOptions");
117177
var options = CredentialCreateOptions.FromJson(jsonOptions);
118178

119179
// 2. Create callback so that lib can verify credential id is unique to this user
120180
IsCredentialIdUniqueToUserAsyncDelegate callback = async (IsCredentialIdUniqueToUserParams args) =>
121181
{
122-
List<User> users = await DemoStorage.GetUsersByCredentialIdAsync(args.CredentialId);
123-
if (users.Count > 0) return false;
124-
125-
return true;
182+
var users = await DemoStorage.GetUsersByCredentialIdAsync(args.CredentialId);
183+
return users.Count == 0; // Return true if credential ID is unique
126184
};
127185

128-
// 2. Verify and make the credentials
129-
var success = await _lib.MakeNewCredentialAsync(attestationResponse, options, callback);
186+
// 3. Verify and make the credentials using new parameter wrapper
187+
var result = await _fido2.MakeNewCredentialAsync(new MakeNewCredentialParams
188+
{
189+
AttestationResponse = attestationResponse,
190+
OriginalOptions = options,
191+
IsCredentialIdUniqueToUserCallback = callback
192+
});
130193

131-
// 3. Store the credentials in db
194+
// 4. Store the credentials in database
132195
DemoStorage.AddCredentialToUser(options.User, new StoredCredential
133196
{
134-
Descriptor = new PublicKeyCredentialDescriptor(success.Result.CredentialId),
135-
PublicKey = success.Result.PublicKey,
136-
UserHandle = success.Result.User.Id
197+
Descriptor = new PublicKeyCredentialDescriptor(result.Id),
198+
PublicKey = result.PublicKey,
199+
UserHandle = result.User.Id
137200
});
138201

139-
// 4. return "ok" to the client
140-
return Json(success);
202+
// 5. Return success to client
203+
return Json(result);
141204
```
142205

143-
### Create Assertion options
144-
145-
When a user wants to log a user in, we do an assertion based on the registered credentials.
206+
### Create Assertion Options
146207

147-
First we create the assertion options and return to the client.
208+
For user authentication, create assertion options based on registered credentials.
148209

149210
```csharp
150-
// file: Controller.cs
151211
// 1. Get user from DB
152212
var user = DemoStorage.GetUser(username);
153-
if (user == null) return NotFound("username was not registered");
213+
if (user == null) return NotFound("Username was not registered");
154214

155215
// 2. Get registered credentials from database
156-
List<PublicKeyCredentialDescriptor> existingCredentials = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList();
216+
var existingCredentials = DemoStorage.GetCredentialsByUser(user)
217+
.Select(c => c.Descriptor)
218+
.ToList();
157219

158-
// 3. Create options
159-
var options = _lib.GetAssertionOptions(
160-
existingCredentials,
161-
UserVerificationRequirement.Discouraged
162-
);
220+
// 3. Create options using new parameter wrapper
221+
var options = _fido2.GetAssertionOptions(new GetAssertionOptionsParams
222+
{
223+
AllowedCredentials = existingCredentials,
224+
UserVerification = UserVerificationRequirement.Preferred,
225+
Extensions = new AuthenticationExtensionsClientInputs
226+
{
227+
Extensions = true
228+
}
229+
});
163230

164231
// 4. Temporarily store options, session/in-memory cache/redis/db
165232
HttpContext.Session.SetString("fido2.assertionOptions", options.ToJson());
@@ -168,8 +235,9 @@ HttpContext.Session.SetString("fido2.assertionOptions", options.ToJson());
168235
return Json(options);
169236
```
170237

171-
### Verify the assertion response
172-
When the client returns a response, we verify it and accepts the login.
238+
### Verify the Assertion Response
239+
240+
When the client returns a response, verify it and accept the login.
173241

174242
```csharp
175243
// 1. Get the assertion options we sent the client and remove from storage
@@ -178,26 +246,30 @@ HttpContext.Session.Remove("fido2.assertionOptions");
178246
var options = AssertionOptions.FromJson(jsonOptions);
179247

180248
// 2. Get registered credential from database
181-
StoredCredential creds = DemoStorage.GetCredentialById(clientResponse.Id);
182-
183-
// 3. Get credential counter from database
184-
var storedCounter = creds.SignatureCounter;
249+
var creds = DemoStorage.GetCredentialById(clientResponse.Id);
185250

186-
// 4. Create callback to check if userhandle owns the credentialId
251+
// 3. Create callback to check if userhandle owns the credentialId
187252
IsUserHandleOwnerOfCredentialIdAsync callback = async (args) =>
188253
{
189-
List<StoredCredential> storedCreds = await DemoStorage.GetCredentialsByUserHandleAsync(args.UserHandle);
254+
var storedCreds = await DemoStorage.GetCredentialsByUserHandleAsync(args.UserHandle);
190255
return storedCreds.Exists(c => c.Descriptor.Id.SequenceEqual(args.CredentialId));
191256
};
192257

193-
// 5. Make the assertion
194-
var res = await _lib.MakeAssertionAsync(clientResponse, options, creds.PublicKey, storedCounter, callback);
258+
// 4. Make the assertion using new parameter wrapper
259+
var result = await _fido2.MakeAssertionAsync(new MakeAssertionParams
260+
{
261+
AssertionResponse = clientResponse,
262+
OriginalOptions = options,
263+
StoredPublicKey = creds.PublicKey,
264+
StoredSignatureCounter = creds.SignatureCounter,
265+
IsUserHandleOwnerOfCredentialIdCallback = callback
266+
});
195267

196-
// 6. Store the updated counter
197-
DemoStorage.UpdateCounter(res.CredentialId, res.Counter);
268+
// 5. Store the updated counter
269+
DemoStorage.UpdateCounter(result.CredentialId, result.Counter);
198270

199-
// 7. return OK to client
200-
return Json(res);
271+
// 6. Return success to client
272+
return Json(result);
201273
```
202274

203275
## Nuget package

0 commit comments

Comments
 (0)