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:
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:
The host app tells the WebView2 control to navigate to a URI.
The WebView2 control talks to the HTTP server requesting to get the document at a specified URI.
The HTTP server replies to the WebView2 control, saying "You can't get that URI (document) without authentication."
The WebView2 control tells the host app "Authentication is needed" (which is the BasicAuthenticationRequested event).
The host app responds to that event by providing the username and password to the WebView2 control.
The WebView2 control again requests the URI from the HTTP server, but this time with the authentication (username and password).
The HTTP server evaluates the credentials (username and password).
The HTTP server might deny the credentials and request new credentials.
The HTTP server might reject the username and password; it might tell the WebView2 control "You're not permitted to get that URI/document".
The WebView2 control renders the error page that's returned by the HTTP server. The rendering occurs between the ContentLoading event and DOMContentLoaded event.
The HTTP server might accept the authentication credentials and return the requested document.
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
// 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";
};
// 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(
newchar[] { '\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);
};
// Prerequisite: Before using this code, make sure you read the section "Use HTTPS // for sending credentials" in this article.if (auto webView10 = m_webView.try_query<ICoreWebView2_10>())
{
CHECK_FAILURE(webView10->add_BasicAuthenticationRequested(
Callback<ICoreWebView2BasicAuthenticationRequestedEventHandler>(
[this](
ICoreWebView2* sender,
ICoreWebView2BasicAuthenticationRequestedEventArgs* argsRaw)
{
// Make a smart pointer copy of the event args so we can take it// into our lambda below.
wil::com_ptr<ICoreWebView2BasicAuthenticationRequestedEventArgs>
args = argsRaw;
// 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.
wil::com_ptr<ICoreWebView2Deferral> deferral;
CHECK_FAILURE(args->GetDeferral(&deferral));
HWND mainWindowHwnd = m_appWindow->GetMainWindow();
m_appWindow->RunAsync([args, deferral, mainWindowHwnd]()
{
wil::com_ptr<ICoreWebView2BasicAuthenticationResponse>
basicAuthenticationResponse;
CHECK_FAILURE(args->get_Response(&basicAuthenticationResponse));
wil::unique_cotaskmem_string uri;
CHECK_FAILURE(args->get_Uri(&uri));
wil::unique_cotaskmem_string challenge;
CHECK_FAILURE(args->get_Challenge(&challenge));
// 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.std::wstring prompt = L"Authentication request from ";
prompt += uri.get();
// 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.
prompt += L"\r\nChallenge: ";
prompt += challenge.get();
// Use an app or UI framework method to get input from the end user.
TextInputDialog dialog(
mainWindowHwnd,
L"Authentication Request",
L"User name and password",
prompt.c_str(),
L"username\r\npassword");
bool userNameAndPasswordSet = false;
if (dialog.confirmed)
{
conststd::wstring& userNameAndPassword = dialog.input;
std::size_t separatorIdx = userNameAndPassword.find(L"\r\n");
if (separatorIdx != std::wstring::npos)
{
std::wstring userName =
userNameAndPassword.substr(0, separatorIdx);
std::wstring password =
userNameAndPassword.substr(separatorIdx + 2);
basicAuthenticationResponse->put_UserName(userName.c_str());
basicAuthenticationResponse->put_Password(password.c_str());
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->put_Cancel(TRUE);
}
// We've finished our asynchronous work and so we complete the// deferral to let the CoreWebView2 know that we're done changing// values on the event args.
deferral->Complete();
});
return S_OK;
})
.Get(),
&m_basicAuthenticationRequestedToken));
}
else
{
FeatureNotAvailable();
}
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.
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.