[webview_flutter] Support for handling basic authentication requests (iOS) (#5455)

Adds the iOS implementation for basic http authentication.

This PR is part of a series of PRs that aim to close https://github.com/flutter/flutter/issues/83556.
The PR that contains all changes can be found at https://github.com/flutter/packages/pull/4140.
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
index d95a843..cc60d2d 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
+++ b/packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 3.10.0
 
+* Adds support for `PlatformNavigationDelegate.setOnHttpAuthRequest`.
 * Updates minimum supported SDK version to Flutter 3.10/Dart 3.0.
 
 ## 3.9.4
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
index 64d7702..89ecad8 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/integration_test/webview_flutter_test.dart
@@ -34,6 +34,15 @@
       request.response.writeln('${request.headers}');
     } else if (request.uri.path == '/favicon.ico') {
       request.response.statusCode = HttpStatus.notFound;
+    } else if (request.uri.path == '/http-basic-authentication') {
+      final bool isAuthenticating = request.headers['Authorization'] != null;
+      if (isAuthenticating) {
+        request.response.writeln('Authorized');
+      } else {
+        request.response.headers
+            .add('WWW-Authenticate', 'Basic realm="Test realm"');
+        request.response.statusCode = HttpStatus.unauthorized;
+      }
     } else {
       fail('unexpected request: ${request.method} ${request.uri}');
     }
@@ -43,6 +52,7 @@
   final String primaryUrl = '$prefixUrl/hello.txt';
   final String secondaryUrl = '$prefixUrl/secondary.txt';
   final String headersUrl = '$prefixUrl/headers';
+  final String basicAuthUrl = '$prefixUrl/http-basic-authentication';
 
   testWidgets(
       'withWeakReferenceTo allows encapsulating class to be garbage collected',
@@ -1127,6 +1137,82 @@
     });
   });
 
+  testWidgets('can receive HTTP basic auth requests',
+      (WidgetTester tester) async {
+    final Completer<void> authRequested = Completer<void>();
+    final PlatformWebViewController controller = PlatformWebViewController(
+      const PlatformWebViewControllerCreationParams(),
+    );
+
+    final PlatformNavigationDelegate navigationDelegate =
+        PlatformNavigationDelegate(
+      const PlatformNavigationDelegateCreationParams(),
+    );
+    await navigationDelegate.setOnHttpAuthRequest(
+        (HttpAuthRequest request) => authRequested.complete());
+    await controller.setPlatformNavigationDelegate(navigationDelegate);
+
+    // Clear cache so that the auth request is always received and we don't get
+    // a cached response.
+    await controller.clearCache();
+
+    await tester.pumpWidget(
+      Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            WebKitWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ),
+    );
+
+    await controller.loadRequest(
+      LoadRequestParams(uri: Uri.parse(basicAuthUrl)),
+    );
+
+    await expectLater(authRequested.future, completes);
+  });
+
+  testWidgets('can reply to HTTP basic auth requests',
+      (WidgetTester tester) async {
+    final Completer<void> pageFinished = Completer<void>();
+    final PlatformWebViewController controller = PlatformWebViewController(
+      const PlatformWebViewControllerCreationParams(),
+    );
+
+    final PlatformNavigationDelegate navigationDelegate =
+        PlatformNavigationDelegate(
+      const PlatformNavigationDelegateCreationParams(),
+    );
+    await navigationDelegate.setOnPageFinished((_) => pageFinished.complete());
+    await navigationDelegate.setOnHttpAuthRequest(
+      (HttpAuthRequest request) => request.onProceed(
+        const WebViewCredential(user: 'user', password: 'password'),
+      ),
+    );
+    await controller.setPlatformNavigationDelegate(navigationDelegate);
+
+    // Clear cache so that the auth request is always received and we don't get
+    // a cached response.
+    await controller.clearCache();
+
+    await tester.pumpWidget(
+      Builder(
+        builder: (BuildContext context) {
+          return PlatformWebViewWidget(
+            WebKitWebViewWidgetCreationParams(controller: controller),
+          ).build(context);
+        },
+      ),
+    );
+
+    await controller.loadRequest(
+      LoadRequestParams(uri: Uri.parse(basicAuthUrl)),
+    );
+
+    await expectLater(pageFinished.future, completes);
+  });
+
   testWidgets('launches with gestureNavigationEnabled on iOS',
       (WidgetTester tester) async {
     final WebKitWebViewController controller = WebKitWebViewController(
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj
index 32c0bf9..5b13eba 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/project.pbxproj
@@ -11,6 +11,9 @@
 		3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
 		8F4FF949299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F4FF948299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m */; };
 		8F4FF94B29AC223F000A6586 /* FWFURLTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F4FF94A29AC223F000A6586 /* FWFURLTests.m */; };
+		8F562F902A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F562F8F2A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m */; };
+		8F562F922A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F562F912A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m */; };
+		8F562F942A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F562F932A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m */; };
 		8F78EAAA2A02CB9100C2E520 /* FWFErrorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F78EAA92A02CB9100C2E520 /* FWFErrorTests.m */; };
 		8FA6A87928062CD000A4B183 /* FWFInstanceManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8FA6A87828062CD000A4B183 /* FWFInstanceManagerTests.m */; };
 		8FB79B5328134C3100C101D3 /* FWFWebViewHostApiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8FB79B5228134C3100C101D3 /* FWFWebViewHostApiTests.m */; };
@@ -81,6 +84,9 @@
 		7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
 		8F4FF948299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FWFWebViewFlutterWKWebViewExternalAPITests.m; sourceTree = "<group>"; };
 		8F4FF94A29AC223F000A6586 /* FWFURLTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLTests.m; sourceTree = "<group>"; };
+		8F562F8F2A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLCredentialHostApiTests.m; sourceTree = "<group>"; };
+		8F562F912A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLProtectionSpaceHostApiTests.m; sourceTree = "<group>"; };
+		8F562F932A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFURLAuthenticationChallengeHostApiTests.m; sourceTree = "<group>"; };
 		8F78EAA92A02CB9100C2E520 /* FWFErrorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFErrorTests.m; sourceTree = "<group>"; };
 		8FA6A87828062CD000A4B183 /* FWFInstanceManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFInstanceManagerTests.m; sourceTree = "<group>"; };
 		8FB79B5228134C3100C101D3 /* FWFWebViewHostApiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FWFWebViewHostApiTests.m; sourceTree = "<group>"; };
@@ -167,6 +173,9 @@
 				8FB79B902820BAC700C101D3 /* FWFUIViewHostApiTests.m */,
 				8FB79B962821985200C101D3 /* FWFObjectHostApiTests.m */,
 				8F4FF94A29AC223F000A6586 /* FWFURLTests.m */,
+				8F562F8F2A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m */,
+				8F562F912A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m */,
+				8F562F932A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m */,
 				8F78EAA92A02CB9100C2E520 /* FWFErrorTests.m */,
 			);
 			path = RunnerTests;
@@ -318,7 +327,7 @@
 			isa = PBXProject;
 			attributes = {
 				DefaultBuildSystemTypeForWorkspace = Original;
-				LastUpgradeCheck = 1300;
+				LastUpgradeCheck = 1430;
 				ORGANIZATIONNAME = "The Flutter Authors";
 				TargetAttributes = {
 					68BDCAE823C3F7CB00D9C032 = {
@@ -327,7 +336,6 @@
 					};
 					97C146ED1CF9000F007C117D = {
 						CreatedOnToolsVersion = 7.3.1;
-						DevelopmentTeam = 7624MWN53C;
 					};
 					F7151F73266057800028CB91 = {
 						CreatedOnToolsVersion = 12.5;
@@ -474,12 +482,15 @@
 				8FB79B852820A3A400C101D3 /* FWFUIDelegateHostApiTests.m in Sources */,
 				8FB79B972821985200C101D3 /* FWFObjectHostApiTests.m in Sources */,
 				8FB79B672820453400C101D3 /* FWFHTTPCookieStoreHostApiTests.m in Sources */,
+				8F562F942A56C07B00C2BED6 /* FWFURLAuthenticationChallengeHostApiTests.m in Sources */,
 				8FB79B5328134C3100C101D3 /* FWFWebViewHostApiTests.m in Sources */,
 				8FB79B73282096B500C101D3 /* FWFScriptMessageHandlerHostApiTests.m in Sources */,
 				8FB79B7928209D1300C101D3 /* FWFUserContentControllerHostApiTests.m in Sources */,
+				8F562F902A56C02D00C2BED6 /* FWFURLCredentialHostApiTests.m in Sources */,
 				8F4FF949299ADC2D000A6586 /* FWFWebViewFlutterWKWebViewExternalAPITests.m in Sources */,
 				8FB79B6B28204EE500C101D3 /* FWFWebsiteDataStoreHostApiTests.m in Sources */,
 				8FB79B8F2820BAB300C101D3 /* FWFScrollViewHostApiTests.m in Sources */,
+				8F562F922A56C04F00C2BED6 /* FWFURLProtectionSpaceHostApiTests.m in Sources */,
 				8FB79B912820BAC700C101D3 /* FWFUIViewHostApiTests.m in Sources */,
 				8FB79B55281B24F600C101D3 /* FWFDataConvertersTests.m in Sources */,
 				8FB79B6D2820533B00C101D3 /* FWFWebViewConfigurationHostApiTests.m in Sources */,
@@ -689,6 +700,7 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+				DEVELOPMENT_TEAM = 7624MWN53C;
 				ENABLE_BITCODE = NO;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
@@ -715,6 +727,7 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+				DEVELOPMENT_TEAM = 7624MWN53C;
 				ENABLE_BITCODE = NO;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index cb713d7..cf07c46 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1300"
+   LastUpgradeVersion = "1430"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFNavigationDelegateHostApiTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFNavigationDelegateHostApiTests.m
index 669234d..dc4cb3c 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFNavigationDelegateHostApiTests.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFNavigationDelegateHostApiTests.m
@@ -213,4 +213,58 @@
                                                   webViewIdentifier:1
                                                          completion:OCMOCK_ANY]);
 }
+
+- (void)testDidReceiveAuthenticationChallenge {
+  FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
+
+  FWFNavigationDelegate *mockDelegate = [self mockNavigationDelegateWithManager:instanceManager
+                                                                     identifier:0];
+  FWFNavigationDelegateFlutterApiImpl *mockFlutterAPI =
+      [self mockFlutterApiWithManager:instanceManager];
+
+  OCMStub([mockDelegate navigationDelegateAPI]).andReturn(mockFlutterAPI);
+
+  WKWebView *mockWebView = OCMClassMock([WKWebView class]);
+  [instanceManager addDartCreatedInstance:mockWebView withIdentifier:1];
+
+  NSURLAuthenticationChallenge *mockChallenge = OCMClassMock([NSURLAuthenticationChallenge class]);
+  NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"host"
+                                                                                port:0
+                                                                            protocol:nil
+                                                                               realm:@"realm"
+                                                                authenticationMethod:nil];
+  OCMStub([mockChallenge protectionSpace]).andReturn(protectionSpace);
+  [instanceManager addDartCreatedInstance:mockChallenge withIdentifier:2];
+
+  NSURLCredential *credential = [NSURLCredential credentialWithUser:@"user"
+                                                           password:@"password"
+                                                        persistence:NSURLCredentialPersistenceNone];
+  [instanceManager addDartCreatedInstance:credential withIdentifier:5];
+
+  OCMStub([mockFlutterAPI
+      didReceiveAuthenticationChallengeForDelegateWithIdentifier:0
+                                               webViewIdentifier:1
+                                             challengeIdentifier:2
+                                                      completion:
+                                                          ([OCMArg
+                                                              invokeBlockWithArgs:
+                                                                  [FWFAuthenticationChallengeResponse
+                                                                       makeWithDisposition:
+                                                                           FWFNSUrlSessionAuthChallengeDispositionCancelAuthenticationChallenge
+                                                                      credentialIdentifier:@(5)],
+                                                                  [NSNull null], nil])]);
+
+  NSURLSessionAuthChallengeDisposition __block callbackDisposition = -1;
+  NSURLCredential *__block callbackCredential;
+  [mockDelegate webView:mockWebView
+      didReceiveAuthenticationChallenge:mockChallenge
+                      completionHandler:^(NSURLSessionAuthChallengeDisposition disposition,
+                                          NSURLCredential *credential) {
+                        callbackDisposition = disposition;
+                        callbackCredential = credential;
+                      }];
+
+  XCTAssertEqual(callbackDisposition, NSURLSessionAuthChallengeCancelAuthenticationChallenge);
+  XCTAssertEqualObjects(callbackCredential, credential);
+}
 @end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLAuthenticationChallengeHostApiTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLAuthenticationChallengeHostApiTests.m
new file mode 100644
index 0000000..fc0edf9
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLAuthenticationChallengeHostApiTests.m
@@ -0,0 +1,47 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+@import Flutter;
+@import XCTest;
+@import webview_flutter_wkwebview;
+
+#import <OCMock/OCMock.h>
+
+@interface FWFURLAuthenticationChallengeHostApiTests : XCTestCase
+
+@end
+
+@implementation FWFURLAuthenticationChallengeHostApiTests
+- (void)testFlutterApiCreate {
+  FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
+  FWFURLAuthenticationChallengeFlutterApiImpl *flutterApi =
+      [[FWFURLAuthenticationChallengeFlutterApiImpl alloc]
+          initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
+                  instanceManager:instanceManager];
+
+  flutterApi.api = OCMClassMock([FWFNSUrlAuthenticationChallengeFlutterApi class]);
+
+  NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"host"
+                                                                                port:0
+                                                                            protocol:nil
+                                                                               realm:@"realm"
+                                                                authenticationMethod:nil];
+
+  NSURLAuthenticationChallenge *mockChallenge = OCMClassMock([NSURLAuthenticationChallenge class]);
+  OCMStub([mockChallenge protectionSpace]).andReturn(protectionSpace);
+
+  [flutterApi createWithInstance:mockChallenge
+                 protectionSpace:protectionSpace
+                      completion:^(FlutterError *error){
+
+                      }];
+
+  long identifier = [instanceManager identifierWithStrongReferenceForInstance:mockChallenge];
+  long protectionSpaceIdentifier =
+      [instanceManager identifierWithStrongReferenceForInstance:protectionSpace];
+  OCMVerify([flutterApi.api createWithIdentifier:identifier
+                       protectionSpaceIdentifier:protectionSpaceIdentifier
+                                      completion:OCMOCK_ANY]);
+}
+@end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLCredentialHostApiTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLCredentialHostApiTests.m
new file mode 100644
index 0000000..7f3aa34
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLCredentialHostApiTests.m
@@ -0,0 +1,35 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+@import Flutter;
+@import XCTest;
+@import webview_flutter_wkwebview;
+
+#import <OCMock/OCMock.h>
+
+@interface FWFURLCredentialHostApiTests : XCTestCase
+@end
+
+@implementation FWFURLCredentialHostApiTests
+- (void)testHostApiCreate {
+  FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
+
+  FWFURLCredentialHostApiImpl *hostApi = [[FWFURLCredentialHostApiImpl alloc]
+      initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
+              instanceManager:instanceManager];
+
+  FlutterError *error;
+  [hostApi createWithUserWithIdentifier:0
+                                   user:@"user"
+                               password:@"password"
+                            persistence:FWFNSUrlCredentialPersistencePermanent
+                                  error:&error];
+  XCTAssertNil(error);
+
+  NSURLCredential *credential = (NSURLCredential *)[instanceManager instanceForIdentifier:0];
+  XCTAssertEqualObjects(credential.user, @"user");
+  XCTAssertEqualObjects(credential.password, @"password");
+  XCTAssertEqual(credential.persistence, NSURLCredentialPersistencePermanent);
+}
+@end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLProtectionSpaceHostApiTests.m b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLProtectionSpaceHostApiTests.m
new file mode 100644
index 0000000..c5a6cdf
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/ios/RunnerTests/FWFURLProtectionSpaceHostApiTests.m
@@ -0,0 +1,43 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+@import Flutter;
+@import XCTest;
+@import webview_flutter_wkwebview;
+
+#import <OCMock/OCMock.h>
+
+@interface FWFURLProtectionSpaceHostApiTests : XCTestCase
+@end
+
+@implementation FWFURLProtectionSpaceHostApiTests
+- (void)testFlutterApiCreate {
+  FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
+  FWFURLProtectionSpaceFlutterApiImpl *flutterApi = [[FWFURLProtectionSpaceFlutterApiImpl alloc]
+      initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
+              instanceManager:instanceManager];
+
+  flutterApi.api = OCMClassMock([FWFNSUrlProtectionSpaceFlutterApi class]);
+
+  NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"host"
+                                                                                port:0
+                                                                            protocol:nil
+                                                                               realm:@"realm"
+                                                                authenticationMethod:nil];
+  [flutterApi createWithInstance:protectionSpace
+                            host:@"host"
+                           realm:@"realm"
+            authenticationMethod:@"method"
+                      completion:^(FlutterError *error){
+
+                      }];
+
+  long identifier = [instanceManager identifierWithStrongReferenceForInstance:protectionSpace];
+  OCMVerify([flutterApi.api createWithIdentifier:identifier
+                                            host:@"host"
+                                           realm:@"realm"
+                            authenticationMethod:@"method"
+                                      completion:OCMOCK_ANY]);
+}
+@end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
index 8f3dfa8..c237018 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/lib/main.dart
@@ -162,6 +162,9 @@
           })
           ..setOnUrlChange((UrlChange change) {
             debugPrint('url change to ${change.url}');
+          })
+          ..setOnHttpAuthRequest((HttpAuthRequest request) {
+            openDialog(request);
           }),
       )
       ..addJavaScriptChannel(JavaScriptChannelParams(
@@ -220,6 +223,62 @@
       child: const Icon(Icons.favorite),
     );
   }
+
+  Future<void> openDialog(HttpAuthRequest httpRequest) async {
+    final TextEditingController usernameTextController =
+        TextEditingController();
+    final TextEditingController passwordTextController =
+        TextEditingController();
+
+    return showDialog(
+      context: context,
+      barrierDismissible: false,
+      builder: (BuildContext context) {
+        return AlertDialog(
+          title: Text('${httpRequest.host}: ${httpRequest.realm ?? '-'}'),
+          content: SingleChildScrollView(
+            child: Column(
+              mainAxisSize: MainAxisSize.min,
+              children: <Widget>[
+                TextField(
+                  decoration: const InputDecoration(labelText: 'Username'),
+                  autofocus: true,
+                  controller: usernameTextController,
+                ),
+                TextField(
+                  decoration: const InputDecoration(labelText: 'Password'),
+                  controller: passwordTextController,
+                ),
+              ],
+            ),
+          ),
+          actions: <Widget>[
+            // Explicitly cancel the request on iOS as the OS does not emit new
+            // requests when a previous request is pending.
+            TextButton(
+              onPressed: () {
+                httpRequest.onCancel();
+                Navigator.of(context).pop();
+              },
+              child: const Text('Cancel'),
+            ),
+            TextButton(
+              onPressed: () {
+                httpRequest.onProceed(
+                  WebViewCredential(
+                    user: usernameTextController.text,
+                    password: passwordTextController.text,
+                  ),
+                );
+                Navigator.of(context).pop();
+              },
+              child: const Text('Authenticate'),
+            ),
+          ],
+        );
+      },
+    );
+  }
 }
 
 enum MenuOptions {
@@ -237,6 +296,7 @@
   transparentBackground,
   setCookie,
   logExample,
+  basicAuthentication,
 }
 
 class SampleMenu extends StatelessWidget {
@@ -300,6 +360,9 @@
           case MenuOptions.logExample:
             _onLogExample();
             break;
+          case MenuOptions.basicAuthentication:
+            _promptForUrl(context);
+            break;
         }
       },
       itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
@@ -360,6 +423,10 @@
           value: MenuOptions.logExample,
           child: Text('Log example'),
         ),
+        const PopupMenuItem<MenuOptions>(
+          value: MenuOptions.basicAuthentication,
+          child: Text('Basic Authentication Example'),
+        ),
       ],
     );
   }
@@ -518,6 +585,41 @@
 
     return webViewController.loadHtmlString(kLogExamplePage);
   }
+
+  Future<void> _promptForUrl(BuildContext context) {
+    final TextEditingController urlTextController =
+        TextEditingController(text: 'https://');
+
+    return showDialog<String>(
+      context: context,
+      builder: (BuildContext context) {
+        return AlertDialog(
+          title: const Text('Input URL to visit'),
+          content: TextField(
+            decoration: const InputDecoration(labelText: 'URL'),
+            autofocus: true,
+            controller: urlTextController,
+          ),
+          actions: <Widget>[
+            TextButton(
+              onPressed: () {
+                if (urlTextController.text.isNotEmpty) {
+                  final Uri? uri = Uri.tryParse(urlTextController.text);
+                  if (uri != null && uri.scheme.isNotEmpty) {
+                    webViewController.loadRequest(
+                      LoadRequestParams(uri: uri),
+                    );
+                    Navigator.pop(context);
+                  }
+                }
+              },
+              child: const Text('Visit'),
+            ),
+          ],
+        );
+      },
+    );
+  }
 }
 
 class NavigationControls extends StatelessWidget {
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
index e4066c0..6590404 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_wkwebview/example/pubspec.yaml
@@ -10,7 +10,7 @@
   flutter:
     sdk: flutter
   path_provider: ^2.0.6
-  webview_flutter_platform_interface: ^2.6.0
+  webview_flutter_platform_interface: ^2.7.0
   webview_flutter_wkwebview:
     # When depending on this package from a real application you should use:
     #   webview_flutter: ^x.y.z
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m
index c3d6699..e776726 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FLTWebViewFlutterPlugin.m
@@ -13,6 +13,7 @@
 #import "FWFScrollViewHostApi.h"
 #import "FWFUIDelegateHostApi.h"
 #import "FWFUIViewHostApi.h"
+#import "FWFURLCredentialHostApi.h"
 #import "FWFURLHostApi.h"
 #import "FWFUserContentControllerHostApi.h"
 #import "FWFWebViewConfigurationHostApi.h"
@@ -105,6 +106,11 @@
                        [[FWFURLHostApiImpl alloc] initWithBinaryMessenger:registrar.messenger
                                                           instanceManager:instanceManager]);
 
+  SetUpFWFNSUrlCredentialHostApi(
+      registrar.messenger,
+      [[FWFURLCredentialHostApiImpl alloc] initWithBinaryMessenger:registrar.messenger
+                                                   instanceManager:instanceManager]);
+
   FWFWebViewFactory *webviewFactory = [[FWFWebViewFactory alloc] initWithManager:instanceManager];
   [registrar registerViewFactory:webviewFactory withId:@"plugins.flutter.io/webview"];
 
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.h
index 005cecb..e9405f3 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.h
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.h
@@ -193,4 +193,26 @@
 extern FWFWKMediaCaptureTypeData *FWFWKMediaCaptureTypeDataFromNativeWKMediaCaptureType(
     WKMediaCaptureType type);
 
+/**
+ * Converts an FWFNSUrlSessionAuthChallengeDisposition to an NSURLSessionAuthChallengeDisposition.
+ *
+ * @param value The object containing information to create an NSURLSessionAuthChallengeDisposition.
+ *
+ * @return A NSURLSessionAuthChallengeDisposition or -1 if data could not be converted.
+ */
+extern NSURLSessionAuthChallengeDisposition
+FWFNativeNSURLSessionAuthChallengeDispositionFromFWFNSUrlSessionAuthChallengeDisposition(
+    FWFNSUrlSessionAuthChallengeDisposition value);
+
+/**
+ * Converts an FWFNSUrlCredentialPersistence to an NSURLCredentialPersistence.
+ *
+ * @param value The object containing information to create an NSURLCredentialPersistence.
+ *
+ * @return A NSURLCredentialPersistence or -1 if data could not be converted.
+ */
+extern NSURLCredentialPersistence
+FWFNativeNSURLCredentialPersistenceFromFWFNSUrlCredentialPersistence(
+    FWFNSUrlCredentialPersistence value);
+
 NS_ASSUME_NONNULL_END
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.m
index 3cbcea8..a4dda8b 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFDataConverters.m
@@ -285,3 +285,36 @@
 
   return nil;
 }
+
+NSURLSessionAuthChallengeDisposition
+FWFNativeNSURLSessionAuthChallengeDispositionFromFWFNSUrlSessionAuthChallengeDisposition(
+    FWFNSUrlSessionAuthChallengeDisposition value) {
+  switch (value) {
+    case FWFNSUrlSessionAuthChallengeDispositionUseCredential:
+      return NSURLSessionAuthChallengeUseCredential;
+    case FWFNSUrlSessionAuthChallengeDispositionPerformDefaultHandling:
+      return NSURLSessionAuthChallengePerformDefaultHandling;
+    case FWFNSUrlSessionAuthChallengeDispositionCancelAuthenticationChallenge:
+      return NSURLSessionAuthChallengeCancelAuthenticationChallenge;
+    case FWFNSUrlSessionAuthChallengeDispositionRejectProtectionSpace:
+      return NSURLSessionAuthChallengeRejectProtectionSpace;
+  }
+
+  return -1;
+}
+
+NSURLCredentialPersistence FWFNativeNSURLCredentialPersistenceFromFWFNSUrlCredentialPersistence(
+    FWFNSUrlCredentialPersistence value) {
+  switch (value) {
+    case FWFNSUrlCredentialPersistenceNone:
+      return NSURLCredentialPersistenceNone;
+    case FWFNSUrlCredentialPersistenceSession:
+      return NSURLCredentialPersistenceForSession;
+    case FWFNSUrlCredentialPersistencePermanent:
+      return NSURLCredentialPersistencePermanent;
+    case FWFNSUrlCredentialPersistenceSynchronizable:
+      return NSURLCredentialPersistenceSynchronizable;
+  }
+
+  return -1;
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h
index 8469438..1e312a2 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.h
@@ -264,6 +264,73 @@
 - (instancetype)initWithValue:(FWFWKMediaCaptureType)value;
 @end
 
+/// Responses to an authentication challenge.
+///
+/// See
+/// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition?language=objc.
+typedef NS_ENUM(NSUInteger, FWFNSUrlSessionAuthChallengeDisposition) {
+  /// Use the specified credential, which may be nil.
+  ///
+  /// See
+  /// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeusecredential?language=objc.
+  FWFNSUrlSessionAuthChallengeDispositionUseCredential = 0,
+  /// Use the default handling for the challenge as though this delegate method
+  /// were not implemented.
+  ///
+  /// See
+  /// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeperformdefaulthandling?language=objc.
+  FWFNSUrlSessionAuthChallengeDispositionPerformDefaultHandling = 1,
+  /// Cancel the entire request.
+  ///
+  /// See
+  /// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengecancelauthenticationchallenge?language=objc.
+  FWFNSUrlSessionAuthChallengeDispositionCancelAuthenticationChallenge = 2,
+  /// Reject this challenge, and call the authentication delegate method again
+  /// with the next authentication protection space.
+  ///
+  /// See
+  /// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengerejectprotectionspace?language=objc.
+  FWFNSUrlSessionAuthChallengeDispositionRejectProtectionSpace = 3,
+};
+
+/// Wrapper for FWFNSUrlSessionAuthChallengeDisposition to allow for nullability.
+@interface FWFNSUrlSessionAuthChallengeDispositionBox : NSObject
+@property(nonatomic, assign) FWFNSUrlSessionAuthChallengeDisposition value;
+- (instancetype)initWithValue:(FWFNSUrlSessionAuthChallengeDisposition)value;
+@end
+
+/// Specifies how long a credential will be kept.
+typedef NS_ENUM(NSUInteger, FWFNSUrlCredentialPersistence) {
+  /// The credential should not be stored.
+  ///
+  /// See
+  /// https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencenone?language=objc.
+  FWFNSUrlCredentialPersistenceNone = 0,
+  /// The credential should be stored only for this session.
+  ///
+  /// See
+  /// https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistenceforsession?language=objc.
+  FWFNSUrlCredentialPersistenceSession = 1,
+  /// The credential should be stored in the keychain.
+  ///
+  /// See
+  /// https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencepermanent?language=objc.
+  FWFNSUrlCredentialPersistencePermanent = 2,
+  /// The credential should be stored permanently in the keychain, and in
+  /// addition should be distributed to other devices based on the owning Apple
+  /// ID.
+  ///
+  /// See
+  /// https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencesynchronizable?language=objc.
+  FWFNSUrlCredentialPersistenceSynchronizable = 3,
+};
+
+/// Wrapper for FWFNSUrlCredentialPersistence to allow for nullability.
+@interface FWFNSUrlCredentialPersistenceBox : NSObject
+@property(nonatomic, assign) FWFNSUrlCredentialPersistence value;
+- (instancetype)initWithValue:(FWFNSUrlCredentialPersistence)value;
+@end
+
 @class FWFNSKeyValueObservingOptionsEnumData;
 @class FWFNSKeyValueChangeKeyEnumData;
 @class FWFWKUserScriptInjectionTimeEnumData;
@@ -282,6 +349,7 @@
 @class FWFWKSecurityOriginData;
 @class FWFNSHttpCookieData;
 @class FWFObjectOrIdentifier;
+@class FWFAuthenticationChallengeResponse;
 
 @interface FWFNSKeyValueObservingOptionsEnumData : NSObject
 /// `init` unavailable to enforce nonnull fields, see the `make` class method.
@@ -462,6 +530,15 @@
 @property(nonatomic, assign) BOOL isIdentifier;
 @end
 
+@interface FWFAuthenticationChallengeResponse : NSObject
+/// `init` unavailable to enforce nonnull fields, see the `make` class method.
+- (instancetype)init NS_UNAVAILABLE;
++ (instancetype)makeWithDisposition:(FWFNSUrlSessionAuthChallengeDisposition)disposition
+               credentialIdentifier:(nullable NSNumber *)credentialIdentifier;
+@property(nonatomic, assign) FWFNSUrlSessionAuthChallengeDisposition disposition;
+@property(nonatomic, strong, nullable) NSNumber *credentialIdentifier;
+@end
+
 /// The codec used by FWFWKWebsiteDataStoreHostApi.
 NSObject<FlutterMessageCodec> *FWFWKWebsiteDataStoreHostApiGetCodec(void);
 
@@ -711,6 +788,14 @@
                                                            completion:
                                                                (void (^)(FlutterError *_Nullable))
                                                                    completion;
+- (void)didReceiveAuthenticationChallengeForDelegateWithIdentifier:(NSInteger)identifier
+                                                 webViewIdentifier:(NSInteger)webViewIdentifier
+                                               challengeIdentifier:(NSInteger)challengeIdentifier
+                                                        completion:
+                                                            (void (^)(
+                                                                FWFAuthenticationChallengeResponse
+                                                                    *_Nullable,
+                                                                FlutterError *_Nullable))completion;
 @end
 
 /// The codec used by FWFNSObjectHostApi.
@@ -919,4 +1004,65 @@
                   completion:(void (^)(FlutterError *_Nullable))completion;
 @end
 
+/// The codec used by FWFNSUrlCredentialHostApi.
+NSObject<FlutterMessageCodec> *FWFNSUrlCredentialHostApiGetCodec(void);
+
+/// Host API for `NSUrlCredential`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or handle method calls on the associated
+/// native class or an instance of the class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlcredential?language=objc.
+@protocol FWFNSUrlCredentialHostApi
+/// Create a new native instance and add it to the `InstanceManager`.
+- (void)createWithUserWithIdentifier:(NSInteger)identifier
+                                user:(NSString *)user
+                            password:(NSString *)password
+                         persistence:(FWFNSUrlCredentialPersistence)persistence
+                               error:(FlutterError *_Nullable *_Nonnull)error;
+@end
+
+extern void SetUpFWFNSUrlCredentialHostApi(id<FlutterBinaryMessenger> binaryMessenger,
+                                           NSObject<FWFNSUrlCredentialHostApi> *_Nullable api);
+
+/// The codec used by FWFNSUrlProtectionSpaceFlutterApi.
+NSObject<FlutterMessageCodec> *FWFNSUrlProtectionSpaceFlutterApiGetCodec(void);
+
+/// Flutter API for `NSUrlProtectionSpace`.
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlprotectionspace?language=objc.
+@interface FWFNSUrlProtectionSpaceFlutterApi : NSObject
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;
+/// Create a new Dart instance and add it to the `InstanceManager`.
+- (void)createWithIdentifier:(NSInteger)identifier
+                        host:(nullable NSString *)host
+                       realm:(nullable NSString *)realm
+        authenticationMethod:(nullable NSString *)authenticationMethod
+                  completion:(void (^)(FlutterError *_Nullable))completion;
+@end
+
+/// The codec used by FWFNSUrlAuthenticationChallengeFlutterApi.
+NSObject<FlutterMessageCodec> *FWFNSUrlAuthenticationChallengeFlutterApiGetCodec(void);
+
+/// Flutter API for `NSUrlAuthenticationChallenge`.
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+///
+/// See
+/// https://developer.apple.com/documentation/foundation/nsurlauthenticationchallenge?language=objc.
+@interface FWFNSUrlAuthenticationChallengeFlutterApi : NSObject
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;
+/// Create a new Dart instance and add it to the `InstanceManager`.
+- (void)createWithIdentifier:(NSInteger)identifier
+    protectionSpaceIdentifier:(NSInteger)protectionSpaceIdentifier
+                   completion:(void (^)(FlutterError *_Nullable))completion;
+@end
+
 NS_ASSUME_NONNULL_END
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m
index 52fbbee..5d80178 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFGeneratedWebKitApis.m
@@ -164,6 +164,31 @@
 }
 @end
 
+/// Responses to an authentication challenge.
+///
+/// See
+/// https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition?language=objc.
+@implementation FWFNSUrlSessionAuthChallengeDispositionBox
+- (instancetype)initWithValue:(FWFNSUrlSessionAuthChallengeDisposition)value {
+  self = [super init];
+  if (self) {
+    _value = value;
+  }
+  return self;
+}
+@end
+
+/// Specifies how long a credential will be kept.
+@implementation FWFNSUrlCredentialPersistenceBox
+- (instancetype)initWithValue:(FWFNSUrlCredentialPersistence)value {
+  self = [super init];
+  if (self) {
+    _value = value;
+  }
+  return self;
+}
+@end
+
 static NSArray *wrapResult(id result, FlutterError *error) {
   if (error) {
     return @[
@@ -285,6 +310,12 @@
 - (NSArray *)toList;
 @end
 
+@interface FWFAuthenticationChallengeResponse ()
++ (FWFAuthenticationChallengeResponse *)fromList:(NSArray *)list;
++ (nullable FWFAuthenticationChallengeResponse *)nullableFromList:(NSArray *)list;
+- (NSArray *)toList;
+@end
+
 @implementation FWFNSKeyValueObservingOptionsEnumData
 + (instancetype)makeWithValue:(FWFNSKeyValueObservingOptionsEnum)value {
   FWFNSKeyValueObservingOptionsEnumData *pigeonResult =
@@ -727,6 +758,33 @@
 }
 @end
 
+@implementation FWFAuthenticationChallengeResponse
++ (instancetype)makeWithDisposition:(FWFNSUrlSessionAuthChallengeDisposition)disposition
+               credentialIdentifier:(nullable NSNumber *)credentialIdentifier {
+  FWFAuthenticationChallengeResponse *pigeonResult =
+      [[FWFAuthenticationChallengeResponse alloc] init];
+  pigeonResult.disposition = disposition;
+  pigeonResult.credentialIdentifier = credentialIdentifier;
+  return pigeonResult;
+}
++ (FWFAuthenticationChallengeResponse *)fromList:(NSArray *)list {
+  FWFAuthenticationChallengeResponse *pigeonResult =
+      [[FWFAuthenticationChallengeResponse alloc] init];
+  pigeonResult.disposition = [GetNullableObjectAtIndex(list, 0) integerValue];
+  pigeonResult.credentialIdentifier = GetNullableObjectAtIndex(list, 1);
+  return pigeonResult;
+}
++ (nullable FWFAuthenticationChallengeResponse *)nullableFromList:(NSArray *)list {
+  return (list) ? [FWFAuthenticationChallengeResponse fromList:list] : nil;
+}
+- (NSArray *)toList {
+  return @[
+    @(self.disposition),
+    self.credentialIdentifier ?: [NSNull null],
+  ];
+}
+@end
+
 @interface FWFWKWebsiteDataStoreHostApiCodecReader : FlutterStandardReader
 @end
 @implementation FWFWKWebsiteDataStoreHostApiCodecReader
@@ -1684,14 +1742,16 @@
 - (nullable id)readValueOfType:(UInt8)type {
   switch (type) {
     case 128:
-      return [FWFNSErrorData fromList:[self readValue]];
+      return [FWFAuthenticationChallengeResponse fromList:[self readValue]];
     case 129:
-      return [FWFNSUrlRequestData fromList:[self readValue]];
+      return [FWFNSErrorData fromList:[self readValue]];
     case 130:
-      return [FWFWKFrameInfoData fromList:[self readValue]];
+      return [FWFNSUrlRequestData fromList:[self readValue]];
     case 131:
-      return [FWFWKNavigationActionData fromList:[self readValue]];
+      return [FWFWKFrameInfoData fromList:[self readValue]];
     case 132:
+      return [FWFWKNavigationActionData fromList:[self readValue]];
+    case 133:
       return [FWFWKNavigationActionPolicyEnumData fromList:[self readValue]];
     default:
       return [super readValueOfType:type];
@@ -1703,21 +1763,24 @@
 @end
 @implementation FWFWKNavigationDelegateFlutterApiCodecWriter
 - (void)writeValue:(id)value {
-  if ([value isKindOfClass:[FWFNSErrorData class]]) {
+  if ([value isKindOfClass:[FWFAuthenticationChallengeResponse class]]) {
     [self writeByte:128];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) {
+  } else if ([value isKindOfClass:[FWFNSErrorData class]]) {
     [self writeByte:129];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) {
+  } else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) {
     [self writeByte:130];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) {
+  } else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) {
     [self writeByte:131];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) {
     [self writeByte:132];
     [self writeValue:[value toList]];
+  } else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) {
+    [self writeByte:133];
+    [self writeValue:[value toList]];
   } else {
     [super writeValue:value];
   }
@@ -1934,6 +1997,40 @@
               }
             }];
 }
+- (void)
+    didReceiveAuthenticationChallengeForDelegateWithIdentifier:(NSInteger)arg_identifier
+                                             webViewIdentifier:(NSInteger)arg_webViewIdentifier
+                                           challengeIdentifier:(NSInteger)arg_challengeIdentifier
+                                                    completion:
+                                                        (void (^)(FWFAuthenticationChallengeResponse
+                                                                      *_Nullable,
+                                                                  FlutterError *_Nullable))
+                                                            completion {
+  FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+      messageChannelWithName:@"dev.flutter.pigeon.webview_flutter_wkwebview."
+                             @"WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge"
+             binaryMessenger:self.binaryMessenger
+                       codec:FWFWKNavigationDelegateFlutterApiGetCodec()];
+  [channel sendMessage:@[ @(arg_identifier), @(arg_webViewIdentifier), @(arg_challengeIdentifier) ]
+                 reply:^(NSArray<id> *reply) {
+                   if (reply != nil) {
+                     if (reply.count > 1) {
+                       completion(nil, [FlutterError errorWithCode:reply[0]
+                                                           message:reply[1]
+                                                           details:reply[2]]);
+                     } else {
+                       FWFAuthenticationChallengeResponse *output =
+                           reply[0] == [NSNull null] ? nil : reply[0];
+                       completion(output, nil);
+                     }
+                   } else {
+                     completion(nil, [FlutterError
+                                         errorWithCode:@"channel-error"
+                                               message:@"Unable to establish connection on channel."
+                                               details:@""]);
+                   }
+                 }];
+}
 @end
 
 @interface FWFNSObjectHostApiCodecReader : FlutterStandardReader
@@ -2201,40 +2298,42 @@
 - (nullable id)readValueOfType:(UInt8)type {
   switch (type) {
     case 128:
-      return [FWFNSErrorData fromList:[self readValue]];
+      return [FWFAuthenticationChallengeResponse fromList:[self readValue]];
     case 129:
-      return [FWFNSHttpCookieData fromList:[self readValue]];
+      return [FWFNSErrorData fromList:[self readValue]];
     case 130:
-      return [FWFNSHttpCookiePropertyKeyEnumData fromList:[self readValue]];
+      return [FWFNSHttpCookieData fromList:[self readValue]];
     case 131:
-      return [FWFNSKeyValueChangeKeyEnumData fromList:[self readValue]];
+      return [FWFNSHttpCookiePropertyKeyEnumData fromList:[self readValue]];
     case 132:
-      return [FWFNSKeyValueObservingOptionsEnumData fromList:[self readValue]];
+      return [FWFNSKeyValueChangeKeyEnumData fromList:[self readValue]];
     case 133:
-      return [FWFNSUrlRequestData fromList:[self readValue]];
+      return [FWFNSKeyValueObservingOptionsEnumData fromList:[self readValue]];
     case 134:
-      return [FWFObjectOrIdentifier fromList:[self readValue]];
+      return [FWFNSUrlRequestData fromList:[self readValue]];
     case 135:
-      return [FWFWKAudiovisualMediaTypeEnumData fromList:[self readValue]];
+      return [FWFObjectOrIdentifier fromList:[self readValue]];
     case 136:
-      return [FWFWKFrameInfoData fromList:[self readValue]];
+      return [FWFWKAudiovisualMediaTypeEnumData fromList:[self readValue]];
     case 137:
-      return [FWFWKMediaCaptureTypeData fromList:[self readValue]];
+      return [FWFWKFrameInfoData fromList:[self readValue]];
     case 138:
-      return [FWFWKNavigationActionData fromList:[self readValue]];
+      return [FWFWKMediaCaptureTypeData fromList:[self readValue]];
     case 139:
-      return [FWFWKNavigationActionPolicyEnumData fromList:[self readValue]];
+      return [FWFWKNavigationActionData fromList:[self readValue]];
     case 140:
-      return [FWFWKPermissionDecisionData fromList:[self readValue]];
+      return [FWFWKNavigationActionPolicyEnumData fromList:[self readValue]];
     case 141:
-      return [FWFWKScriptMessageData fromList:[self readValue]];
+      return [FWFWKPermissionDecisionData fromList:[self readValue]];
     case 142:
-      return [FWFWKSecurityOriginData fromList:[self readValue]];
+      return [FWFWKScriptMessageData fromList:[self readValue]];
     case 143:
-      return [FWFWKUserScriptData fromList:[self readValue]];
+      return [FWFWKSecurityOriginData fromList:[self readValue]];
     case 144:
-      return [FWFWKUserScriptInjectionTimeEnumData fromList:[self readValue]];
+      return [FWFWKUserScriptData fromList:[self readValue]];
     case 145:
+      return [FWFWKUserScriptInjectionTimeEnumData fromList:[self readValue]];
+    case 146:
       return [FWFWKWebsiteDataTypeEnumData fromList:[self readValue]];
     default:
       return [super readValueOfType:type];
@@ -2246,60 +2345,63 @@
 @end
 @implementation FWFWKWebViewHostApiCodecWriter
 - (void)writeValue:(id)value {
-  if ([value isKindOfClass:[FWFNSErrorData class]]) {
+  if ([value isKindOfClass:[FWFAuthenticationChallengeResponse class]]) {
     [self writeByte:128];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFNSHttpCookieData class]]) {
+  } else if ([value isKindOfClass:[FWFNSErrorData class]]) {
     [self writeByte:129];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFNSHttpCookiePropertyKeyEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFNSHttpCookieData class]]) {
     [self writeByte:130];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFNSKeyValueChangeKeyEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFNSHttpCookiePropertyKeyEnumData class]]) {
     [self writeByte:131];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFNSKeyValueObservingOptionsEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFNSKeyValueChangeKeyEnumData class]]) {
     [self writeByte:132];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) {
+  } else if ([value isKindOfClass:[FWFNSKeyValueObservingOptionsEnumData class]]) {
     [self writeByte:133];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFObjectOrIdentifier class]]) {
+  } else if ([value isKindOfClass:[FWFNSUrlRequestData class]]) {
     [self writeByte:134];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKAudiovisualMediaTypeEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFObjectOrIdentifier class]]) {
     [self writeByte:135];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) {
+  } else if ([value isKindOfClass:[FWFWKAudiovisualMediaTypeEnumData class]]) {
     [self writeByte:136];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKMediaCaptureTypeData class]]) {
+  } else if ([value isKindOfClass:[FWFWKFrameInfoData class]]) {
     [self writeByte:137];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) {
+  } else if ([value isKindOfClass:[FWFWKMediaCaptureTypeData class]]) {
     [self writeByte:138];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFWKNavigationActionData class]]) {
     [self writeByte:139];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKPermissionDecisionData class]]) {
+  } else if ([value isKindOfClass:[FWFWKNavigationActionPolicyEnumData class]]) {
     [self writeByte:140];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKScriptMessageData class]]) {
+  } else if ([value isKindOfClass:[FWFWKPermissionDecisionData class]]) {
     [self writeByte:141];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKSecurityOriginData class]]) {
+  } else if ([value isKindOfClass:[FWFWKScriptMessageData class]]) {
     [self writeByte:142];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKUserScriptData class]]) {
+  } else if ([value isKindOfClass:[FWFWKSecurityOriginData class]]) {
     [self writeByte:143];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKUserScriptInjectionTimeEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFWKUserScriptData class]]) {
     [self writeByte:144];
     [self writeValue:[value toList]];
-  } else if ([value isKindOfClass:[FWFWKWebsiteDataTypeEnumData class]]) {
+  } else if ([value isKindOfClass:[FWFWKUserScriptInjectionTimeEnumData class]]) {
     [self writeByte:145];
     [self writeValue:[value toList]];
+  } else if ([value isKindOfClass:[FWFWKWebsiteDataTypeEnumData class]]) {
+    [self writeByte:146];
+    [self writeValue:[value toList]];
   } else {
     [super writeValue:value];
   }
@@ -3181,3 +3283,143 @@
             }];
 }
 @end
+
+NSObject<FlutterMessageCodec> *FWFNSUrlCredentialHostApiGetCodec(void) {
+  static FlutterStandardMessageCodec *sSharedObject = nil;
+  sSharedObject = [FlutterStandardMessageCodec sharedInstance];
+  return sSharedObject;
+}
+
+void SetUpFWFNSUrlCredentialHostApi(id<FlutterBinaryMessenger> binaryMessenger,
+                                    NSObject<FWFNSUrlCredentialHostApi> *api) {
+  /// Create a new native instance and add it to the `InstanceManager`.
+  {
+    FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
+           initWithName:
+               @"dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser"
+        binaryMessenger:binaryMessenger
+                  codec:FWFNSUrlCredentialHostApiGetCodec()];
+    if (api) {
+      NSCAssert([api respondsToSelector:@selector
+                     (createWithUserWithIdentifier:user:password:persistence:error:)],
+                @"FWFNSUrlCredentialHostApi api (%@) doesn't respond to "
+                @"@selector(createWithUserWithIdentifier:user:password:persistence:error:)",
+                api);
+      [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
+        NSArray *args = message;
+        NSInteger arg_identifier = [GetNullableObjectAtIndex(args, 0) integerValue];
+        NSString *arg_user = GetNullableObjectAtIndex(args, 1);
+        NSString *arg_password = GetNullableObjectAtIndex(args, 2);
+        FWFNSUrlCredentialPersistence arg_persistence =
+            [GetNullableObjectAtIndex(args, 3) integerValue];
+        FlutterError *error;
+        [api createWithUserWithIdentifier:arg_identifier
+                                     user:arg_user
+                                 password:arg_password
+                              persistence:arg_persistence
+                                    error:&error];
+        callback(wrapResult(nil, error));
+      }];
+    } else {
+      [channel setMessageHandler:nil];
+    }
+  }
+}
+NSObject<FlutterMessageCodec> *FWFNSUrlProtectionSpaceFlutterApiGetCodec(void) {
+  static FlutterStandardMessageCodec *sSharedObject = nil;
+  sSharedObject = [FlutterStandardMessageCodec sharedInstance];
+  return sSharedObject;
+}
+
+@interface FWFNSUrlProtectionSpaceFlutterApi ()
+@property(nonatomic, strong) NSObject<FlutterBinaryMessenger> *binaryMessenger;
+@end
+
+@implementation FWFNSUrlProtectionSpaceFlutterApi
+
+- (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger> *)binaryMessenger {
+  self = [super init];
+  if (self) {
+    _binaryMessenger = binaryMessenger;
+  }
+  return self;
+}
+- (void)createWithIdentifier:(NSInteger)arg_identifier
+                        host:(nullable NSString *)arg_host
+                       realm:(nullable NSString *)arg_realm
+        authenticationMethod:(nullable NSString *)arg_authenticationMethod
+                  completion:(void (^)(FlutterError *_Nullable))completion {
+  FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+      messageChannelWithName:
+          @"dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlProtectionSpaceFlutterApi.create"
+             binaryMessenger:self.binaryMessenger
+                       codec:FWFNSUrlProtectionSpaceFlutterApiGetCodec()];
+  [channel
+      sendMessage:@[
+        @(arg_identifier), arg_host ?: [NSNull null], arg_realm ?: [NSNull null],
+        arg_authenticationMethod ?: [NSNull null]
+      ]
+            reply:^(NSArray<id> *reply) {
+              if (reply != nil) {
+                if (reply.count > 1) {
+                  completion([FlutterError errorWithCode:reply[0]
+                                                 message:reply[1]
+                                                 details:reply[2]]);
+                } else {
+                  completion(nil);
+                }
+              } else {
+                completion([FlutterError errorWithCode:@"channel-error"
+                                               message:@"Unable to establish connection on channel."
+                                               details:@""]);
+              }
+            }];
+}
+@end
+
+NSObject<FlutterMessageCodec> *FWFNSUrlAuthenticationChallengeFlutterApiGetCodec(void) {
+  static FlutterStandardMessageCodec *sSharedObject = nil;
+  sSharedObject = [FlutterStandardMessageCodec sharedInstance];
+  return sSharedObject;
+}
+
+@interface FWFNSUrlAuthenticationChallengeFlutterApi ()
+@property(nonatomic, strong) NSObject<FlutterBinaryMessenger> *binaryMessenger;
+@end
+
+@implementation FWFNSUrlAuthenticationChallengeFlutterApi
+
+- (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger> *)binaryMessenger {
+  self = [super init];
+  if (self) {
+    _binaryMessenger = binaryMessenger;
+  }
+  return self;
+}
+- (void)createWithIdentifier:(NSInteger)arg_identifier
+    protectionSpaceIdentifier:(NSInteger)arg_protectionSpaceIdentifier
+                   completion:(void (^)(FlutterError *_Nullable))completion {
+  FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
+      messageChannelWithName:@"dev.flutter.pigeon.webview_flutter_wkwebview."
+                             @"NSUrlAuthenticationChallengeFlutterApi.create"
+             binaryMessenger:self.binaryMessenger
+                       codec:FWFNSUrlAuthenticationChallengeFlutterApiGetCodec()];
+  [channel
+      sendMessage:@[ @(arg_identifier), @(arg_protectionSpaceIdentifier) ]
+            reply:^(NSArray<id> *reply) {
+              if (reply != nil) {
+                if (reply.count > 1) {
+                  completion([FlutterError errorWithCode:reply[0]
+                                                 message:reply[1]
+                                                 details:reply[2]]);
+                } else {
+                  completion(nil);
+                }
+              } else {
+                completion([FlutterError errorWithCode:@"channel-error"
+                                               message:@"Unable to establish connection on channel."
+                                               details:@""]);
+              }
+            }];
+}
+@end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.m
index 30035d0..db8c456 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.m
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFNavigationDelegateHostApi.m
@@ -4,9 +4,13 @@
 
 #import "FWFNavigationDelegateHostApi.h"
 #import "FWFDataConverters.h"
+#import "FWFURLAuthenticationChallengeHostApi.h"
 #import "FWFWebViewConfigurationHostApi.h"
 
 @interface FWFNavigationDelegateFlutterApiImpl ()
+// BinaryMessenger must be weak to prevent a circular reference with the host API it
+// references.
+@property(nonatomic, weak) id<FlutterBinaryMessenger> binaryMessenger;
 // InstanceManager must be weak to prevent a circular reference with the object it stores.
 @property(nonatomic, weak) FWFInstanceManager *instanceManager;
 @end
@@ -16,6 +20,7 @@
                         instanceManager:(FWFInstanceManager *)instanceManager {
   self = [self initWithBinaryMessenger:binaryMessenger];
   if (self) {
+    _binaryMessenger = binaryMessenger;
     _instanceManager = instanceManager;
   }
   return self;
@@ -102,6 +107,37 @@
                                                     webViewIdentifier:webViewIdentifier
                                                            completion:completion];
 }
+
+- (void)
+    didReceiveAuthenticationChallengeForDelegate:(FWFNavigationDelegate *)instance
+                                         webView:(WKWebView *)webView
+                                       challenge:(NSURLAuthenticationChallenge *)challenge
+                                      completion:
+                                          (void (^)(FWFAuthenticationChallengeResponse *_Nullable,
+                                                    FlutterError *_Nullable))completion {
+  NSInteger webViewIdentifier =
+      [self.instanceManager identifierWithStrongReferenceForInstance:webView];
+
+  FWFURLAuthenticationChallengeFlutterApiImpl *challengeApi =
+      [[FWFURLAuthenticationChallengeFlutterApiImpl alloc]
+          initWithBinaryMessenger:self.binaryMessenger
+                  instanceManager:self.instanceManager];
+  [challengeApi createWithInstance:challenge
+                   protectionSpace:challenge.protectionSpace
+                        completion:^(FlutterError *error) {
+                          NSAssert(!error, @"%@", error);
+                        }];
+
+  [self
+      didReceiveAuthenticationChallengeForDelegateWithIdentifier:[self
+                                                                     identifierForDelegate:instance]
+                                               webViewIdentifier:webViewIdentifier
+                                             challengeIdentifier:
+                                                 [self.instanceManager
+                                                     identifierWithStrongReferenceForInstance:
+                                                         challenge]
+                                                      completion:completion];
+}
 @end
 
 @implementation FWFNavigationDelegate
@@ -144,8 +180,13 @@
                                       completion:^(FWFWKNavigationActionPolicyEnumData *policy,
                                                    FlutterError *error) {
                                         NSAssert(!error, @"%@", error);
-                                        decisionHandler(
-                                            FWFNativeWKNavigationActionPolicyFromEnumData(policy));
+                                        if (!error) {
+                                          decisionHandler(
+                                              FWFNativeWKNavigationActionPolicyFromEnumData(
+                                                  policy));
+                                        } else {
+                                          decisionHandler(WKNavigationActionPolicyCancel);
+                                        }
                                       }];
 }
 
@@ -179,6 +220,40 @@
                                              NSAssert(!error, @"%@", error);
                                            }];
 }
+
+- (void)webView:(WKWebView *)webView
+    didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+                    completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition,
+                                                NSURLCredential *_Nullable))completionHandler {
+  [self.navigationDelegateAPI
+      didReceiveAuthenticationChallengeForDelegate:self
+                                           webView:webView
+                                         challenge:challenge
+                                        completion:^(FWFAuthenticationChallengeResponse *response,
+                                                     FlutterError *error) {
+                                          NSAssert(!error, @"%@", error);
+                                          if (!error) {
+                                            NSURLSessionAuthChallengeDisposition disposition =
+                                                FWFNativeNSURLSessionAuthChallengeDispositionFromFWFNSUrlSessionAuthChallengeDisposition(
+                                                    response.disposition);
+
+                                            NSURLCredential *credential =
+                                                response.credentialIdentifier
+                                                    ? (NSURLCredential *)[self.navigationDelegateAPI
+                                                                              .instanceManager
+                                                          instanceForIdentifier:
+                                                              response.credentialIdentifier
+                                                                  .longValue]
+                                                    : nil;
+
+                                            completionHandler(disposition, credential);
+                                          } else {
+                                            completionHandler(
+                                                NSURLSessionAuthChallengeCancelAuthenticationChallenge,
+                                                nil);
+                                          }
+                                        }];
+}
 @end
 
 @interface FWFNavigationDelegateHostApiImpl ()
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLAuthenticationChallengeHostApi.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLAuthenticationChallengeHostApi.h
new file mode 100644
index 0000000..6100b70
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLAuthenticationChallengeHostApi.h
@@ -0,0 +1,33 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Flutter/Flutter.h>
+#import <Foundation/Foundation.h>
+#import "FWFGeneratedWebKitApis.h"
+#import "FWFInstanceManager.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Flutter API implementation for `NSURLAuthenticationChallenge`.
+ *
+ * This class may handle instantiating and adding Dart instances that are attached to a native
+ * instance or sending callback methods from an overridden native class.
+ */
+@interface FWFURLAuthenticationChallengeFlutterApiImpl : NSObject
+/**
+ * The Flutter API used to send messages back to Dart.
+ */
+@property FWFNSUrlAuthenticationChallengeFlutterApi *api;
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
+                        instanceManager:(FWFInstanceManager *)instanceManager;
+/**
+ * Sends a message to Dart to create a new Dart instance and add it to the `InstanceManager`.
+ */
+- (void)createWithInstance:(NSURLAuthenticationChallenge *)instance
+           protectionSpace:(NSURLProtectionSpace *)protectionSpace
+                completion:(void (^)(FlutterError *_Nullable))completion;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLAuthenticationChallengeHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLAuthenticationChallengeHostApi.m
new file mode 100644
index 0000000..965952d
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLAuthenticationChallengeHostApi.m
@@ -0,0 +1,52 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "FWFURLAuthenticationChallengeHostApi.h"
+#import "FWFURLProtectionSpaceHostApi.h"
+
+@interface FWFURLAuthenticationChallengeFlutterApiImpl ()
+// BinaryMessenger must be weak to prevent a circular reference with the host API it
+// references.
+@property(nonatomic, weak) id<FlutterBinaryMessenger> binaryMessenger;
+// InstanceManager must be weak to prevent a circular reference with the object it stores.
+@property(nonatomic, weak) FWFInstanceManager *instanceManager;
+@end
+
+@implementation FWFURLAuthenticationChallengeFlutterApiImpl
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
+                        instanceManager:(FWFInstanceManager *)instanceManager {
+  self = [self init];
+  if (self) {
+    _binaryMessenger = binaryMessenger;
+    _instanceManager = instanceManager;
+    _api =
+        [[FWFNSUrlAuthenticationChallengeFlutterApi alloc] initWithBinaryMessenger:binaryMessenger];
+  }
+  return self;
+}
+
+- (void)createWithInstance:(NSURLAuthenticationChallenge *)instance
+           protectionSpace:(NSURLProtectionSpace *)protectionSpace
+                completion:(void (^)(FlutterError *_Nullable))completion {
+  if ([self.instanceManager containsInstance:instance]) {
+    return;
+  }
+
+  FWFURLProtectionSpaceFlutterApiImpl *protectionSpaceApi =
+      [[FWFURLProtectionSpaceFlutterApiImpl alloc] initWithBinaryMessenger:self.binaryMessenger
+                                                           instanceManager:self.instanceManager];
+  [protectionSpaceApi createWithInstance:protectionSpace
+                                    host:protectionSpace.host
+                                   realm:protectionSpace.realm
+                    authenticationMethod:protectionSpace.authenticationMethod
+                              completion:^(FlutterError *error) {
+                                NSAssert(!error, @"%@", error);
+                              }];
+
+  [self.api createWithIdentifier:[self.instanceManager addHostCreatedInstance:instance]
+       protectionSpaceIdentifier:[self.instanceManager
+                                     identifierWithStrongReferenceForInstance:protectionSpace]
+                      completion:completion];
+}
+@end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLCredentialHostApi.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLCredentialHostApi.h
new file mode 100644
index 0000000..fe9b3d0
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLCredentialHostApi.h
@@ -0,0 +1,24 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Flutter/Flutter.h>
+#import <Foundation/Foundation.h>
+#import "FWFDataConverters.h"
+#import "FWFGeneratedWebKitApis.h"
+#import "FWFInstanceManager.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Host API implementation for `NSURLCredential`.
+ *
+ * This class may handle instantiating and adding native object instances that are attached to a
+ * Dart instance or method calls on the associated native class or an instance of the class.
+ */
+@interface FWFURLCredentialHostApiImpl : NSObject <FWFNSUrlCredentialHostApi>
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
+                        instanceManager:(FWFInstanceManager *)instanceManager;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLCredentialHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLCredentialHostApi.m
new file mode 100644
index 0000000..2b6955f
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLCredentialHostApi.m
@@ -0,0 +1,58 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "FWFURLCredentialHostApi.h"
+
+@interface FWFURLCredentialHostApiImpl ()
+// BinaryMessenger must be weak to prevent a circular reference with the host API it
+// references.
+@property(nonatomic, weak) id<FlutterBinaryMessenger> binaryMessenger;
+// InstanceManager must be weak to prevent a circular reference with the object it stores.
+@property(nonatomic, weak) FWFInstanceManager *instanceManager;
+@end
+
+@implementation FWFURLCredentialHostApiImpl
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
+                        instanceManager:(FWFInstanceManager *)instanceManager {
+  self = [self init];
+  if (self) {
+    _binaryMessenger = binaryMessenger;
+    _instanceManager = instanceManager;
+  }
+  return self;
+}
+
+- (void)createWithUserWithIdentifier:(NSInteger)identifier
+                                user:(nonnull NSString *)user
+                            password:(nonnull NSString *)password
+                         persistence:(FWFNSUrlCredentialPersistence)persistence
+                               error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
+  [self.instanceManager
+      addDartCreatedInstance:
+          [NSURLCredential
+              credentialWithUser:user
+                        password:password
+                     persistence:
+                         FWFNativeNSURLCredentialPersistenceFromFWFNSUrlCredentialPersistence(
+                             persistence)]
+              withIdentifier:identifier];
+}
+
+- (nullable NSURL *)credentialForIdentifier:(NSNumber *)identifier
+                                      error:
+                                          (FlutterError *_Nullable __autoreleasing *_Nonnull)error {
+  NSURL *instance = (NSURL *)[self.instanceManager instanceForIdentifier:identifier.longValue];
+
+  if (!instance) {
+    NSString *message =
+        [NSString stringWithFormat:@"InstanceManager does not contain an NSURL with identifier: %@",
+                                   identifier];
+    *error = [FlutterError errorWithCode:NSInternalInconsistencyException
+                                 message:message
+                                 details:nil];
+  }
+
+  return instance;
+}
+@end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLProtectionSpaceHostApi.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLProtectionSpaceHostApi.h
new file mode 100644
index 0000000..5e57ab5
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLProtectionSpaceHostApi.h
@@ -0,0 +1,35 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Flutter/Flutter.h>
+#import <Foundation/Foundation.h>
+#import "FWFGeneratedWebKitApis.h"
+#import "FWFInstanceManager.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Flutter API implementation for `NSURLProtectionSpace`.
+ *
+ * This class may handle instantiating and adding Dart instances that are attached to a native
+ * instance or sending callback methods from an overridden native class.
+ */
+@interface FWFURLProtectionSpaceFlutterApiImpl : NSObject
+/**
+ * The Flutter API used to send messages back to Dart.
+ */
+@property FWFNSUrlProtectionSpaceFlutterApi *api;
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
+                        instanceManager:(FWFInstanceManager *)instanceManager;
+/**
+ * Sends a message to Dart to create a new Dart instance and add it to the `InstanceManager`.
+ */
+- (void)createWithInstance:(NSURLProtectionSpace *)instance
+                      host:(nullable NSString *)host
+                     realm:(nullable NSString *)realm
+      authenticationMethod:(nullable NSString *)authenticationMethod
+                completion:(void (^)(FlutterError *_Nullable))completion;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLProtectionSpaceHostApi.m b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLProtectionSpaceHostApi.m
new file mode 100644
index 0000000..fc2d163
--- /dev/null
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/FWFURLProtectionSpaceHostApi.m
@@ -0,0 +1,36 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "FWFURLProtectionSpaceHostApi.h"
+
+@interface FWFURLProtectionSpaceFlutterApiImpl ()
+// InstanceManager must be weak to prevent a circular reference with the object it stores.
+@property(nonatomic, weak) FWFInstanceManager *instanceManager;
+@end
+
+@implementation FWFURLProtectionSpaceFlutterApiImpl
+- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
+                        instanceManager:(FWFInstanceManager *)instanceManager {
+  self = [self init];
+  if (self) {
+    _instanceManager = instanceManager;
+    _api = [[FWFNSUrlProtectionSpaceFlutterApi alloc] initWithBinaryMessenger:binaryMessenger];
+  }
+  return self;
+}
+
+- (void)createWithInstance:(NSURLProtectionSpace *)instance
+                      host:(nullable NSString *)host
+                     realm:(nullable NSString *)realm
+      authenticationMethod:(nullable NSString *)authenticationMethod
+                completion:(void (^)(FlutterError *_Nullable))completion {
+  if (![self.instanceManager containsInstance:instance]) {
+    [self.api createWithIdentifier:[self.instanceManager addHostCreatedInstance:instance]
+                              host:host
+                             realm:realm
+              authenticationMethod:authenticationMethod
+                        completion:completion];
+  }
+}
+@end
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/webview-umbrella.h b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/webview-umbrella.h
index 2836829..6d97c07 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/webview-umbrella.h
+++ b/packages/webview_flutter/webview_flutter_wkwebview/ios/Classes/webview-umbrella.h
@@ -16,7 +16,10 @@
 #import "FWFScrollViewHostApi.h"
 #import "FWFUIDelegateHostApi.h"
 #import "FWFUIViewHostApi.h"
+#import "FWFURLAuthenticationChallengeHostApi.h"
+#import "FWFURLCredentialHostApi.h"
 #import "FWFURLHostApi.h"
+#import "FWFURLProtectionSpaceHostApi.h"
 #import "FWFUserContentControllerHostApi.h"
 #import "FWFWebViewConfigurationHostApi.h"
 #import "FWFWebViewFlutterWKWebViewExternalAPI.h"
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart
index ff08766..1c63220 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart
@@ -202,6 +202,58 @@
   unknown,
 }
 
+/// Responses to an authentication challenge.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition?language=objc.
+enum NSUrlSessionAuthChallengeDisposition {
+  /// Use the specified credential, which may be nil.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeusecredential?language=objc.
+  useCredential,
+
+  /// Use the default handling for the challenge as though this delegate method
+  /// were not implemented.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeperformdefaulthandling?language=objc.
+  performDefaultHandling,
+
+  /// Cancel the entire request.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengecancelauthenticationchallenge?language=objc.
+  cancelAuthenticationChallenge,
+
+  /// Reject this challenge, and call the authentication delegate method again
+  /// with the next authentication protection space.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengerejectprotectionspace?language=objc.
+  rejectProtectionSpace,
+}
+
+/// Specifies how long a credential will be kept.
+enum NSUrlCredentialPersistence {
+  /// The credential should not be stored.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencenone?language=objc.
+  none,
+
+  /// The credential should be stored only for this session.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistenceforsession?language=objc.
+  session,
+
+  /// The credential should be stored in the keychain.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencepermanent?language=objc.
+  permanent,
+
+  /// The credential should be stored permanently in the keychain, and in
+  /// addition should be distributed to other devices based on the owning Apple
+  /// ID.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencesynchronizable?language=objc.
+  synchronizable,
+}
+
 class NSKeyValueObservingOptionsEnumData {
   NSKeyValueObservingOptionsEnumData({
     required this.value,
@@ -684,6 +736,33 @@
   }
 }
 
+class AuthenticationChallengeResponse {
+  AuthenticationChallengeResponse({
+    required this.disposition,
+    this.credentialIdentifier,
+  });
+
+  NSUrlSessionAuthChallengeDisposition disposition;
+
+  int? credentialIdentifier;
+
+  Object encode() {
+    return <Object?>[
+      disposition.index,
+      credentialIdentifier,
+    ];
+  }
+
+  static AuthenticationChallengeResponse decode(Object result) {
+    result as List<Object?>;
+    return AuthenticationChallengeResponse(
+      disposition:
+          NSUrlSessionAuthChallengeDisposition.values[result[0]! as int],
+      credentialIdentifier: result[1] as int?,
+    );
+  }
+}
+
 class _WKWebsiteDataStoreHostApiCodec extends StandardMessageCodec {
   const _WKWebsiteDataStoreHostApiCodec();
   @override
@@ -1576,21 +1655,24 @@
   const _WKNavigationDelegateFlutterApiCodec();
   @override
   void writeValue(WriteBuffer buffer, Object? value) {
-    if (value is NSErrorData) {
+    if (value is AuthenticationChallengeResponse) {
       buffer.putUint8(128);
       writeValue(buffer, value.encode());
-    } else if (value is NSUrlRequestData) {
+    } else if (value is NSErrorData) {
       buffer.putUint8(129);
       writeValue(buffer, value.encode());
-    } else if (value is WKFrameInfoData) {
+    } else if (value is NSUrlRequestData) {
       buffer.putUint8(130);
       writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionData) {
+    } else if (value is WKFrameInfoData) {
       buffer.putUint8(131);
       writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionPolicyEnumData) {
+    } else if (value is WKNavigationActionData) {
       buffer.putUint8(132);
       writeValue(buffer, value.encode());
+    } else if (value is WKNavigationActionPolicyEnumData) {
+      buffer.putUint8(133);
+      writeValue(buffer, value.encode());
     } else {
       super.writeValue(buffer, value);
     }
@@ -1600,14 +1682,16 @@
   Object? readValueOfType(int type, ReadBuffer buffer) {
     switch (type) {
       case 128:
-        return NSErrorData.decode(readValue(buffer)!);
+        return AuthenticationChallengeResponse.decode(readValue(buffer)!);
       case 129:
-        return NSUrlRequestData.decode(readValue(buffer)!);
+        return NSErrorData.decode(readValue(buffer)!);
       case 130:
-        return WKFrameInfoData.decode(readValue(buffer)!);
+        return NSUrlRequestData.decode(readValue(buffer)!);
       case 131:
-        return WKNavigationActionData.decode(readValue(buffer)!);
+        return WKFrameInfoData.decode(readValue(buffer)!);
       case 132:
+        return WKNavigationActionData.decode(readValue(buffer)!);
+      case 133:
         return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
       default:
         return super.readValueOfType(type, buffer);
@@ -1641,6 +1725,9 @@
   void webViewWebContentProcessDidTerminate(
       int identifier, int webViewIdentifier);
 
+  Future<AuthenticationChallengeResponse> didReceiveAuthenticationChallenge(
+      int identifier, int webViewIdentifier, int challengeIdentifier);
+
   static void setup(WKNavigationDelegateFlutterApi? api,
       {BinaryMessenger? binaryMessenger}) {
     {
@@ -1842,6 +1929,41 @@
         });
       }
     }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.webview_flutter_wkwebview.WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_identifier = (args[0] as int?);
+          assert(arg_identifier != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge was null, expected non-null int.');
+          final int? arg_webViewIdentifier = (args[1] as int?);
+          assert(arg_webViewIdentifier != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge was null, expected non-null int.');
+          final int? arg_challengeIdentifier = (args[2] as int?);
+          assert(arg_challengeIdentifier != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKNavigationDelegateFlutterApi.didReceiveAuthenticationChallenge was null, expected non-null int.');
+          try {
+            final AuthenticationChallengeResponse output =
+                await api.didReceiveAuthenticationChallenge(arg_identifier!,
+                    arg_webViewIdentifier!, arg_challengeIdentifier!);
+            return wrapResponse(result: output);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
   }
 }
 
@@ -2082,60 +2204,63 @@
   const _WKWebViewHostApiCodec();
   @override
   void writeValue(WriteBuffer buffer, Object? value) {
-    if (value is NSErrorData) {
+    if (value is AuthenticationChallengeResponse) {
       buffer.putUint8(128);
       writeValue(buffer, value.encode());
-    } else if (value is NSHttpCookieData) {
+    } else if (value is NSErrorData) {
       buffer.putUint8(129);
       writeValue(buffer, value.encode());
-    } else if (value is NSHttpCookiePropertyKeyEnumData) {
+    } else if (value is NSHttpCookieData) {
       buffer.putUint8(130);
       writeValue(buffer, value.encode());
-    } else if (value is NSKeyValueChangeKeyEnumData) {
+    } else if (value is NSHttpCookiePropertyKeyEnumData) {
       buffer.putUint8(131);
       writeValue(buffer, value.encode());
-    } else if (value is NSKeyValueObservingOptionsEnumData) {
+    } else if (value is NSKeyValueChangeKeyEnumData) {
       buffer.putUint8(132);
       writeValue(buffer, value.encode());
-    } else if (value is NSUrlRequestData) {
+    } else if (value is NSKeyValueObservingOptionsEnumData) {
       buffer.putUint8(133);
       writeValue(buffer, value.encode());
-    } else if (value is ObjectOrIdentifier) {
+    } else if (value is NSUrlRequestData) {
       buffer.putUint8(134);
       writeValue(buffer, value.encode());
-    } else if (value is WKAudiovisualMediaTypeEnumData) {
+    } else if (value is ObjectOrIdentifier) {
       buffer.putUint8(135);
       writeValue(buffer, value.encode());
-    } else if (value is WKFrameInfoData) {
+    } else if (value is WKAudiovisualMediaTypeEnumData) {
       buffer.putUint8(136);
       writeValue(buffer, value.encode());
-    } else if (value is WKMediaCaptureTypeData) {
+    } else if (value is WKFrameInfoData) {
       buffer.putUint8(137);
       writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionData) {
+    } else if (value is WKMediaCaptureTypeData) {
       buffer.putUint8(138);
       writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionPolicyEnumData) {
+    } else if (value is WKNavigationActionData) {
       buffer.putUint8(139);
       writeValue(buffer, value.encode());
-    } else if (value is WKPermissionDecisionData) {
+    } else if (value is WKNavigationActionPolicyEnumData) {
       buffer.putUint8(140);
       writeValue(buffer, value.encode());
-    } else if (value is WKScriptMessageData) {
+    } else if (value is WKPermissionDecisionData) {
       buffer.putUint8(141);
       writeValue(buffer, value.encode());
-    } else if (value is WKSecurityOriginData) {
+    } else if (value is WKScriptMessageData) {
       buffer.putUint8(142);
       writeValue(buffer, value.encode());
-    } else if (value is WKUserScriptData) {
+    } else if (value is WKSecurityOriginData) {
       buffer.putUint8(143);
       writeValue(buffer, value.encode());
-    } else if (value is WKUserScriptInjectionTimeEnumData) {
+    } else if (value is WKUserScriptData) {
       buffer.putUint8(144);
       writeValue(buffer, value.encode());
-    } else if (value is WKWebsiteDataTypeEnumData) {
+    } else if (value is WKUserScriptInjectionTimeEnumData) {
       buffer.putUint8(145);
       writeValue(buffer, value.encode());
+    } else if (value is WKWebsiteDataTypeEnumData) {
+      buffer.putUint8(146);
+      writeValue(buffer, value.encode());
     } else {
       super.writeValue(buffer, value);
     }
@@ -2145,40 +2270,42 @@
   Object? readValueOfType(int type, ReadBuffer buffer) {
     switch (type) {
       case 128:
-        return NSErrorData.decode(readValue(buffer)!);
+        return AuthenticationChallengeResponse.decode(readValue(buffer)!);
       case 129:
-        return NSHttpCookieData.decode(readValue(buffer)!);
+        return NSErrorData.decode(readValue(buffer)!);
       case 130:
-        return NSHttpCookiePropertyKeyEnumData.decode(readValue(buffer)!);
+        return NSHttpCookieData.decode(readValue(buffer)!);
       case 131:
-        return NSKeyValueChangeKeyEnumData.decode(readValue(buffer)!);
+        return NSHttpCookiePropertyKeyEnumData.decode(readValue(buffer)!);
       case 132:
-        return NSKeyValueObservingOptionsEnumData.decode(readValue(buffer)!);
+        return NSKeyValueChangeKeyEnumData.decode(readValue(buffer)!);
       case 133:
-        return NSUrlRequestData.decode(readValue(buffer)!);
+        return NSKeyValueObservingOptionsEnumData.decode(readValue(buffer)!);
       case 134:
-        return ObjectOrIdentifier.decode(readValue(buffer)!);
+        return NSUrlRequestData.decode(readValue(buffer)!);
       case 135:
-        return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
+        return ObjectOrIdentifier.decode(readValue(buffer)!);
       case 136:
-        return WKFrameInfoData.decode(readValue(buffer)!);
+        return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
       case 137:
-        return WKMediaCaptureTypeData.decode(readValue(buffer)!);
+        return WKFrameInfoData.decode(readValue(buffer)!);
       case 138:
-        return WKNavigationActionData.decode(readValue(buffer)!);
+        return WKMediaCaptureTypeData.decode(readValue(buffer)!);
       case 139:
-        return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
+        return WKNavigationActionData.decode(readValue(buffer)!);
       case 140:
-        return WKPermissionDecisionData.decode(readValue(buffer)!);
+        return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
       case 141:
-        return WKScriptMessageData.decode(readValue(buffer)!);
+        return WKPermissionDecisionData.decode(readValue(buffer)!);
       case 142:
-        return WKSecurityOriginData.decode(readValue(buffer)!);
+        return WKScriptMessageData.decode(readValue(buffer)!);
       case 143:
-        return WKUserScriptData.decode(readValue(buffer)!);
+        return WKSecurityOriginData.decode(readValue(buffer)!);
       case 144:
-        return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
+        return WKUserScriptData.decode(readValue(buffer)!);
       case 145:
+        return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
+      case 146:
         return WKWebsiteDataTypeEnumData.decode(readValue(buffer)!);
       default:
         return super.readValueOfType(type, buffer);
@@ -3052,3 +3179,148 @@
     }
   }
 }
+
+/// Host API for `NSUrlCredential`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or handle method calls on the associated
+/// native class or an instance of the class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlcredential?language=objc.
+class NSUrlCredentialHostApi {
+  /// Constructor for [NSUrlCredentialHostApi].  The [binaryMessenger] named argument is
+  /// available for dependency injection.  If it is left null, the default
+  /// BinaryMessenger will be used which routes to the host platform.
+  NSUrlCredentialHostApi({BinaryMessenger? binaryMessenger})
+      : _binaryMessenger = binaryMessenger;
+  final BinaryMessenger? _binaryMessenger;
+
+  static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+  /// Create a new native instance and add it to the `InstanceManager`.
+  Future<void> createWithUser(int arg_identifier, String arg_user,
+      String arg_password, NSUrlCredentialPersistence arg_persistence) async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser',
+        codec,
+        binaryMessenger: _binaryMessenger);
+    final List<Object?>? replyList = await channel.send(<Object?>[
+      arg_identifier,
+      arg_user,
+      arg_password,
+      arg_persistence.index
+    ]) as List<Object?>?;
+    if (replyList == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+      );
+    } else if (replyList.length > 1) {
+      throw PlatformException(
+        code: replyList[0]! as String,
+        message: replyList[1] as String?,
+        details: replyList[2],
+      );
+    } else {
+      return;
+    }
+  }
+}
+
+/// Flutter API for `NSUrlProtectionSpace`.
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlprotectionspace?language=objc.
+abstract class NSUrlProtectionSpaceFlutterApi {
+  static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+  /// Create a new Dart instance and add it to the `InstanceManager`.
+  void create(int identifier, String? host, String? realm,
+      String? authenticationMethod);
+
+  static void setup(NSUrlProtectionSpaceFlutterApi? api,
+      {BinaryMessenger? binaryMessenger}) {
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlProtectionSpaceFlutterApi.create',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlProtectionSpaceFlutterApi.create was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_identifier = (args[0] as int?);
+          assert(arg_identifier != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlProtectionSpaceFlutterApi.create was null, expected non-null int.');
+          final String? arg_host = (args[1] as String?);
+          final String? arg_realm = (args[2] as String?);
+          final String? arg_authenticationMethod = (args[3] as String?);
+          try {
+            api.create(
+                arg_identifier!, arg_host, arg_realm, arg_authenticationMethod);
+            return wrapResponse(empty: true);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
+  }
+}
+
+/// Flutter API for `NSUrlAuthenticationChallenge`.
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlauthenticationchallenge?language=objc.
+abstract class NSUrlAuthenticationChallengeFlutterApi {
+  static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+  /// Create a new Dart instance and add it to the `InstanceManager`.
+  void create(int identifier, int protectionSpaceIdentifier);
+
+  static void setup(NSUrlAuthenticationChallengeFlutterApi? api,
+      {BinaryMessenger? binaryMessenger}) {
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlAuthenticationChallengeFlutterApi.create',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlAuthenticationChallengeFlutterApi.create was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_identifier = (args[0] as int?);
+          assert(arg_identifier != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlAuthenticationChallengeFlutterApi.create was null, expected non-null int.');
+          final int? arg_protectionSpaceIdentifier = (args[1] as int?);
+          assert(arg_protectionSpaceIdentifier != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlAuthenticationChallengeFlutterApi.create was null, expected non-null int.');
+          try {
+            api.create(arg_identifier!, arg_protectionSpaceIdentifier!);
+            return wrapResponse(empty: true);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation.dart
index 3fe1a57..2647ed9 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation.dart
@@ -9,6 +9,9 @@
 import '../common/weak_reference_utils.dart';
 import 'foundation_api_impls.dart';
 
+export 'foundation_api_impls.dart'
+    show NSUrlSessionAuthChallengeDisposition, NSUrlCredentialPersistence;
+
 /// The values that can be returned in a change map.
 ///
 /// Wraps [NSKeyValueObservingOptions](https://developer.apple.com/documentation/foundation/nskeyvalueobservingoptions?language=objc).
@@ -387,3 +390,131 @@
     );
   }
 }
+
+/// An authentication credential consisting of information specific to the type
+/// of credential and the type of persistent storage to use, if any.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlcredential?language=objc.
+class NSUrlCredential extends NSObject {
+  /// Creates a URL credential instance for internet password authentication
+  /// with a given user name and password, using a given persistence setting.
+  NSUrlCredential.withUser({
+    required String user,
+    required String password,
+    required NSUrlCredentialPersistence persistence,
+    @visibleForTesting super.binaryMessenger,
+    @visibleForTesting super.instanceManager,
+  })  : _urlCredentialApi = NSUrlCredentialHostApiImpl(
+            binaryMessenger: binaryMessenger, instanceManager: instanceManager),
+        super.detached() {
+    // Ensures Flutter Apis are setup.
+    FoundationFlutterApis.instance.ensureSetUp();
+    _urlCredentialApi.createWithUserFromInstances(
+      this,
+      user,
+      password,
+      persistence,
+    );
+  }
+
+  /// Instantiates a [NSUrlCredential] without creating and attaching to an
+  /// instance of the associated native class.
+  ///
+  /// This should only be used outside of tests by subclasses created by this
+  /// library or to create a copy for an [InstanceManager].
+  @protected
+  NSUrlCredential.detached({super.binaryMessenger, super.instanceManager})
+      : _urlCredentialApi = NSUrlCredentialHostApiImpl(
+            binaryMessenger: binaryMessenger, instanceManager: instanceManager),
+        super.detached();
+
+  final NSUrlCredentialHostApiImpl _urlCredentialApi;
+
+  @override
+  NSObject copy() {
+    return NSUrlCredential.detached(
+      binaryMessenger: _urlCredentialApi.binaryMessenger,
+      instanceManager: _urlCredentialApi.instanceManager,
+    );
+  }
+}
+
+/// A server or an area on a server, commonly referred to as a realm, that
+/// requires authentication.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlprotectionspace?language=objc.
+class NSUrlProtectionSpace extends NSObject {
+  /// Instantiates a [NSUrlProtectionSpace] without creating and attaching to an
+  /// instance of the associated native class.
+  ///
+  /// This should only be used outside of tests by subclasses created by this
+  /// library or to create a copy for an [InstanceManager].
+  @protected
+  NSUrlProtectionSpace.detached({
+    required this.host,
+    required this.realm,
+    required this.authenticationMethod,
+    super.binaryMessenger,
+    super.instanceManager,
+  }) : super.detached();
+
+  /// The receiver’s host.
+  final String? host;
+
+  /// The receiver’s authentication realm.
+  final String? realm;
+
+  /// The authentication method used by the receiver.
+  final String? authenticationMethod;
+
+  @override
+  NSUrlProtectionSpace copy() {
+    return NSUrlProtectionSpace.detached(
+      host: host,
+      realm: realm,
+      authenticationMethod: authenticationMethod,
+    );
+  }
+}
+
+/// The authentication method used by the receiver.
+class NSUrlAuthenticationMethod {
+  /// Use the default authentication method for a protocol.
+  static const String default_ = 'NSURLAuthenticationMethodDefault';
+
+  /// Use HTML form authentication for this protection space.
+  static const String htmlForm = 'NSURLAuthenticationMethodHTMLForm';
+
+  /// Use HTTP basic authentication for this protection space.
+  static const String httpBasic = 'NSURLAuthenticationMethodHTTPBasic';
+
+  /// Use HTTP digest authentication for this protection space.
+  static const String httpDigest = 'NSURLAuthenticationMethodHTTPDigest';
+}
+
+/// A challenge from a server requiring authentication from the client.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlauthenticationchallenge?language=objc.
+class NSUrlAuthenticationChallenge extends NSObject {
+  /// Instantiates a [NSUrlAuthenticationChallenge] without creating and
+  /// attaching to an instance of the associated native class.
+  ///
+  /// This should only be used outside of tests by subclasses created by this
+  /// library or to create a copy for an [InstanceManager].
+  @protected
+  NSUrlAuthenticationChallenge.detached({
+    required this.protectionSpace,
+    super.binaryMessenger,
+    super.instanceManager,
+  }) : super.detached();
+
+  /// The receiver’s protection space.
+  late final NSUrlProtectionSpace protectionSpace;
+
+  @override
+  NSUrlAuthenticationChallenge copy() {
+    return NSUrlAuthenticationChallenge.detached(
+      protectionSpace: protectionSpace,
+    );
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation_api_impls.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation_api_impls.dart
index 4f73c08..7bd1259 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation_api_impls.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/foundation/foundation_api_impls.dart
@@ -9,6 +9,9 @@
 import '../common/web_kit.g.dart';
 import 'foundation.dart';
 
+export '../common/web_kit.g.dart'
+    show NSUrlSessionAuthChallengeDisposition, NSUrlCredentialPersistence;
+
 Iterable<NSKeyValueObservingOptionsEnumData>
     _toNSKeyValueObservingOptionsEnumData(
   Iterable<NSKeyValueObservingOptions> options,
@@ -56,6 +59,14 @@
         url = NSUrlFlutterApiImpl(
           binaryMessenger: binaryMessenger,
           instanceManager: instanceManager,
+        ),
+        urlProtectionSpace = NSUrlProtectionSpaceFlutterApiImpl(
+          binaryMessenger: binaryMessenger,
+          instanceManager: instanceManager,
+        ),
+        urlAuthenticationChallenge = NSUrlAuthenticationChallengeFlutterApiImpl(
+          binaryMessenger: binaryMessenger,
+          instanceManager: instanceManager,
         );
 
   static FoundationFlutterApis _instance = FoundationFlutterApis();
@@ -82,6 +93,14 @@
   @visibleForTesting
   final NSUrlFlutterApiImpl url;
 
+  /// Flutter Api for [NSUrlProtectionSpace].
+  @visibleForTesting
+  final NSUrlProtectionSpaceFlutterApiImpl urlProtectionSpace;
+
+  /// Flutter Api for [NSUrlAuthenticationChallenge].
+  @visibleForTesting
+  final NSUrlAuthenticationChallengeFlutterApiImpl urlAuthenticationChallenge;
+
   /// Ensures all the Flutter APIs have been set up to receive calls from native code.
   void ensureSetUp() {
     if (!_hasBeenSetUp) {
@@ -90,6 +109,14 @@
         binaryMessenger: _binaryMessenger,
       );
       NSUrlFlutterApi.setup(url, binaryMessenger: _binaryMessenger);
+      NSUrlProtectionSpaceFlutterApi.setup(
+        urlProtectionSpace,
+        binaryMessenger: _binaryMessenger,
+      );
+      NSUrlAuthenticationChallengeFlutterApi.setup(
+        urlAuthenticationChallenge,
+        binaryMessenger: _binaryMessenger,
+      );
       _hasBeenSetUp = true;
     }
   }
@@ -249,3 +276,121 @@
     );
   }
 }
+
+/// Host api implementation for [NSUrlCredential].
+class NSUrlCredentialHostApiImpl extends NSUrlCredentialHostApi {
+  /// Constructs an [NSUrlCredentialHostApiImpl].
+  NSUrlCredentialHostApiImpl({
+    this.binaryMessenger,
+    InstanceManager? instanceManager,
+  })  : instanceManager = instanceManager ?? NSObject.globalInstanceManager,
+        super(binaryMessenger: binaryMessenger);
+
+  /// Sends binary data across the Flutter platform barrier.
+  ///
+  /// If it is null, the default BinaryMessenger will be used which routes to
+  /// the host platform.
+  final BinaryMessenger? binaryMessenger;
+
+  /// Maintains instances stored to communicate with Objective-C objects.
+  final InstanceManager instanceManager;
+
+  /// Calls [createWithUser] with the ids of the provided object instances.
+  Future<void> createWithUserFromInstances(
+    NSUrlCredential instance,
+    String user,
+    String password,
+    NSUrlCredentialPersistence persistence,
+  ) {
+    return createWithUser(
+      instanceManager.addDartCreatedInstance(instance),
+      user,
+      password,
+      persistence,
+    );
+  }
+}
+
+/// Flutter API implementation for [NSUrlProtectionSpace].
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+@protected
+class NSUrlProtectionSpaceFlutterApiImpl
+    implements NSUrlProtectionSpaceFlutterApi {
+  /// Constructs a [NSUrlProtectionSpaceFlutterApiImpl].
+  NSUrlProtectionSpaceFlutterApiImpl({
+    this.binaryMessenger,
+    InstanceManager? instanceManager,
+  }) : instanceManager = instanceManager ?? NSObject.globalInstanceManager;
+
+  /// Receives binary data across the Flutter platform barrier.
+  ///
+  /// If it is null, the default BinaryMessenger will be used which routes to
+  /// the host platform.
+  final BinaryMessenger? binaryMessenger;
+
+  /// Maintains instances stored to communicate with native language objects.
+  final InstanceManager instanceManager;
+
+  @override
+  void create(
+    int identifier,
+    String? host,
+    String? realm,
+    String? authenticationMethod,
+  ) {
+    instanceManager.addHostCreatedInstance(
+      NSUrlProtectionSpace.detached(
+        host: host,
+        realm: realm,
+        authenticationMethod: authenticationMethod,
+        binaryMessenger: binaryMessenger,
+        instanceManager: instanceManager,
+      ),
+      identifier,
+    );
+  }
+}
+
+/// Flutter API implementation for [NSUrlAuthenticationChallenge].
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+@protected
+class NSUrlAuthenticationChallengeFlutterApiImpl
+    implements NSUrlAuthenticationChallengeFlutterApi {
+  /// Constructs a [NSUrlAuthenticationChallengeFlutterApiImpl].
+  NSUrlAuthenticationChallengeFlutterApiImpl({
+    this.binaryMessenger,
+    InstanceManager? instanceManager,
+  }) : instanceManager = instanceManager ?? NSObject.globalInstanceManager;
+
+  /// Receives binary data across the Flutter platform barrier.
+  ///
+  /// If it is null, the default BinaryMessenger will be used which routes to
+  /// the host platform.
+  final BinaryMessenger? binaryMessenger;
+
+  /// Maintains instances stored to communicate with native language objects.
+  final InstanceManager instanceManager;
+
+  @override
+  void create(
+    int identifier,
+    int protectionSpaceIdentifier,
+  ) {
+    instanceManager.addHostCreatedInstance(
+      NSUrlAuthenticationChallenge.detached(
+        protectionSpace: instanceManager.getInstanceWithWeakReference(
+          protectionSpaceIdentifier,
+        )!,
+        binaryMessenger: binaryMessenger,
+        instanceManager: instanceManager,
+      ),
+      identifier,
+    );
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart
index db9f41c..b5bfcd9 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit.dart
@@ -830,6 +830,7 @@
     this.didFailNavigation,
     this.didFailProvisionalNavigation,
     this.webViewWebContentProcessDidTerminate,
+    this.didReceiveAuthenticationChallenge,
     super.observeValue,
     super.binaryMessenger,
     super.instanceManager,
@@ -855,6 +856,7 @@
     this.didFailNavigation,
     this.didFailProvisionalNavigation,
     this.webViewWebContentProcessDidTerminate,
+    this.didReceiveAuthenticationChallenge,
     super.observeValue,
     super.binaryMessenger,
     super.instanceManager,
@@ -901,6 +903,16 @@
   /// {@macro webview_flutter_wkwebview.foundation.callbacks}
   final void Function(WKWebView webView)? webViewWebContentProcessDidTerminate;
 
+  /// Called when the delegate needs a response to an authentication challenge.
+  final void Function(
+    WKWebView webView,
+    NSUrlAuthenticationChallenge challenge,
+    void Function(
+      NSUrlSessionAuthChallengeDisposition disposition,
+      NSUrlCredential? credential,
+    ) completionHandler,
+  )? didReceiveAuthenticationChallenge;
+
   @override
   WKNavigationDelegate copy() {
     return WKNavigationDelegate.detached(
@@ -911,6 +923,7 @@
       didFailProvisionalNavigation: didFailProvisionalNavigation,
       webViewWebContentProcessDidTerminate:
           webViewWebContentProcessDidTerminate,
+      didReceiveAuthenticationChallenge: didReceiveAuthenticationChallenge,
       observeValue: observeValue,
       binaryMessenger: _navigationDelegateApi.binaryMessenger,
       instanceManager: _navigationDelegateApi.instanceManager,
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart
index ee545d4..bb86f2b 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/web_kit/web_kit_api_impls.dart
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'dart:async';
+
 import 'package:flutter/foundation.dart';
 import 'package:flutter/services.dart';
 
@@ -904,6 +906,53 @@
           as WKWebView,
     );
   }
+
+  @override
+  Future<AuthenticationChallengeResponse> didReceiveAuthenticationChallenge(
+    int identifier,
+    int webViewIdentifier,
+    int challengeIdentifier,
+  ) async {
+    final void Function(
+      WKWebView webView,
+      NSUrlAuthenticationChallenge challenge,
+      void Function(
+        NSUrlSessionAuthChallengeDisposition disposition,
+        NSUrlCredential? credential,
+      ),
+    )? function = _getDelegate(identifier).didReceiveAuthenticationChallenge;
+
+    if (function == null) {
+      return AuthenticationChallengeResponse(
+        disposition: NSUrlSessionAuthChallengeDisposition.rejectProtectionSpace,
+      );
+    }
+
+    final Completer<AuthenticationChallengeResponse> responseCompleter =
+        Completer<AuthenticationChallengeResponse>();
+
+    function.call(
+      instanceManager.getInstanceWithWeakReference(webViewIdentifier)!
+          as WKWebView,
+      instanceManager.getInstanceWithWeakReference(challengeIdentifier)!
+          as NSUrlAuthenticationChallenge,
+      (
+        NSUrlSessionAuthChallengeDisposition disposition,
+        NSUrlCredential? credential,
+      ) {
+        responseCompleter.complete(
+          AuthenticationChallengeResponse(
+            disposition: disposition,
+            credentialIdentifier: credential != null
+                ? instanceManager.getIdentifier(credential)
+                : null,
+          ),
+        );
+      },
+    );
+
+    return responseCompleter.future;
+  }
 }
 
 /// Host api implementation for [WKWebView].
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
index 68ce913..4b0c4cc 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart
@@ -71,6 +71,14 @@
     void Function(WKWebView webView, NSError error)?
         didFailProvisionalNavigation,
     void Function(WKWebView webView)? webViewWebContentProcessDidTerminate,
+    void Function(
+      WKWebView webView,
+      NSUrlAuthenticationChallenge challenge,
+      void Function(
+        NSUrlSessionAuthChallengeDisposition disposition,
+        NSUrlCredential? credential,
+      ) completionHandler,
+    )? didReceiveAuthenticationChallenge,
   }) createNavigationDelegate;
 
   /// Constructs a [WKUIDelegate].
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart
index d15b282..62a4deb 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart
@@ -948,6 +948,54 @@
           );
         }
       },
+      didReceiveAuthenticationChallenge: (
+        WKWebView webView,
+        NSUrlAuthenticationChallenge challenge,
+        void Function(
+          NSUrlSessionAuthChallengeDisposition disposition,
+          NSUrlCredential? credential,
+        ) completionHandler,
+      ) {
+        if (challenge.protectionSpace.authenticationMethod ==
+            NSUrlAuthenticationMethod.httpBasic) {
+          final void Function(HttpAuthRequest)? callback =
+              weakThis.target?._onHttpAuthRequest;
+          final String? host = challenge.protectionSpace.host;
+          final String? realm = challenge.protectionSpace.realm;
+
+          if (callback != null && host != null) {
+            callback(
+              HttpAuthRequest(
+                onProceed: (WebViewCredential credential) {
+                  completionHandler(
+                    NSUrlSessionAuthChallengeDisposition.useCredential,
+                    NSUrlCredential.withUser(
+                      user: credential.user,
+                      password: credential.password,
+                      persistence: NSUrlCredentialPersistence.session,
+                    ),
+                  );
+                },
+                onCancel: () {
+                  completionHandler(
+                    NSUrlSessionAuthChallengeDisposition
+                        .cancelAuthenticationChallenge,
+                    null,
+                  );
+                },
+                host: host,
+                realm: realm,
+              ),
+            );
+            return;
+          }
+        }
+
+        completionHandler(
+          NSUrlSessionAuthChallengeDisposition.performDefaultHandling,
+          null,
+        );
+      },
     );
   }
 
@@ -960,6 +1008,7 @@
   WebResourceErrorCallback? _onWebResourceError;
   NavigationRequestCallback? _onNavigationRequest;
   UrlChangeCallback? _onUrlChange;
+  HttpAuthRequestCallback? _onHttpAuthRequest;
 
   @override
   Future<void> setOnPageFinished(PageEventCallback onPageFinished) async {
@@ -994,6 +1043,13 @@
   Future<void> setOnUrlChange(UrlChangeCallback onUrlChange) async {
     _onUrlChange = onUrlChange;
   }
+
+  @override
+  Future<void> setOnHttpAuthRequest(
+    HttpAuthRequestCallback onHttpAuthRequest,
+  ) async {
+    _onHttpAuthRequest = onHttpAuthRequest;
+  }
 }
 
 /// WebKit implementation of [PlatformWebViewPermissionRequest].
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart b/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart
index 8e9e16f..c489469 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart
@@ -258,6 +258,58 @@
   late WKMediaCaptureType value;
 }
 
+/// Responses to an authentication challenge.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition?language=objc.
+enum NSUrlSessionAuthChallengeDisposition {
+  /// Use the specified credential, which may be nil.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeusecredential?language=objc.
+  useCredential,
+
+  /// Use the default handling for the challenge as though this delegate method
+  /// were not implemented.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengeperformdefaulthandling?language=objc.
+  performDefaultHandling,
+
+  /// Cancel the entire request.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengecancelauthenticationchallenge?language=objc.
+  cancelAuthenticationChallenge,
+
+  /// Reject this challenge, and call the authentication delegate method again
+  /// with the next authentication protection space.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlsessionauthchallengedisposition/nsurlsessionauthchallengerejectprotectionspace?language=objc.
+  rejectProtectionSpace,
+}
+
+/// Specifies how long a credential will be kept.
+enum NSUrlCredentialPersistence {
+  /// The credential should not be stored.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencenone?language=objc.
+  none,
+
+  /// The credential should be stored only for this session.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistenceforsession?language=objc.
+  session,
+
+  /// The credential should be stored in the keychain.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencepermanent?language=objc.
+  permanent,
+
+  /// The credential should be stored permanently in the keychain, and in
+  /// addition should be distributed to other devices based on the owning Apple
+  /// ID.
+  ///
+  /// See https://developer.apple.com/documentation/foundation/nsurlcredentialpersistence/nsurlcredentialpersistencesynchronizable?language=objc.
+  synchronizable,
+}
+
 /// Mirror of NSURLRequest.
 ///
 /// See https://developer.apple.com/documentation/foundation/nsurlrequest?language=objc.
@@ -343,6 +395,11 @@
   late bool isIdentifier;
 }
 
+class AuthenticationChallengeResponse {
+  late NSUrlSessionAuthChallengeDisposition disposition;
+  late int? credentialIdentifier;
+}
+
 /// Mirror of WKWebsiteDataStore.
 ///
 /// See https://developer.apple.com/documentation/webkit/wkwebsitedatastore?language=objc.
@@ -582,6 +639,16 @@
     int identifier,
     int webViewIdentifier,
   );
+
+  @async
+  @ObjCSelector(
+    'didReceiveAuthenticationChallengeForDelegateWithIdentifier:webViewIdentifier:challengeIdentifier:',
+  )
+  AuthenticationChallengeResponse didReceiveAuthenticationChallenge(
+    int identifier,
+    int webViewIdentifier,
+    int challengeIdentifier,
+  );
 }
 
 /// Mirror of NSObject.
@@ -781,3 +848,57 @@
   @ObjCSelector('createWithIdentifier:')
   void create(int identifier);
 }
+
+/// Host API for `NSUrlCredential`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or handle method calls on the associated
+/// native class or an instance of the class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlcredential?language=objc.
+@HostApi(dartHostTestHandler: 'TestNSUrlCredentialHostApi')
+abstract class NSUrlCredentialHostApi {
+  /// Create a new native instance and add it to the `InstanceManager`.
+  @ObjCSelector(
+    'createWithUserWithIdentifier:user:password:persistence:',
+  )
+  void createWithUser(
+    int identifier,
+    String user,
+    String password,
+    NSUrlCredentialPersistence persistence,
+  );
+}
+
+/// Flutter API for `NSUrlProtectionSpace`.
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlprotectionspace?language=objc.
+@FlutterApi()
+abstract class NSUrlProtectionSpaceFlutterApi {
+  /// Create a new Dart instance and add it to the `InstanceManager`.
+  @ObjCSelector('createWithIdentifier:host:realm:authenticationMethod:')
+  void create(
+    int identifier,
+    String? host,
+    String? realm,
+    String? authenticationMethod,
+  );
+}
+
+/// Flutter API for `NSUrlAuthenticationChallenge`.
+///
+/// This class may handle instantiating and adding Dart instances that are
+/// attached to a native instance or receiving callback methods from an
+/// overridden native class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlauthenticationchallenge?language=objc.
+@FlutterApi()
+abstract class NSUrlAuthenticationChallengeFlutterApi {
+  /// Create a new Dart instance and add it to the `InstanceManager`.
+  @ObjCSelector('createWithIdentifier:protectionSpaceIdentifier:')
+  void create(int identifier, int protectionSpaceIdentifier);
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
index 4c7eca1..a7e5885 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
+++ b/packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
 repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_wkwebview
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
-version: 3.9.4
+version: 3.10.0
 
 environment:
   sdk: ">=3.0.0 <4.0.0"
@@ -20,7 +20,7 @@
   flutter:
     sdk: flutter
   path: ^1.8.0
-  webview_flutter_platform_interface: ^2.6.0
+  webview_flutter_platform_interface: ^2.7.0
 
 dev_dependencies:
   build_runner: ^2.1.5
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart
index 1541f02..a9b0157 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/common/test_web_kit.g.dart
@@ -1199,60 +1199,63 @@
   const _TestWKWebViewHostApiCodec();
   @override
   void writeValue(WriteBuffer buffer, Object? value) {
-    if (value is NSErrorData) {
+    if (value is AuthenticationChallengeResponse) {
       buffer.putUint8(128);
       writeValue(buffer, value.encode());
-    } else if (value is NSHttpCookieData) {
+    } else if (value is NSErrorData) {
       buffer.putUint8(129);
       writeValue(buffer, value.encode());
-    } else if (value is NSHttpCookiePropertyKeyEnumData) {
+    } else if (value is NSHttpCookieData) {
       buffer.putUint8(130);
       writeValue(buffer, value.encode());
-    } else if (value is NSKeyValueChangeKeyEnumData) {
+    } else if (value is NSHttpCookiePropertyKeyEnumData) {
       buffer.putUint8(131);
       writeValue(buffer, value.encode());
-    } else if (value is NSKeyValueObservingOptionsEnumData) {
+    } else if (value is NSKeyValueChangeKeyEnumData) {
       buffer.putUint8(132);
       writeValue(buffer, value.encode());
-    } else if (value is NSUrlRequestData) {
+    } else if (value is NSKeyValueObservingOptionsEnumData) {
       buffer.putUint8(133);
       writeValue(buffer, value.encode());
-    } else if (value is ObjectOrIdentifier) {
+    } else if (value is NSUrlRequestData) {
       buffer.putUint8(134);
       writeValue(buffer, value.encode());
-    } else if (value is WKAudiovisualMediaTypeEnumData) {
+    } else if (value is ObjectOrIdentifier) {
       buffer.putUint8(135);
       writeValue(buffer, value.encode());
-    } else if (value is WKFrameInfoData) {
+    } else if (value is WKAudiovisualMediaTypeEnumData) {
       buffer.putUint8(136);
       writeValue(buffer, value.encode());
-    } else if (value is WKMediaCaptureTypeData) {
+    } else if (value is WKFrameInfoData) {
       buffer.putUint8(137);
       writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionData) {
+    } else if (value is WKMediaCaptureTypeData) {
       buffer.putUint8(138);
       writeValue(buffer, value.encode());
-    } else if (value is WKNavigationActionPolicyEnumData) {
+    } else if (value is WKNavigationActionData) {
       buffer.putUint8(139);
       writeValue(buffer, value.encode());
-    } else if (value is WKPermissionDecisionData) {
+    } else if (value is WKNavigationActionPolicyEnumData) {
       buffer.putUint8(140);
       writeValue(buffer, value.encode());
-    } else if (value is WKScriptMessageData) {
+    } else if (value is WKPermissionDecisionData) {
       buffer.putUint8(141);
       writeValue(buffer, value.encode());
-    } else if (value is WKSecurityOriginData) {
+    } else if (value is WKScriptMessageData) {
       buffer.putUint8(142);
       writeValue(buffer, value.encode());
-    } else if (value is WKUserScriptData) {
+    } else if (value is WKSecurityOriginData) {
       buffer.putUint8(143);
       writeValue(buffer, value.encode());
-    } else if (value is WKUserScriptInjectionTimeEnumData) {
+    } else if (value is WKUserScriptData) {
       buffer.putUint8(144);
       writeValue(buffer, value.encode());
-    } else if (value is WKWebsiteDataTypeEnumData) {
+    } else if (value is WKUserScriptInjectionTimeEnumData) {
       buffer.putUint8(145);
       writeValue(buffer, value.encode());
+    } else if (value is WKWebsiteDataTypeEnumData) {
+      buffer.putUint8(146);
+      writeValue(buffer, value.encode());
     } else {
       super.writeValue(buffer, value);
     }
@@ -1262,40 +1265,42 @@
   Object? readValueOfType(int type, ReadBuffer buffer) {
     switch (type) {
       case 128:
-        return NSErrorData.decode(readValue(buffer)!);
+        return AuthenticationChallengeResponse.decode(readValue(buffer)!);
       case 129:
-        return NSHttpCookieData.decode(readValue(buffer)!);
+        return NSErrorData.decode(readValue(buffer)!);
       case 130:
-        return NSHttpCookiePropertyKeyEnumData.decode(readValue(buffer)!);
+        return NSHttpCookieData.decode(readValue(buffer)!);
       case 131:
-        return NSKeyValueChangeKeyEnumData.decode(readValue(buffer)!);
+        return NSHttpCookiePropertyKeyEnumData.decode(readValue(buffer)!);
       case 132:
-        return NSKeyValueObservingOptionsEnumData.decode(readValue(buffer)!);
+        return NSKeyValueChangeKeyEnumData.decode(readValue(buffer)!);
       case 133:
-        return NSUrlRequestData.decode(readValue(buffer)!);
+        return NSKeyValueObservingOptionsEnumData.decode(readValue(buffer)!);
       case 134:
-        return ObjectOrIdentifier.decode(readValue(buffer)!);
+        return NSUrlRequestData.decode(readValue(buffer)!);
       case 135:
-        return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
+        return ObjectOrIdentifier.decode(readValue(buffer)!);
       case 136:
-        return WKFrameInfoData.decode(readValue(buffer)!);
+        return WKAudiovisualMediaTypeEnumData.decode(readValue(buffer)!);
       case 137:
-        return WKMediaCaptureTypeData.decode(readValue(buffer)!);
+        return WKFrameInfoData.decode(readValue(buffer)!);
       case 138:
-        return WKNavigationActionData.decode(readValue(buffer)!);
+        return WKMediaCaptureTypeData.decode(readValue(buffer)!);
       case 139:
-        return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
+        return WKNavigationActionData.decode(readValue(buffer)!);
       case 140:
-        return WKPermissionDecisionData.decode(readValue(buffer)!);
+        return WKNavigationActionPolicyEnumData.decode(readValue(buffer)!);
       case 141:
-        return WKScriptMessageData.decode(readValue(buffer)!);
+        return WKPermissionDecisionData.decode(readValue(buffer)!);
       case 142:
-        return WKSecurityOriginData.decode(readValue(buffer)!);
+        return WKScriptMessageData.decode(readValue(buffer)!);
       case 143:
-        return WKUserScriptData.decode(readValue(buffer)!);
+        return WKSecurityOriginData.decode(readValue(buffer)!);
       case 144:
-        return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
+        return WKUserScriptData.decode(readValue(buffer)!);
       case 145:
+        return WKUserScriptInjectionTimeEnumData.decode(readValue(buffer)!);
+      case 146:
         return WKWebsiteDataTypeEnumData.decode(readValue(buffer)!);
       default:
         return super.readValueOfType(type, buffer);
@@ -2196,3 +2201,66 @@
     }
   }
 }
+
+/// Host API for `NSUrlCredential`.
+///
+/// This class may handle instantiating and adding native object instances that
+/// are attached to a Dart instance or handle method calls on the associated
+/// native class or an instance of the class.
+///
+/// See https://developer.apple.com/documentation/foundation/nsurlcredential?language=objc.
+abstract class TestNSUrlCredentialHostApi {
+  static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
+      TestDefaultBinaryMessengerBinding.instance;
+  static const MessageCodec<Object?> codec = StandardMessageCodec();
+
+  /// Create a new native instance and add it to the `InstanceManager`.
+  void createWithUser(int identifier, String user, String password,
+      NSUrlCredentialPersistence persistence);
+
+  static void setup(TestNSUrlCredentialHostApi? api,
+      {BinaryMessenger? binaryMessenger}) {
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel, null);
+      } else {
+        _testBinaryMessengerBinding!.defaultBinaryMessenger
+            .setMockDecodedMessageHandler<Object?>(channel,
+                (Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_identifier = (args[0] as int?);
+          assert(arg_identifier != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser was null, expected non-null int.');
+          final String? arg_user = (args[1] as String?);
+          assert(arg_user != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser was null, expected non-null String.');
+          final String? arg_password = (args[2] as String?);
+          assert(arg_password != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser was null, expected non-null String.');
+          final NSUrlCredentialPersistence? arg_persistence = args[3] == null
+              ? null
+              : NSUrlCredentialPersistence.values[args[3]! as int];
+          assert(arg_persistence != null,
+              'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.NSUrlCredentialHostApi.createWithUser was null, expected non-null NSUrlCredentialPersistence.');
+          try {
+            api.createWithUser(
+                arg_identifier!, arg_user!, arg_password!, arg_persistence!);
+            return wrapResponse(empty: true);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
+  }
+}
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.dart
index ea2e37e..345c6fa 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.dart
@@ -17,6 +17,7 @@
 
 @GenerateMocks(<Type>[
   TestNSObjectHostApi,
+  TestNSUrlCredentialHostApi,
   TestNSUrlHostApi,
 ])
 void main() {
@@ -245,6 +246,102 @@
         expect(instanceManager.getInstanceWithWeakReference(0), isA<NSUrl>());
       });
     });
+
+    group('NSUrlCredential', () {
+      tearDown(() {
+        TestNSUrlCredentialHostApi.setup(null);
+      });
+
+      test('HostApi createWithUser', () {
+        final MockTestNSUrlCredentialHostApi mockApi =
+            MockTestNSUrlCredentialHostApi();
+        TestNSUrlCredentialHostApi.setup(mockApi);
+
+        final InstanceManager instanceManager = InstanceManager(
+          onWeakReferenceRemoved: (_) {},
+        );
+
+        const String user = 'testString';
+        const String password = 'testString2';
+
+        const NSUrlCredentialPersistence persistence =
+            NSUrlCredentialPersistence.permanent;
+
+        final NSUrlCredential instance = NSUrlCredential.withUser(
+          user: user,
+          password: password,
+          persistence: persistence,
+          instanceManager: instanceManager,
+        );
+
+        verify(mockApi.createWithUser(
+          instanceManager.getIdentifier(instance),
+          user,
+          password,
+          persistence,
+        ));
+      });
+    });
+
+    group('NSUrlProtectionSpace', () {
+      test('FlutterAPI create', () {
+        final InstanceManager instanceManager = InstanceManager(
+          onWeakReferenceRemoved: (_) {},
+        );
+
+        final NSUrlProtectionSpaceFlutterApiImpl api =
+            NSUrlProtectionSpaceFlutterApiImpl(
+          instanceManager: instanceManager,
+        );
+
+        const int instanceIdentifier = 0;
+
+        api.create(
+          instanceIdentifier,
+          'testString',
+          'testString',
+          'testAuthenticationMethod',
+        );
+
+        expect(
+          instanceManager.getInstanceWithWeakReference(instanceIdentifier),
+          isA<NSUrlProtectionSpace>(),
+        );
+      });
+    });
+
+    group('NSUrlAuthenticationChallenge', () {
+      test('FlutterAPI create', () {
+        final InstanceManager instanceManager = InstanceManager(
+          onWeakReferenceRemoved: (_) {},
+        );
+
+        final NSUrlAuthenticationChallengeFlutterApiImpl api =
+            NSUrlAuthenticationChallengeFlutterApiImpl(
+          instanceManager: instanceManager,
+        );
+
+        const int instanceIdentifier = 0;
+
+        const int protectionSpaceIdentifier = 1;
+        instanceManager.addHostCreatedInstance(
+          NSUrlProtectionSpace.detached(
+            host: null,
+            realm: null,
+            authenticationMethod: null,
+            instanceManager: instanceManager,
+          ),
+          protectionSpaceIdentifier,
+        );
+
+        api.create(instanceIdentifier, protectionSpaceIdentifier);
+
+        expect(
+          instanceManager.getInstanceWithWeakReference(instanceIdentifier),
+          isA<NSUrlAuthenticationChallenge>(),
+        );
+      });
+    });
   });
 
   test('NSError', () {
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart
index 29d9e63..ef23208 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/foundation/foundation_test.mocks.dart
@@ -78,6 +78,36 @@
       );
 }
 
+/// A class which mocks [TestNSUrlCredentialHostApi].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockTestNSUrlCredentialHostApi extends _i1.Mock
+    implements _i2.TestNSUrlCredentialHostApi {
+  MockTestNSUrlCredentialHostApi() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  void createWithUser(
+    int? identifier,
+    String? user,
+    String? password,
+    _i3.NSUrlCredentialPersistence? persistence,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #createWithUser,
+          [
+            identifier,
+            user,
+            password,
+            persistence,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
+}
+
 /// A class which mocks [TestNSUrlHostApi].
 ///
 /// See the documentation for Mockito's code generation for more information.
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart
index 98a70de..2c95a52 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/src/web_kit/web_kit_test.dart
@@ -683,6 +683,63 @@
 
         expect(argsCompleter.future, completion(<Object?>[webView]));
       });
+
+      test('didReceiveAuthenticationChallenge', () async {
+        WebKitFlutterApis.instance = WebKitFlutterApis(
+          instanceManager: instanceManager,
+        );
+
+        const int credentialIdentifier = 3;
+        final NSUrlCredential credential = NSUrlCredential.detached(
+          instanceManager: instanceManager,
+        );
+        instanceManager.addHostCreatedInstance(
+          credential,
+          credentialIdentifier,
+        );
+
+        navigationDelegate = WKNavigationDelegate(
+          instanceManager: instanceManager,
+          didReceiveAuthenticationChallenge: (
+            WKWebView webView,
+            NSUrlAuthenticationChallenge challenge,
+            void Function(
+              NSUrlSessionAuthChallengeDisposition disposition,
+              NSUrlCredential? credential,
+            ) completionHandler,
+          ) {
+            completionHandler(
+              NSUrlSessionAuthChallengeDisposition.useCredential,
+              credential,
+            );
+          },
+        );
+
+        const int challengeIdentifier = 27;
+        instanceManager.addHostCreatedInstance(
+          NSUrlAuthenticationChallenge.detached(
+            protectionSpace: NSUrlProtectionSpace.detached(
+              host: null,
+              realm: null,
+              authenticationMethod: null,
+            ),
+            instanceManager: instanceManager,
+          ),
+          challengeIdentifier,
+        );
+
+        final AuthenticationChallengeResponse response = await WebKitFlutterApis
+            .instance.navigationDelegate
+            .didReceiveAuthenticationChallenge(
+          instanceManager.getIdentifier(navigationDelegate)!,
+          instanceManager.getIdentifier(webView)!,
+          challengeIdentifier,
+        );
+
+        expect(response.disposition,
+            NSUrlSessionAuthChallengeDisposition.useCredential);
+        expect(response.credentialIdentifier, credentialIdentifier);
+      });
     });
 
     group('WKWebView', () {
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart
index 4581c92..63d432c 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_navigation_delegate_test.dart
@@ -7,6 +7,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart';
+import 'package:webview_flutter_wkwebview/src/common/web_kit.g.dart';
 import 'package:webview_flutter_wkwebview/src/foundation/foundation.dart';
 import 'package:webview_flutter_wkwebview/src/web_kit/web_kit.dart';
 import 'package:webview_flutter_wkwebview/src/webkit_proxy.dart';
@@ -214,6 +215,44 @@
       expect(callbackRequest.url, 'https://www.google.com');
       expect(callbackRequest.isMainFrame, isFalse);
     });
+
+    test('onHttpBasicAuthRequest emits host and realm', () {
+      final WebKitNavigationDelegate iosNavigationDelegate =
+          WebKitNavigationDelegate(
+        const WebKitNavigationDelegateCreationParams(
+          webKitProxy: WebKitProxy(
+            createNavigationDelegate: CapturingNavigationDelegate.new,
+          ),
+        ),
+      );
+
+      String? callbackHost;
+      String? callbackRealm;
+
+      iosNavigationDelegate.setOnHttpAuthRequest((HttpAuthRequest request) {
+        callbackHost = request.host;
+        callbackRealm = request.realm;
+      });
+
+      const String expectedHost = 'expectedHost';
+      const String expectedRealm = 'expectedRealm';
+
+      CapturingNavigationDelegate
+              .lastCreatedDelegate.didReceiveAuthenticationChallenge!(
+          WKWebView.detached(),
+          NSUrlAuthenticationChallenge.detached(
+            protectionSpace: NSUrlProtectionSpace.detached(
+              host: expectedHost,
+              realm: expectedRealm,
+              authenticationMethod: NSUrlAuthenticationMethod.httpBasic,
+            ),
+          ),
+          (NSUrlSessionAuthChallengeDisposition disposition,
+              NSUrlCredential? credential) {});
+
+      expect(callbackHost, expectedHost);
+      expect(callbackRealm, expectedRealm);
+    });
   });
 }
 
@@ -226,6 +265,7 @@
     super.didFailProvisionalNavigation,
     super.decidePolicyForNavigationAction,
     super.webViewWebContentProcessDidTerminate,
+    super.didReceiveAuthenticationChallenge,
   }) : super.detached() {
     lastCreatedDelegate = this;
   }
diff --git a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart
index 46badc0..0bada40 100644
--- a/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart
+++ b/packages/webview_flutter/webview_flutter_wkwebview/test/webkit_webview_controller_test.dart
@@ -1366,6 +1366,7 @@
     super.didFailProvisionalNavigation,
     super.decidePolicyForNavigationAction,
     super.webViewWebContentProcessDidTerminate,
+    super.didReceiveAuthenticationChallenge,
   }) : super.detached() {
     lastCreatedDelegate = this;
   }