Upravit

Sdílet prostřednictvím


Basic authentication for WebView2 apps

Basic authentication is an authentication approach that's part of the HTTP protocol.

Basic authentication for WebView2 apps includes a sequence of authentication and navigation steps to retrieve a webpage from an HTTP server. The WebView2 control acts as an intermediary for communication between the host app and the HTTP server.

Use HTTPS for sending credentials

Warning: You must use HTTPS when using Basic Authentication. Otherwise the username and password are not encrypted. You may want to consider other forms of authentication.

The HTTP standard for basic authentication includes the authentication credentials (username and password) unencrypted. Therefore, you must use https, to ensure that the credentials are encrypted.

The order of navigation events

The basic authentication event happens in the middle of the sequence of events:

  1. NavigationStarting - navigation event
  2. ContentLoading - navigation event
  3. BasicAuthenticationRequested
  4. DOMContentLoaded
  5. NavigationCompleted - navigation event

For more information, see Navigation events for WebView2 apps.

Communication between the HTTP server, WebView2 control, and host app

  • The HTTP server checks authentication (username and password credentials) and returns either an error document or the requested webpage.

  • The WebView2 control instance raises the events. The WebView2 control sits between the HTTP server and the host app. The WebView2 control serves as an intermediary for communication between the host app and the HTTP server.

  • You write the host app. The host app sets the user name and password on the event's arguments (EventArgs) response objects.

BasicAuthenticationRequestedEventArgs has a Response property. The Response property is an object that contains the username and password properties.

Sequence of navigation events

The following diagram shows the flow of navigation events for basic authentication for WebView2 apps:

Flow of navigation events for basic authentication for WebView2 apps

  1. The host app tells the WebView2 control to navigate to a URI.

  2. The WebView2 control talks to the HTTP server requesting to get the document at a specified URI.

  3. The HTTP server replies to the WebView2 control, saying "You can't get that URI (document) without authentication."

  4. The WebView2 control tells the host app "Authentication is needed" (which is the BasicAuthenticationRequested event).

  5. The host app responds to that event by providing the username and password to the WebView2 control.

  6. The WebView2 control again requests the URI from the HTTP server, but this time with the authentication (username and password).

  7. The HTTP server evaluates the credentials (username and password).

  8. The HTTP server might deny the credentials and request new credentials.

  9. The HTTP server might reject the username and password; it might tell the WebView2 control "You're not permitted to get that URI/document".

  10. The WebView2 control renders the error page that's returned by the HTTP server. The rendering occurs between the ContentLoading event and DOMContentLoaded event.

  11. The HTTP server might accept the authentication credentials and return the requested document.

  12. The WebView2 control renders the returned document. The rendering occurs between the ContentLoading event and DOMContentLoaded event.

Example code: App providing credentials that are known ahead of time

The following simplified example shows the host app providing credentials (user name and password) that are known ahead of time. This example is a slightly modified version of the code that's in WebView2Samples repo > WebView2APISample > ScenarioAuthentication.cpp.

This example isn't realistic, because:

  • In practice, you'd prompt the user for the username and password rather than hardcoding them like "user" and "pass".
  • This code is synchronous, but you'd probably use asynchronous code instead.

For more realistic code, see the subsequent section.

// Prerequisite: Before using this code, make sure you read the section "Use HTTPS 
// for sending credentials" in this article.
    webView.CoreWebView2.BasicAuthenticationRequested += delegate (
       object sender, 
       CoreWebView2BasicAuthenticationRequestedEventArgs args)
    {
        args.Response.UserName = "user";
        args.Response.Password = "pass";
    };

APIs:

Example code: Prompting user for credentials

This example demonstrates a host app prompting the user for credentials (user name and password), and uses async code.

This example builds upon the above sample, by adding the following features:

  • Displays a dialog to prompt the user for their username and password.
  • Calls the GetDeferral method on the event argument.
// Prerequisite: Before using this code, make sure you read the section "Use HTTPS 
// for sending credentials" in this article.
webView.CoreWebView2.BasicAuthenticationRequested += delegate (
    object sender, 
    CoreWebView2BasicAuthenticationRequestedEventArgs args)
{
    // We need to show UI asynchronously so we obtain a deferral.
    // A deferral will delay the CoreWebView2 from
    // examining the properties we set on the event args until
    // after we call the Complete method asynchronously later.
    // This gives us time to asynchronously show UI.
    CoreWebView2Deferral deferral = args.GetDeferral();

    // We avoid potential reentrancy from running a message loop in the
    // event handler by showing our download dialog later when we
    // complete the deferral asynchronously.
    System.Threading.SynchronizationContext.Current.Post((_) =>
    {
        using (deferral)
        {
            // When prompting the end user for authentication its important
            // to show them the URI or origin of the URI that is requesting
            // authentication so the end user will know who they are giving
            // their username and password to.

            // Its also important to display the challenge to the end user
            // as it may have important site specific information for the
            // end user to provide the correct username and password.

            // Use an app or UI framework method to get input from the end user.
            TextInputDialog dialog = new TextInputDialog(
                title: "Authentication Request",
                description: "Authentication request from " + args.Uri + "\r\n" +
                    "Challenge: " + args.Challenge,
                defaultInput: "username\r\npassword");
            bool userNameAndPasswordSet = false;

            if (dialog.ShowDialog().GetValueOrDefault(false))
            {
                string[] userNameAndPassword = dialog.Input.Text.Split(
                    new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                if (userNameAndPassword.Length > 1)
                {
                    args.Response.UserName = userNameAndPassword[0];
                    args.Response.Password = userNameAndPassword[1];
                    userNameAndPasswordSet = true;
                }
            }

            // If we didn't get a username and password from the end user then
            // we cancel the authentication request and don't provide any
            // authentication.
            if (!userNameAndPasswordSet)
            {
                args.Cancel = true;
            }
        }
    }, null);
};

APIs:

How navigations work

This section provides optional background information about how navigations work.

A navigation corresponds to multiple navigation events. By navigation, we here mean each retry, starting with the NavigationStarting box of the above diagram, through the NavigationCompleted box.

When a new navigation begins, a new navigation ID is assigned. For the new navigation, the HTTP server gave the WebView2 control a document. This is the "have document" navigation.

As a part of navigation, the WebView2 control renders the corresponding page (the requested page or an error page, whichever is returned by the HTTP server), and a "success" or "failure" outcome raises a successful or failed NavigationCompleted event.

For more information, see Navigation events for WebView2 apps.

There are two kinds of navigations in the flow:

  • A "server requested authentication" navigation.
  • A "server gave the WebView2 control a document" navigation.

After the first type of navigation, the server has asked for authentication and the app needs to try that kind of navigation again (with a new navigation ID). The new navigation will use whatever the host app gets from the events arguments response objects.

An HTTP server may require HTTP authentication. In this case, there's a first navigation, which has the navigation events that are listed above. The HTTP server returns a 401 or 407 HTTP response, and so the NavigationCompleted event has a corresponding failure. The WebView2 then renders a blank page, and raise the BasicAuthenticationRequested event, which will potentially prompt the user for credentials.

If the BasicAuthenticationRequested event is canceled, then there's no subsequent navigation and the WebView2 will remain to display the blank page.

If the BasicAuthenticationRequested event isn't canceled, the WebView2 will perform the initial navigation again, but this time, using any provided credentials. You'll again see all the same navigation events as before.

If the credentials aren't accepted by the HTTP server, navigation fails again with 401 or 407. In that case, the CoreWebView2 class instance again raises the BasicAuthenticationRequested event, and navigation continues as above.

The navigation succeeds if the credentials are accepted by the HTTP server. The navigation fails if the HTTP server denies authentication (the server typically returns an error page).

The navigations before and after the BasicAuthenticationRequested event are distinct navigations and have distinct navigation IDs.

Navigation event args has a property: the NavigationId. The NavigationId ties together navigation events that correspond to a single navigation. The NavigationId remains the same during each navigation, such as a retry. During the next pass through the event flow, a different NavigationId is used.

API Reference overview

See also