dotnet / dotnet/maui

Cannot use passkey/fido/webauthn in BlazorWebView.

Open
#32,020 9 comments 0 reactions 0 assignees View on GitHub
area-blazor t/bug
Dominant language
C#
Stars
23.3k
Forks
2k
Avg merge
1d 15h
Merged PRs (30d)
290

Description

### Description

consider following code:

``` razor
@using Microsoft.JSInterop
@using System.Diagnostics
@inject HttpClient Http
@inject IJSRuntime JSRuntime

@if (_module is null)
{

loading...


}
else
{

Click Me

}

@code {
private IJSObjectReference? _module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
_module = await JSRuntime.InvokeAsync("import", "./Home.razor.js");

StateHasChanged();
}
await base.OnAfterRenderAsync(firstRender);
}

private async Task PasskeyAsync(IJSObjectReference js)
{
try
{
var possible = await js.InvokeAsync("isWebAuthnPossible");
var response = await Http.PostAsJsonAsync("assertion-options", "username");

var options = await response.Content.ReadFromJsonAsync();

// exception thrown
var assertion = await js.InvokeAsync("verify", options);
}
catch (Exception ex)
{
Debug.Assert(ex.Message == "This is an invalid domain.\nundefined");
}
}
}

```

``` javascript
export function isWebAuthnPossible() {
return !!window.PublicKeyCredential;
}

export async function verify(options) {
if (typeof options.challenge === 'string')
options.challenge = fromBase64Url(options.challenge);
if (options.allowCredentials) {
for (var i = 0; i < options.allowCredentials.length; i++) {
const id = options.allowCredentials[i].id;
if (typeof id === 'string')
options.allowCredentials[i].id = fromBase64Url(id);
}
}
var creds = await navigator.credentials.get({ publicKey: options });
const response = creds.response;
const retval = {
id: creds.id,
rawId: toBase64Url(creds.rawId),
type: creds.type,
clientExtensionResults: creds.getClientExtensionResults(),
response: {
authenticatorData: toBase64Url(response.authenticatorData),
clientDataJSON: toBase64Url(response.clientDataJSON),
userHandle: response.userHandle && response.userHandle.byteLength > 0 ? toBase64Url(response.userHandle) : undefined,
signature: toBase64Url(response.signature)
}
}
return retval;
}
```

### Steps to Reproduce

1. Create a blazor hybrid app , see [docs](https://learn.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/windows-forms?view=aspnetcore-10.0)
2. create a component and js file above.
3. click button

### Link to public reproduction project repository

_No response_

### Version with bug

10.0.0-rc.2

### Is this a regression from previous behavior?

No, this is something new

### Last version that worked well

Unknown/Other

### Affected platforms

Windows

### Affected platform versions

_No response_

### Did you find any workaround?

For someone wants use passkey with winform app + blazor. Here is the temp solution:
1. create a empty winform app
2. add nuget package `Microsoft.Web.WebView2`
3. add `WebView2` control to your form by using winform designer.
4. right click the `WebView2` control-> Properties
5. set Dock: "Fill" , Source : "https://yourdomain.com/index.html"
6. publish your blazor webassembly(contains auth dance logic) to your server (yourdomain.com)

Helper link:

- [Get started with WebView2 in WinForms apps](https://learn.microsoft.com/en-us/microsoft-edge/webview2/get-started/winforms)
- [Host and deploy ASP.NET Core Blazor WebAssembly](https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/webassembly/?view=aspnetcore-9.0&tabs=windows)

### Relevant log output

```shell

```

Contributor guide

Open the contributing guide

Research direction

Start with the Windows BlazorWebView reproduction and the Home.razor.js module shown in the report; run the passkey flow through navigator.credentials.get and capture the exception. Trace the JS interop and WebView host behavior around the reported invalid-domain failure. Done means the supplied flow works on Windows or the limitation and supported path are documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, javascript
Domain
authentication, desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.