diff --git a/src/RestSharp/KnownHeaders.cs b/src/RestSharp/KnownHeaders.cs
index c8909a7be..e520937f0 100644
--- a/src/RestSharp/KnownHeaders.cs
+++ b/src/RestSharp/KnownHeaders.cs
@@ -36,6 +36,7 @@ public static class KnownHeaders {
     public const string Cookie             = "Cookie";
     public const string SetCookie          = "Set-Cookie";
     public const string UserAgent          = "User-Agent";
+    public const string TransferEncoding   = "Transfer-Encoding";
 
     internal static readonly string[] ContentHeaders = {
         Allow, Expires, ContentDisposition, ContentEncoding, ContentLanguage, ContentLength, ContentLocation, ContentRange, ContentType, ContentMD5,
diff --git a/src/RestSharp/Options/RestClientOptions.cs b/src/RestSharp/Options/RestClientOptions.cs
index 95db15020..4d0bdf2bc 100644
--- a/src/RestSharp/Options/RestClientOptions.cs
+++ b/src/RestSharp/Options/RestClientOptions.cs
@@ -50,6 +50,12 @@ public RestClientOptions(string baseUrl) : this(new Uri(Ensure.NotEmptyString(ba
     /// <summary>
     /// Custom configuration for the underlying <seealso cref="HttpMessageHandler"/>
     /// </summary>
+    /// <remarks>
+    /// With the addition of all redirection processing being implemented directly by <see cref="RestClient"/>
+    /// please do not alter the <see cref="System.Net.Http.HttpClientHandler.AllowAutoRedirect"/> from its default supplied by RestClient.
+    /// If you set <see cref="System.Net.Http.HttpClientHandler.AllowAutoRedirect"/> to true, then redirection cookie
+    /// processing improvements in RestClient will be skipped since <see cref="System.Net.Http.HttpClient"/> will hide the details from us.
+    /// </remarks>
     public Func<HttpMessageHandler, HttpMessageHandler>? ConfigureMessageHandler { get; set; }
 
     /// <summary>
@@ -60,7 +66,7 @@ public RestClientOptions(string baseUrl) : this(new Uri(Ensure.NotEmptyString(ba
             ? ResponseStatus.Completed
             : ResponseStatus.Error;
 
-    /// <summary>
+    /// <summary>s
     /// Authenticator that will be used to populate request with necessary authentication data
     /// </summary>
     public IAuthenticator? Authenticator { get; set; }
@@ -86,7 +92,7 @@ public RestClientOptions(string baseUrl) : this(new Uri(Ensure.NotEmptyString(ba
     public bool UseDefaultCredentials { get; set; }
 
     /// <summary>
-    /// Set to true if you need the Content-Type not to have the charset 
+    /// Set to true if you need the Content-Type not to have the charset
     /// </summary>
     public bool DisableCharset { get; set; }
 
@@ -131,10 +137,25 @@ public RestClientOptions(string baseUrl) : this(new Uri(Ensure.NotEmptyString(ba
     /// </summary>
     public CacheControlHeaderValue? CachePolicy { get; set; }
 
+    /// <summary>
+    /// Policy settings for redirect processing
+    /// </summary>
+    public RestClientRedirectionOptions RedirectOptions { get; set; } = new RestClientRedirectionOptions();
+
     /// <summary>
     /// Instruct the client to follow redirects. Default is true.
     /// </summary>
-    public bool FollowRedirects { get; set; } = true;
+    /// <remarks>
+    /// Note: This now delegates the property implementation to <see cref="RestClientRedirectionOptions"/>.
+    /// </remarks>
+    public bool FollowRedirects {
+        get {
+            return RedirectOptions.FollowRedirects;
+        }
+        set {
+            RedirectOptions.FollowRedirects = value;
+        }
+    }
 
     /// <summary>
     /// Gets or sets a value that indicates if the <see langword="Expect" /> header for an HTTP request contains Continue.
diff --git a/src/RestSharp/Options/RestClientRedirectionOptions.cs b/src/RestSharp/Options/RestClientRedirectionOptions.cs
new file mode 100644
index 000000000..224bdeb70
--- /dev/null
+++ b/src/RestSharp/Options/RestClientRedirectionOptions.cs
@@ -0,0 +1,143 @@
+using RestSharp.Extensions;
+using System.Net;
+using System.Reflection;
+
+namespace RestSharp;
+
+/// <summary>
+/// Options related to redirect processing.
+/// </summary>
+[GenerateImmutable]
+public class RestClientRedirectionOptions {
+    static readonly Version Version = new AssemblyName(typeof(RestClientOptions).Assembly.FullName!).Version!;
+
+    /// <summary>
+    /// Set to true (default), when you want to follow redirects
+    /// </summary>
+    public bool FollowRedirects { get; set; } = true;
+
+    /// <summary>
+    /// Set to true (default is false), when you want to follow a
+    /// redirect from HTTPS to HTTP.
+    /// </summary>
+    public bool FollowRedirectsToInsecure { get; set; } = false;
+
+    /// <summary>
+    /// Set to true (default), when you want to include the originally
+    /// requested headers in redirected requests.
+    /// </summary>
+    /// <remarks>NOTE: The 'Authorization' header is controlled by <see cref="ForwardAuthorization"/>,
+    /// and the 'Cookie' header is controlled by <see cref="ForwardCookies"/>.
+    /// </remarks>
+    public bool ForwardHeaders { get; set; } = true;
+
+    /// <summary>
+    /// Set to true (default is false), when you want to send the original
+    /// Authorization header to the redirected destination.
+    /// </summary>
+    public bool ForwardAuthorization { get; set; } = false;
+
+    /// <summary>
+    /// Set to true (default), when you want to include cookies from the
+    /// <see cref="CookieContainer"/> on the redirected URL.
+    /// </summary>
+    /// <remarks>
+    /// NOTE: The exact cookies sent to the redirected url DEPENDS directly
+    /// on the redirected url. A redirection to a completly differnet FQDN
+    /// for example is unlikely to actually propagate any cookies from the
+    /// <see cref="CookieContainer"/>.
+    /// </remarks>
+    public bool ForwardCookies { get; set; } = true;
+
+    /// <summary>
+    /// Set to true (default) in order to send the body to the
+    /// redirected URL, unless the force verb to GET behavior is triggered.
+    /// <see cref="ForceForwardBody"/>
+    /// </summary>
+    public bool ForwardBody { get; set; } = false;
+
+    /// <summary>
+    /// Set to true (default is false) to force forwarding the body of the
+    /// request even when normally, the verb might be altered to GET based
+    /// on backward compatiblity with browser processing of HTTP status codes.
+    /// </summary>
+    /// <remarks>
+    /// Based on Wikipedia https://en.wikipedia.org/wiki/HTTP_302:
+    /// <pre>
+    ///  Many web browsers implemented this code in a manner that violated this standard, changing
+    ///  the request type of the new request to GET, regardless of the type employed in the original request
+    ///  (e.g. POST). For this reason, HTTP/1.1 (RFC 2616) added the new status codes 303 and 307 to disambiguate
+    ///  between the two behaviours, with 303 mandating the change of request type to GET, and 307 preserving the
+    ///  request type as originally sent. Despite the greater clarity provided by this disambiguation, the 302 code
+    ///  is still employed in web frameworks to preserve compatibility with browsers that do not implement the HTTP/1.1
+    ///  specification.
+    /// </pre>
+    /// </remarks>
+    public bool ForceForwardBody { get; set; } = false;
+
+    /// <summary>
+    /// Set to true (default) to forward the query string to the redirected URL.
+    /// </summary>
+    public bool ForwardQuery { get; set; } = true;
+
+    /// <summary>
+    /// The maximum number of redirects to follow.
+    /// </summary>
+    public int MaxRedirects { get; set; } = 50;
+
+    /// <summary>
+    /// Set to true (default), to supply any requested fragment portion of the original URL to the destination URL.
+    /// </summary>
+    /// <remarks>
+    /// Per https://tools.ietf.org/html/rfc7231#section-7.1.2, a redirect location without a
+    /// fragment should inherit the fragment from the original URI.
+    /// </remarks>
+    public bool ForwardFragment { get; set; } = true;
+
+    /// <summary>
+    /// Set to true (default), to allow the HTTP Method used on the original request to
+    /// be replaced with GET when the status code 303 (HttpStatusCode.RedirectMethod)
+    /// was returned. Setting this to false will disallow the altering of the verb.
+    /// </summary>
+    public bool AllowRedirectMethodStatusCodeToAlterVerb { get; set; } = true;
+
+    /// <summary>
+    /// Set to true (default), to allow the backward compatibility behavior of
+    /// changing the verb to GET with non 303 redirection status codes.
+    /// </summary>
+    /// <remarks>
+    /// NOTE: Even though the below text only references 302, this also allows some other scenarios.
+    /// See <see cref="RestClient.RedirectRequestRequiresForceGet(HttpStatusCode, HttpMethod)"/> for the specifics.
+    /// Based on Wikipedia https://en.wikipedia.org/wiki/HTTP_302:
+    ///  Many web browsers implemented this code in a manner that violated this standard, changing
+    ///  the request type of the new request to GET, regardless of the type employed in the original request
+    ///  (e.g. POST). For this reason, HTTP/1.1 (RFC 2616) added the new status codes 303 and 307 to disambiguate
+    ///  between the two behaviours, with 303 mandating the change of request type to GET, and 307 preserving the
+    ///  request type as originally sent. Despite the greater clarity provided by this disambiguation, the 302 code
+    ///  is still employed in web frameworks to preserve compatibility with browsers that do not implement the HTTP/1.1
+    ///  specification.
+    /// </remarks>
+    public bool AllowForcedRedirectVerbChange { get; set; } = true;
+
+    /// <summary>
+    /// HttpStatusCodes that trigger redirect processing. Defaults to MovedPermanently (301),
+    /// SeeOther/RedirectMethod (303),
+    /// TemporaryRedirect (307),
+    /// Redirect (302),
+    /// PermanentRedirect (308)
+    /// </summary>
+    public IReadOnlyList<HttpStatusCode> RedirectStatusCodes { get; set; }
+
+    public RestClientRedirectionOptions() {
+        RedirectStatusCodes = new List<HttpStatusCode>() {
+            HttpStatusCode.MovedPermanently,
+            HttpStatusCode.SeeOther,
+            HttpStatusCode.TemporaryRedirect,
+            HttpStatusCode.Redirect,
+#if NET
+            HttpStatusCode.PermanentRedirect,
+#endif
+        }.AsReadOnly();
+    }
+}
+
diff --git a/src/RestSharp/Parameters/FileParameter.cs b/src/RestSharp/Parameters/FileParameter.cs
index 5b58bf44d..30813087a 100644
--- a/src/RestSharp/Parameters/FileParameter.cs
+++ b/src/RestSharp/Parameters/FileParameter.cs
@@ -114,6 +114,7 @@ public static FileParameter FromFile(
 [PublicAPI]
 public class FileParameterOptions {
     [Obsolete("Use DisableFilenameStar instead")]
+    [CLSCompliant(false)]
     public bool DisableFileNameStar {
         get => DisableFilenameStar;
         set => DisableFilenameStar = value;
diff --git a/src/RestSharp/Request/RequestContent.cs b/src/RestSharp/Request/RequestContent.cs
index cfc7995ca..c88c3fed7 100644
--- a/src/RestSharp/Request/RequestContent.cs
+++ b/src/RestSharp/Request/RequestContent.cs
@@ -1,11 +1,11 @@
 //  Copyright (c) .NET Foundation and Contributors
-// 
+//
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
-// 
+//
 // http://www.apache.org/licenses/LICENSE-2.0
-// 
+//
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -36,7 +36,7 @@ public RequestContent(RestClient client, RestRequest request) {
         _parameters = new RequestParameters(_request.Parameters.Union(_client.DefaultParameters));
     }
 
-    public HttpContent BuildContent() {
+    public HttpContent BuildContent(bool omitBody = false) {
         var postParameters       = _parameters.GetContentParameters(_request.Method).ToArray();
         var postParametersExists = postParameters.Length > 0;
         var bodyParametersExists = _request.TryGetBodyParameter(out var bodyParameter);
@@ -51,7 +51,7 @@ public HttpContent BuildContent() {
 
         if (filesExists) AddFiles();
 
-        if (bodyParametersExists) AddBody(postParametersExists, bodyParameter!);
+        if (bodyParametersExists && !omitBody) AddBody(postParametersExists, bodyParameter!);
 
         if (postParametersExists) AddPostParameters(postParameters);
 
@@ -83,7 +83,7 @@ StreamContent ToStreamContent(FileParameter fileParameter) {
         var dispositionHeader = fileParameter.Options.DisableFilenameEncoding
             ? ContentDispositionHeaderValue.Parse($"form-data; name=\"{fileParameter.Name}\"; filename=\"{fileParameter.FileName}\"")
             : new ContentDispositionHeaderValue("form-data") { Name = $"\"{fileParameter.Name}\"", FileName = $"\"{fileParameter.FileName}\"" };
-        if (!fileParameter.Options.DisableFileNameStar) dispositionHeader.FileNameStar = fileParameter.FileName;
+        if (!fileParameter.Options.DisableFilenameStar) dispositionHeader.FileNameStar = fileParameter.FileName;
         streamContent.Headers.ContentDisposition = dispositionHeader;
 
         return streamContent;
diff --git a/src/RestSharp/Request/UriExtensions.cs b/src/RestSharp/Request/UriExtensions.cs
index 95ad66611..141248df9 100644
--- a/src/RestSharp/Request/UriExtensions.cs
+++ b/src/RestSharp/Request/UriExtensions.cs
@@ -37,10 +37,17 @@ public static Uri MergeBaseUrlAndResource(this Uri? baseUrl, string? resource) {
     public static Uri AddQueryString(this Uri uri, string? query) {
         if (query == null) return uri;
 
-        var absoluteUri       = uri.AbsoluteUri;
-        var separator = absoluteUri.Contains('?') ? "&" : "?";
-
-        return new Uri($"{absoluteUri}{separator}{query}");
+        var absoluteUri = uri.AbsoluteUri;
+        var fragment = string.Empty;
+        if (!string.IsNullOrEmpty(uri.Fragment)) {
+            int fragmentStartIndex = absoluteUri.LastIndexOf(uri.Fragment);
+            if (fragmentStartIndex != -1) {
+                fragment = absoluteUri.Substring(fragmentStartIndex, absoluteUri.Length - fragmentStartIndex);
+                absoluteUri = absoluteUri.Substring(0, fragmentStartIndex);
+            }
+        }
+        var separator = string.IsNullOrEmpty(uri.Query) ? "?" : "&"; //absoluteUri.Contains('?') ? "&" : "?";
+        return new Uri($"{absoluteUri}{separator}{query}{fragment}");
     }
 
     public static UrlSegmentParamsValues GetUrlSegmentParamsValues(
diff --git a/src/RestSharp/RestClient.Async.cs b/src/RestSharp/RestClient.Async.cs
index 9c99b9fd7..448a00bd9 100644
--- a/src/RestSharp/RestClient.Async.cs
+++ b/src/RestSharp/RestClient.Async.cs
@@ -1,11 +1,11 @@
 //  Copyright (c) .NET Foundation and Contributors
-// 
+//
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
-// 
+//
 // http://www.apache.org/licenses/LICENSE-2.0
-// 
+//
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 using System.Net;
+using System.Web;
 using RestSharp.Extensions;
 
 namespace RestSharp;
@@ -69,6 +70,16 @@ static RestResponse GetErrorResponse(RestRequest request, Exception exception, C
         bool TimedOut() => timeoutToken.IsCancellationRequested || exception.Message.Contains("HttpClient.Timeout");
     }
 
+    [Flags]
+    private enum ExecutionState {
+        None = 0x0,
+        FoundCookie = 0x1,
+        FirstAttempt = 0x2,
+        DoNotSendBody = 0x4,
+        VerbAltered = 0x8,
+        VerbAlterationPrevented = 0x10,
+    };
+
     async Task<HttpResponse> ExecuteRequestAsync(RestRequest request, CancellationToken cancellationToken) {
         Ensure.NotNull(request, nameof(request));
 
@@ -77,7 +88,7 @@ async Task<HttpResponse> ExecuteRequestAsync(RestRequest request, CancellationTo
             throw new ObjectDisposedException(nameof(RestClient));
         }
 
-        await OnBeforeSerialization(request).ConfigureAwait(false);   
+        await OnBeforeSerialization(request).ConfigureAwait(false);
         request.ValidateParameters();
         var authenticator = request.Authenticator ?? Options.Authenticator;
 
@@ -85,53 +96,222 @@ async Task<HttpResponse> ExecuteRequestAsync(RestRequest request, CancellationTo
             await authenticator.Authenticate(this, request).ConfigureAwait(false);
         }
 
-        using var requestContent = new RequestContent(this, request);
-
         var httpMethod = AsHttpMethod(request.Method);
         var url        = this.BuildUri(request);
-
-        using var message    = new HttpRequestMessage(httpMethod, url) { Content = requestContent.BuildContent() };
-        message.Headers.Host         = Options.BaseHost;
-        message.Headers.CacheControl = request.CachePolicy ?? Options.CachePolicy;
+        var originalUrl = url;
 
         using var timeoutCts = new CancellationTokenSource(request.Timeout > 0 ? request.Timeout : int.MaxValue);
         using var cts        = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, cancellationToken);
 
         var ct = cts.Token;
 
-        
-        HttpResponseMessage? responseMessage;
+        HttpResponseMessage? responseMessage = null;
         // Make sure we have a cookie container if not provided in the request
-        CookieContainer cookieContainer = request.CookieContainer ??= new CookieContainer();
-        
-        var headers = new RequestHeaders()
-            .AddHeaders(request.Parameters)
-            .AddHeaders(DefaultParameters)
-            .AddAcceptHeader(AcceptedContentTypes)
-            .AddCookieHeaders(url, cookieContainer)
-            .AddCookieHeaders(url, Options.CookieContainer);
+        var cookieContainer = request.CookieContainer ??= new CookieContainer();
 
-        message.AddHeaders(headers);
-        if (request.OnBeforeRequest != null) await request.OnBeforeRequest(message).ConfigureAwait(false);
-        await OnBeforeRequest(message).ConfigureAwait(false);
-        
         try {
-            responseMessage = await HttpClient.SendAsync(message, request.CompletionOption, ct).ConfigureAwait(false);
+            var headers = new RequestHeaders()
+                .AddHeaders(request.Parameters)
+                .AddHeaders(DefaultParameters)
+                .AddAcceptHeader(AcceptedContentTypes)
+                .AddCookieHeaders(url, cookieContainer)
+                .AddCookieHeaders(url, Options.CookieContainer);
+
+            ExecutionState state = ExecutionState.FirstAttempt;
+            int redirectCount = 0;
+
+            do {
+                // TODO: Is there a more effecient way to do this other than rebuilding the RequestContent
+                // every time through this loop?
+                using var requestContent = new RequestContent(this, request);
+                using var content = requestContent.BuildContent(omitBody: state.HasFlag(ExecutionState.DoNotSendBody));
+
+                // If we found coookies during a redirect,
+                // we need to update the Cookie headers:
+                if (state.HasFlag(ExecutionState.FoundCookie)) {
+                    headers.AddCookieHeaders(url, cookieContainer);
+                    // Clear the state:
+                    state &= ~ExecutionState.FoundCookie;
+                }
+                using var message = PrepareRequestMessage(httpMethod, url, content, headers);
+
+                if (state.HasFlag(ExecutionState.FirstAttempt)) {
+                    state &= ~ExecutionState.FirstAttempt;
+                    try {
+                        if (request.OnBeforeRequest != null) await request.OnBeforeRequest(message).ConfigureAwait(false);
+                        await OnBeforeRequest(message).ConfigureAwait(false);
+                    }
+                    catch (Exception e) {
+                        throw new RestClientInternalException("RestClient.ExecuteRequestAsync OnBeforeRequest threw an exception: ", e);
+                    }
+                }
+
+                responseMessage = await HttpClient.SendAsync(message, request.CompletionOption, ct).ConfigureAwait(false);
+
+                if (!IsRedirect(Options.RedirectOptions, responseMessage)) {
+                    break;
+                }
+
+                var location = responseMessage.Headers.Location;
+
+                if (location == null) {
+                    break;
+                }
+
+                redirectCount++;
+                if (redirectCount >= Options.RedirectOptions.MaxRedirects) {
+                    break;
+                }
+
+                if (!location.IsAbsoluteUri) {
+                    location = new Uri(url, location);
+                }
+
+                if (Options.RedirectOptions.ForwardQuery) {
+                    string oringalQuery = originalUrl.Query;
+                    if (!string.IsNullOrEmpty(oringalQuery)
+                        && string.IsNullOrEmpty(location.Query)) {
+                        // AddQueryString DOES NOT want the ? in the supplied parameter,
+                        // so strip it:
+                        if (oringalQuery[0] == '?') {
+                            oringalQuery = oringalQuery.Substring(1, oringalQuery.Length - 1);
+                        }
+                        location = location.AddQueryString(oringalQuery);
+                    }
+                }
+
+                // Mirror HttpClient redirection behavior as of 07/25/2023:
+                // Per https://tools.ietf.org/html/rfc7231#section-7.1.2, a redirect location without a
+                // fragment should inherit the fragment from the original URI.
+                if (Options.RedirectOptions.ForwardFragment) {
+                    string requestFragment = originalUrl.Fragment;
+                    if (!string.IsNullOrEmpty(requestFragment)) {
+                        string redirectFragment = location.Fragment;
+                        if (string.IsNullOrEmpty(redirectFragment)) {
+                            location = new UriBuilder(location) { Fragment = requestFragment }.Uri;
+                        }
+                    }
+                }
+
+                // Disallow automatic redirection from secure to non-secure schemes
+                // based on the option setting:
+                if (HttpUtilities.IsSupportedSecureScheme(originalUrl.Scheme)
+                    && !HttpUtilities.IsSupportedSecureScheme(location.Scheme)
+                    && !Options.RedirectOptions.FollowRedirectsToInsecure) {
+                    // TODO: Log here...
+                    break;
+                }
+
+                // This is the expected behavior for this status code, but
+                // ignore it if requested from the RedirectOptions:
+                if (responseMessage.StatusCode == HttpStatusCode.RedirectMethod
+                    && Options.RedirectOptions.AllowRedirectMethodStatusCodeToAlterVerb) {
+                    httpMethod = HttpMethod.Get;
+                    state |= ExecutionState.VerbAltered;
+                }
+                else if (responseMessage.StatusCode == HttpStatusCode.RedirectMethod) {
+                    state |= ExecutionState.VerbAlterationPrevented;
+                }
+
+                // Based on Wikipedia https://en.wikipedia.org/wiki/HTTP_302:
+                //  Many web browsers implemented this code in a manner that violated this standard, changing
+                //  the request type of the new request to GET, regardless of the type employed in the original request
+                //  (e.g. POST). For this reason, HTTP/1.1 (RFC 2616) added the new status codes 303 and 307 to disambiguate
+                //  between the two behaviours, with 303 mandating the change of request type to GET, and 307 preserving the
+                //  request type as originally sent. Despite the greater clarity provided by this disambiguation, the 302 code
+                //  is still employed in web frameworks to preserve compatibility with browsers that do not implement the HTTP/1.1
+                //  specification.
+
+                // NOTE: Given the above, it is not surprising that HttpClient when AllowRedirect = true
+                // solves this problem by a helper method:
+                if (!state.HasFlag(ExecutionState.VerbAlterationPrevented)
+                    && (
+                       state.HasFlag(ExecutionState.VerbAltered)
+                       || (Options.RedirectOptions.AllowForcedRedirectVerbChange
+                           && RedirectRequestRequiresForceGet(responseMessage.StatusCode, httpMethod)))) {
+                    httpMethod = HttpMethod.Get;
+                    if (!Options.RedirectOptions.ForceForwardBody) {
+                        // HttpClient RedirectHandler sets request.Content to null here:
+                        state |= ExecutionState.DoNotSendBody;
+                        // HttpClient Redirect handler also forcibly removes
+                        // a Transfer-Encoding of chunked in this case.
+                        // This makes sense, since without a body, there isn't any chunked (or otherwise) content
+                        // to transmit.
+                        // NOTE: Although, I'm not sure why it only cares about chunked...
+                        Parameter? transferEncoding = request.Parameters.TryFind(KnownHeaders.TransferEncoding);
+                        if (transferEncoding != null
+                            && transferEncoding.Type == ParameterType.HttpHeader
+                            && string.Equals((string)transferEncoding.Value!, "chunked", StringComparison.OrdinalIgnoreCase)) {
+                            message.Headers.Remove(KnownHeaders.TransferEncoding);
+                        }
+                    }
+                }
+
+                url = location;
+
+                // Regardless of whether or not we will be forwarding
+                // cookies, the CookieContainer will be updated:
+                if (responseMessage.Headers.TryGetValues(KnownHeaders.SetCookie, out var cookiesHeader1)) {
+                    if (Options.RedirectOptions.ForwardCookies) {
+                        state |= ExecutionState.FoundCookie;
+                    }
+                    // ReSharper disable once PossibleMultipleEnumeration
+                    cookieContainer.AddCookies(url, cookiesHeader1);
+                    // ReSharper disable once PossibleMultipleEnumeration
+                    Options.CookieContainer?.AddCookies(url, cookiesHeader1);
+                }
+
+                // Process header related RedirectOptions:
+                if (Options.RedirectOptions.ForwardHeaders) {
+                    if (!Options.RedirectOptions.ForwardAuthorization) {
+                        headers.Parameters.RemoveParameter(KnownHeaders.Authorization);
+                    }
+                    if (!Options.RedirectOptions.ForwardCookies) {
+                        headers.Parameters.RemoveParameter(KnownHeaders.Cookie);
+                    }
+                }
+                else {
+                    List<string> headersToRemove = new List<string>();
+                    foreach (var param in headers.Parameters) {
+                        if (param is HeaderParameter header) {
+                            // Keep headers requested to be forwarded:
+                            if (string.Compare(param.Name, KnownHeaders.Authorization, StringComparison.InvariantCultureIgnoreCase) == 0
+                                && Options.RedirectOptions.ForwardAuthorization) {
+                                continue;
+                            }
+                            if (string.Compare(param.Name, KnownHeaders.Cookie, StringComparison.InvariantCultureIgnoreCase) == 0
+                                && Options.RedirectOptions.ForwardCookies) {
+                                continue;
+                            }
+                            // Otherwise: schedule the items for removal:
+                            headersToRemove.Add(param.Name!);
+                        }
+                    }
+                    if (headersToRemove.Count > 0) {
+                        for (int i = 0; i < headersToRemove.Count; i++) {
+                            headers.Parameters.RemoveParameter(headersToRemove[i]);
+                        }
+                    }
+                }
+            } while (true);
+
             // Parse all the cookies from the response and update the cookie jar with cookies
-            if (responseMessage.Headers.TryGetValues(KnownHeaders.SetCookie, out var cookiesHeader)) {
+            if (responseMessage.Headers.TryGetValues(KnownHeaders.SetCookie, out var cookiesHeader2)) {
                 // ReSharper disable once PossibleMultipleEnumeration
-                cookieContainer.AddCookies(url, cookiesHeader);
+                cookieContainer.AddCookies(url, cookiesHeader2);
                 // ReSharper disable once PossibleMultipleEnumeration
-                Options.CookieContainer?.AddCookies(url, cookiesHeader);
+                Options.CookieContainer?.AddCookies(url, cookiesHeader2);
             }
         }
+        catch (RestClientInternalException e) {
+            throw e.InnerException!;
+        }
         catch (Exception ex) {
             return new HttpResponse(null, url, null, ex, timeoutCts.Token);
         }
         if (request.OnAfterRequest != null) await request.OnAfterRequest(responseMessage).ConfigureAwait(false);
         await OnAfterRequest(responseMessage).ConfigureAwait(false);
         return new HttpResponse(responseMessage, url, cookieContainer, null, timeoutCts.Token);
-        
     }
 
     /// <summary>
@@ -162,6 +342,64 @@ async Task OnAfterRequest(HttpResponseMessage responseMessage) {
         }
     }
 
+    /// <summary>
+    /// From https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpUtilities.cs
+    /// </summary>
+    private static class HttpUtilities {
+        internal static bool IsSupportedScheme(string scheme) =>
+            IsSupportedNonSecureScheme(scheme) ||
+            IsSupportedSecureScheme(scheme);
+
+        internal static bool IsSupportedNonSecureScheme(string scheme) =>
+            string.Equals(scheme, "http", StringComparison.OrdinalIgnoreCase) || IsNonSecureWebSocketScheme(scheme);
+
+        internal static bool IsSupportedSecureScheme(string scheme) =>
+            string.Equals(scheme, "https", StringComparison.OrdinalIgnoreCase) || IsSecureWebSocketScheme(scheme);
+
+        internal static bool IsNonSecureWebSocketScheme(string scheme) =>
+            string.Equals(scheme, "ws", StringComparison.OrdinalIgnoreCase);
+
+        internal static bool IsSecureWebSocketScheme(string scheme) =>
+            string.Equals(scheme, "wss", StringComparison.OrdinalIgnoreCase);
+
+        internal static bool IsSupportedProxyScheme(string scheme) =>
+            string.Equals(scheme, "http", StringComparison.OrdinalIgnoreCase) || string.Equals(scheme, "https", StringComparison.OrdinalIgnoreCase) || IsSocksScheme(scheme);
+
+        internal static bool IsSocksScheme(string scheme) =>
+            string.Equals(scheme, "socks5", StringComparison.OrdinalIgnoreCase) ||
+            string.Equals(scheme, "socks4a", StringComparison.OrdinalIgnoreCase) ||
+            string.Equals(scheme, "socks4", StringComparison.OrdinalIgnoreCase);
+    }
+
+    /// <summary>
+    /// Based on .net core RedirectHandler class:
+    /// https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs
+    /// </summary>
+    /// <param name="statusCode"></param>
+    /// <param name="httpMethod"></param>
+    /// <returns>Returns true if statusCode requires a verb change to Get.</returns>
+    private bool RedirectRequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod httpMethod) {
+        return statusCode switch {
+            HttpStatusCode.Moved or HttpStatusCode.Found or HttpStatusCode.MultipleChoices
+                => httpMethod == HttpMethod.Post,
+            HttpStatusCode.SeeOther => httpMethod != HttpMethod.Get && httpMethod != HttpMethod.Head,
+            _ => false,
+        };
+    }
+
+    HttpRequestMessage PrepareRequestMessage(HttpMethod httpMethod, Uri url, HttpContent content, RequestHeaders headers) {
+        var message = new HttpRequestMessage(httpMethod, url) { Content = content };
+        message.Headers.Host         = Options.BaseHost;
+        message.Headers.CacheControl = Options.CachePolicy;
+        message.AddHeaders(headers);
+
+        return message;
+    }
+
+    static bool IsRedirect(RestClientRedirectionOptions options, HttpResponseMessage responseMessage) {
+        return options.FollowRedirects && options.RedirectStatusCodes.Contains(responseMessage.StatusCode);
+    }
+
     record HttpResponse(
         HttpResponseMessage? ResponseMessage,
         Uri                  Url,
diff --git a/src/RestSharp/RestClient.cs b/src/RestSharp/RestClient.cs
index ccaae9f21..874bd088a 100644
--- a/src/RestSharp/RestClient.cs
+++ b/src/RestSharp/RestClient.cs
@@ -247,7 +247,9 @@ static void ConfigureHttpMessageHandler(HttpClientHandler handler, ReadOnlyRestC
 #if NET
         }
 #endif
-        handler.AllowAutoRedirect = options.FollowRedirects;
+        // ExecuteAsync and RedirectionOptions now own
+        // redirection processing:
+        handler.AllowAutoRedirect = false;
 
 #if NET
         if (!OperatingSystem.IsBrowser() && !OperatingSystem.IsIOS() && !OperatingSystem.IsTvOS()) {
diff --git a/src/RestSharp/RestClientInternalException.cs b/src/RestSharp/RestClientInternalException.cs
new file mode 100644
index 000000000..70a5aedee
--- /dev/null
+++ b/src/RestSharp/RestClientInternalException.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace RestSharp;
+
+/// <summary>
+/// This exception SHOULD only be used for catching and throwing internal
+/// exceptions within RestSharp.
+/// </summary>
+[Serializable]
+public class RestClientInternalException : Exception {
+    public RestClientInternalException() {
+    }
+
+    public RestClientInternalException(string? message, Exception? innerException) : base(message, innerException) {
+    }
+
+    protected RestClientInternalException(SerializationInfo info, StreamingContext context) : base(info, context) {
+    }
+}
diff --git a/test/RestSharp.InteractiveTests/AuthenticationTests.cs b/test/RestSharp.InteractiveTests/AuthenticationTests.cs
index c9f9cd6d9..23692d9b7 100644
--- a/test/RestSharp.InteractiveTests/AuthenticationTests.cs
+++ b/test/RestSharp.InteractiveTests/AuthenticationTests.cs
@@ -1,4 +1,5 @@
 using System.Net;
+using System.Text;
 using System.Web;
 using RestSharp.Authenticators;
 
@@ -30,7 +31,7 @@ public static async Task Can_Authenticate_With_OAuth_Async_With_Callback(Twitter
         Assert.NotNull(response);
         Assert.Equal(HttpStatusCode.OK, response.StatusCode);
 
-        var qs               = HttpUtility.ParseQueryString(response.Content);
+        var qs               = HttpUtility.ParseQueryString(response.Content, Encoding.UTF8);
         var oauthToken       = qs["oauth_token"];
         var oauthTokenSecret = qs["oauth_token_secret"];
 
diff --git a/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj b/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj
index c25f980cf..38ab23946 100644
--- a/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj
+++ b/test/RestSharp.InteractiveTests/RestSharp.InteractiveTests.csproj
@@ -1,11 +1,19 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
     <PropertyGroup>
         <OutputType>Exe</OutputType>
         <IsTestProject>false</IsTestProject>
         <TargetFramework>net6</TargetFramework>
     </PropertyGroup>
-    <ItemGroup>
+  <ItemGroup Condition="'$(TargetFramework)' == 'net472'">
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Web" />
+    <PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="All" />
+  </ItemGroup>
+  <ItemGroup>
         <ProjectReference Include="$(RepoRoot)\src\RestSharp\RestSharp.csproj" />
         <ProjectReference Include="..\RestSharp.Tests.Shared\RestSharp.Tests.Shared.csproj" />
     </ItemGroup>
+  <ItemGroup>
+    <PackageReference Update="xunit" Version="2.7.0" />
+  </ItemGroup>
 </Project>
diff --git a/test/RestSharp.Tests.Integrated/RedirectOptionsTest.cs b/test/RestSharp.Tests.Integrated/RedirectOptionsTest.cs
new file mode 100644
index 000000000..707c0ab2f
--- /dev/null
+++ b/test/RestSharp.Tests.Integrated/RedirectOptionsTest.cs
@@ -0,0 +1,795 @@
+using RestSharp.Tests.Integrated.Server;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+using RestSharp.Tests.Shared.Extensions;
+
+namespace RestSharp.Tests.Integrated {
+    [Collection(nameof(TestServerCollection))]
+    public class RedirectOptionsTest {
+        readonly string _host;
+        readonly Uri _baseUri;
+        readonly Uri _baseSecureUri;
+
+        public RedirectOptionsTest(TestServerFixture fixture) {
+            _baseUri = fixture.Server.Url;
+            _baseSecureUri = fixture.Server.SecureUrl;
+            _host = _baseUri.Host;
+        }
+
+        RestClientOptions NewOptions() {
+            return new RestClientOptions(_baseUri);
+        }
+
+        [Fact]
+        public async Task Can_RedirectForwardHeadersFalseWithAuthAndCookie_DropHeaders() {
+            var options = NewOptions();
+            options.RedirectOptions.ForwardHeaders = false;
+            options.RedirectOptions.ForwardAuthorization = true;
+            var client = new RestClient(options);
+
+            // This request sets cookies and redirects to url param value
+            // if supplied, otherwise redirects to /get-cookies
+            var request = new RestRequest("/get-cookies-redirect") {
+                Method = Method.Get,
+            };
+            request.AddHeader("Authorization", "blah");
+            request.AddQueryParameter("url", "/dump-headers");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-headers?url=%2fdump-headers");
+            var content = response.Content;
+            content.Should()
+                .NotContain("'Accept':")
+                .And.NotContain("'User-Agent':")
+                // NOTE: This is expected to be there for normal HTTP purposes
+                // and is expected to be re-added by the underlying HttpClient:
+                .And.Contain("'Host': ")
+                // NOTE: options.AutomaticDecompression controls
+                // Accept-Encoding, so since we did nothing to change that
+                // the underlying HttpClient will re-add this header:
+                .And.Contain("'Accept-Encoding':")
+                // These are expected due to redirection options for this test:
+                .And.Contain("'Cookie':")
+                .And.Contain("'Authorization':");
+
+            // Verify the cookie exists from the redirected get:
+            response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+            response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "value1");
+        }
+
+        [Fact]
+        public async Task Can_RedirectForwardHeadersFalseWithoutCookie_DropHeadersAndCookies() {
+            var options = NewOptions();
+            options.RedirectOptions.ForwardHeaders = false;
+            options.RedirectOptions.ForwardCookies = false;
+            var client = new RestClient(options);
+
+            // This request sets cookies and redirects to url param value
+            // if supplied, otherwise redirects to /get-cookies
+            var request = new RestRequest("/get-cookies-redirect") {
+                Method = Method.Get,
+            };
+            request.AddHeader("Authorization", "blah");
+            request.AddQueryParameter("url", "/dump-headers");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-headers?url=%2fdump-headers");
+            var content = response.Content;
+            // NOTE: This is expected to be there for normal HTTP purposes
+            // and is expected to be re-added by the underlying HttpClient:
+            content.Should()
+                .Contain("'Host': ")
+                // NOTE: options.AutomaticDecompression controls
+                // Accept-Encoding, so since we did nothing to change that
+                // the underlying HttpClient will re-add this header:
+                .And.Contain("'Accept-Encoding':")
+                // These are expected due to redirection options for this test:
+                .And.NotContain("'Cookie':")
+                .And.NotContain("'Accept':")
+                .And.NotContain("'User-Agent':")
+                .And.NotContain("'Authorization':");
+
+            // Verify the cookie exists from the redirected get:
+            response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+            // The cookies from get-cookies-redirect are placed in the cookie container
+            // even though they aren't transmitted to the server on the redirect to dump-headers:
+            response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "value1");
+        }
+
+        [Fact]
+        public async Task Can_RedirectForwardHeadersFalseWithCookie_DropHeaders() {
+            var options = NewOptions();
+            options.RedirectOptions.ForwardHeaders = false;
+            var client = new RestClient(options);
+
+            // This request sets cookies and redirects to url param value
+            // if supplied, otherwise redirects to /get-cookies
+            var request = new RestRequest("/get-cookies-redirect") {
+                Method = Method.Get,
+            };
+            request.AddHeader("Authorization", "blah");
+            request.AddQueryParameter("url", "/dump-headers");
+
+            // These are required to make sure existing cookie headers are preserved
+            // for this test:
+            request.CookieContainer = new();
+            request.CookieContainer.Add(new Cookie("cookie", "value", null, _host));
+            request.CookieContainer.Add(new Cookie("cookie2", "value2", null, _host));
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-headers?url=%2fdump-headers");
+            var content = response.Content;
+            content.Should()
+                // These are expected due to redirection options for this test:
+                .Contain("'Cookie':")
+                .And.NotContain("'Accept':")
+                .And.NotContain("'User-Agent':")
+                .And.NotContain("'Authorization':")
+                // NOTE: This is expected to be there for normal HTTP purposes
+                // and is expected to be re-added by the underlying HttpClient:
+                .And.Contain("'Host': ")
+                // NOTE: options.AutomaticDecompression controls
+                // Accept-Encoding, so since we did nothing to change that
+                // the underlying HttpClient will re-add this header:
+                .And.Contain("'Accept-Encoding':");
+
+            // Verify the cookie exists from the redirected get:
+            response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(3);
+            // The cookies from get-cookies-redirect are placed in the cookie container
+            // even though they aren't transmitted to the server on the redirect to dump-headers:
+            response.Cookies.Should()
+                .ContainCookieWithNameAndValue("redirectCookie", "value1")
+                .And.ContainCookieWithNameAndValue("cookie", "value")
+                .And.ContainCookieWithNameAndValue("cookie2", "value2");
+        }
+
+        [Fact]
+        public async Task Can_RedirectForwardHeadersFalseWithoutCookie_DropHeaders() {
+            var options = NewOptions();
+            options.RedirectOptions.ForwardHeaders = false;
+            options.RedirectOptions.ForwardCookies = false;
+            var client = new RestClient(options);
+
+            // This request sets cookies and redirects to url param value
+            // if supplied, otherwise redirects to /get-cookies
+            var request = new RestRequest("/get-cookies-redirect") {
+                Method = Method.Get,
+            };
+            request.AddHeader("Authorization", "blah");
+            request.AddQueryParameter("url", "/dump-headers");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-headers?url=%2fdump-headers");
+            var content = response.Content;
+            content.Should()
+                // This is expected due to redirection options for this test:
+                .NotContain("'Accept':")
+                .And.NotContain("'User-Agent':")
+                .And.NotContain("'Authorization':")
+                .And.NotContain("'Cookie':")
+                // NOTE: This is expected to be there for normal HTTP purposes
+                // and is expected to be re-added by the underlying HttpClient:
+                .And.Contain("'Host':")
+                // NOTE: options.AutomaticDecompression controls
+                // Accept-Encoding, so since we did nothing to change that
+                // the underlying HttpClient will re-add this header:
+                .And.Contain("'Accept-Encoding':");
+
+            // Verify the cookie exists from the redirected get:
+            response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+            response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "value1");
+        }
+
+        [Fact]
+        public async Task Can_RedirectWithForwardCookieFalse() {
+            var options = NewOptions();
+            options.RedirectOptions.ForwardAuthorization = true;
+            options.RedirectOptions.ForwardCookies = false;
+            var client = new RestClient(options);
+
+            // This request sets cookies and redirects to url param value
+            // if supplied, otherwise redirects to /get-cookies
+            var request = new RestRequest("/get-cookies-redirect") {
+                Method = Method.Get,
+            };
+            request.AddHeader("Authorization", "blah");
+            request.AddQueryParameter("url", "/dump-headers");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-headers?url=%2fdump-headers");
+            var content = response.Content;
+            // This is expected due to redirection options for this test:
+            content.Should()
+                .NotContain("'Cookie':")
+                // These should exist:
+                .And.Contain("'Accept':")
+                .And.Contain("'User-Agent':")
+                .And.Contain("'Authorization':")
+                .And.Contain("'Host':")
+                .And.Contain("'Accept-Encoding':");
+
+            // Regardless of ForwardCookie, the cookie container is ALWAYS
+            // updated:
+
+            // Verify the cookie exists from the redirected get:
+            response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+            response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "value1");
+        }
+
+        [Fact]
+        public async Task Can_RedirectWithForwardQueryWithRedirectLocationContainingQuery() {
+            var options = NewOptions();
+            var client = new RestClient(options);
+
+            // This request sets cookies and redirects to url param value
+            // if supplied, otherwise redirects to /get-cookies
+            var request = new RestRequest("/get-cookies-redirect") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("url", "/dump-headers?blah=blah2");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-headers?blah=blah2");
+            var content = response.Content;
+            // This is expected due to redirection options for this test:
+            content.Should()
+                .Contain("'Cookie':")
+                // These should exist:
+                .And.Contain("'Accept':")
+                .And.Contain("'User-Agent':")
+                .And.Contain("'Host':")
+                .And.Contain("'Accept-Encoding':");
+
+            // Verify the cookie exists from the redirected get:
+            response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+            response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "value1");
+        }
+
+        [Fact]
+        public async Task Can_RedirectWithForwardQueryFalse() {
+            var options = NewOptions();
+            options.RedirectOptions.ForwardQuery = false;
+            var client = new RestClient(options);
+
+            // This request sets cookies and redirects to url param value
+            // if supplied, otherwise redirects to /get-cookies
+            var request = new RestRequest("/get-cookies-redirect") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("url", "/dump-headers");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-headers");
+            var content = response.Content;
+            content.Should()
+                // This is expected due to redirection options for this test:
+                .Contain("'Cookie':")
+                // These should exist:
+                .And.Contain("'Accept':")
+                .And.Contain("'User-Agent':")
+                .And.Contain("'Host':")
+                .And.Contain("'Accept-Encoding':");
+
+            // Verify the cookie exists from the redirected get:
+            response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+            response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "value1");
+        }
+
+        [Fact]
+        public async Task Can_RedirectWithForwardFragment() {
+            var options = NewOptions();
+            var client = new RestClient(options);
+
+            // This request sets cookies and redirects to url param value
+            // if supplied, otherwise redirects to /get-cookies
+            var request = new RestRequest("/get-cookies-redirect#fragmentName") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("url", "/dump-headers");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-headers?url=%2fdump-headers#fragmentName");
+            var content = response.Content;
+            content.Should()
+                // This is expected due to redirection options for this test:
+                .Contain("'Cookie':")
+                // These should exist:
+                .And.Contain("'Accept':")
+                .And.Contain("'User-Agent':")
+                .And.Contain("'Host':")
+                .And.Contain("'Accept-Encoding':");
+
+            // Verify the cookie exists from the redirected get:
+            response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+            response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "value1");
+        }
+
+        [Fact]
+        public async Task Can_RedirectWithForwardFragmentFalse() {
+            var options = NewOptions();
+            options.RedirectOptions.ForwardFragment = false;
+            var client = new RestClient(options);
+
+            // This request sets cookies and redirects to url param value
+            // if supplied, otherwise redirects to /get-cookies
+            var request = new RestRequest("/get-cookies-redirect#fragmentName") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("url", "/dump-headers");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-headers?url=%2fdump-headers");
+            var content = response.Content;
+            // This is expected due to redirection options for this test:
+            content.Should().Contain("'Cookie':");
+            // These should exist:
+            content.Should().Contain("'Accept':");
+            content.Should().Contain("'User-Agent':");
+            content.Should().Contain("'Host':");
+            content.Should().Contain("'Accept-Encoding':");
+
+            // Verify the cookie exists from the redirected get:
+            response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+            response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "value1");
+        }
+
+        [Fact]
+        public async Task Can_RedirectWithForwardFragmentWithoutQuery() {
+            var options = NewOptions();
+            var client = new RestClient(options);
+
+            // This request sets cookies and redirects to url param value
+            // if supplied, otherwise redirects to /get-cookies
+            var request = new RestRequest("/get-cookies-redirect#fragmentName") {
+                Method = Method.Get,
+            };
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}get-cookies#fragmentName");
+            var content = response.Content;
+            content.Should().Contain("redirectCookie=value1");
+
+            // Verify the cookie exists from the redirected get:
+            response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+            response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "value1");
+        }
+
+        [Fact]
+        public async Task Can_RedirectBelowMaxRedirects_WithLoweredValue() {
+            var options = NewOptions();
+            options.RedirectOptions.MaxRedirects = 6;
+            var client = new RestClient(options);
+
+            // This request issues redirections to itself subracting 1
+            // from n until n == 1.
+            var request = new RestRequest("/redirect-countdown") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("n", "20");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.TemporaryRedirect);
+            response.ResponseUri.Should().Be($"{_baseUri}redirect-countdown?n=15");
+            HeaderParameter? locationHeader = null;
+            response.Headers.Should()
+                .Contain((header) => string.Compare(header.Name, "Location", StringComparison.InvariantCultureIgnoreCase) == 0);
+            locationHeader = (from header in response.Headers
+                              where string.Compare(header.Name, "Location", StringComparison.InvariantCultureIgnoreCase) == 0
+                              select header).First();
+            locationHeader.Value.Should().Be("/redirect-countdown?n=14");
+            var content = response.Content;
+            content.Should().NotContain("Stopped redirection countdown!");
+        }
+
+        [Fact]
+        public async Task Can_RedirectBelowMaxRedirects_WithDefault() {
+            var options = NewOptions();
+            var client = new RestClient(options);
+
+            // This request issues redirections to itself subracting 1
+            // from n until n == 1.
+            var request = new RestRequest("/redirect-countdown") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("n", "20");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}redirect-countdown?n=1");
+            var content = response.Content;
+            content.Should().Contain("Stopped redirection countdown!");
+        }
+
+        [Fact]
+        public async Task Can_RedirectAtMaxRedirects() {
+            var options = NewOptions();
+            var client = new RestClient(options);
+
+            // This request issues redirections to itself subracting 1
+            // from n until n == 1.
+            var request = new RestRequest("/redirect-countdown") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("n", "50");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}redirect-countdown?n=1");
+            var content = response.Content;
+            content.Should().Contain("Stopped redirection countdown!");
+        }
+
+        [Fact]
+        public async Task Can_StopRedirectAboveMaxRedirectDefault() {
+            var options = NewOptions();
+            var client = new RestClient(options);
+
+            // This request issues redirections to itself subracting 1
+            // from n until n == 1.
+            var request = new RestRequest("/redirect-countdown") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("n", "51");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.TemporaryRedirect);
+            response.ResponseUri.Should().Be($"{_baseUri}redirect-countdown?n=2");
+            var content = response.Content;
+            content.Should().NotContain("Stopped redirection countdown!");
+        }
+
+        [Fact]
+        public async Task Can_StopRedirectAboveMaxRedirectSet() {
+            var options = NewOptions();
+            options.RedirectOptions.MaxRedirects = 5;
+            var client = new RestClient(options);
+
+            // This request issues redirections to itself subracting 1
+            // from n until n == 1.
+            var request = new RestRequest("/redirect-countdown") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("n", "6");
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.TemporaryRedirect);
+            response.ResponseUri.Should().Be($"{_baseUri}redirect-countdown?n=2");
+            var content = response.Content;
+            content.Should().NotContain("Stopped redirection countdown!");
+        }
+
+        // Custom logic that can either override or extends the .NET validation logic
+        private static bool RemoteCertificateValidationCallback(object sender, X509Certificate? certificate,
+            X509Chain? chain,
+            SslPolicyErrors sslPolicyErrors) {
+            return true;
+        }
+
+        [Fact]
+        public async Task Can_FailToRedirectToInsecureUrl() {
+            var options = NewOptions();
+            options.RemoteCertificateValidationCallback = RemoteCertificateValidationCallback;
+            var client = new RestClient(options);
+
+            // This request redirects to insecure /dump-headers
+            // if the redirection is allowed.
+            var request = new RestRequest($"{_baseSecureUri}redirect-insecure") {
+                Method = Method.Get,
+            };
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.TemporaryRedirect);
+            response.ResponseUri.Should().NotBe($"{_baseUri}dump-headers");
+            response.ResponseUri.Should().Be($"{_baseSecureUri}redirect-insecure");
+            HeaderParameter? locationHeader = null;
+            response.Headers.Should().Contain((header) => string.Compare(header.Name, "Location", StringComparison.InvariantCultureIgnoreCase) == 0);
+            locationHeader = (from header in response.Headers
+                              where string.Compare(header.Name, "Location", StringComparison.InvariantCultureIgnoreCase) == 0
+                              select header).First();
+            locationHeader.Value.Should().Be($"{_baseUri}dump-headers");
+        }
+
+        [Fact]
+        public async Task Can_RedirectToInsecureUrlWithRedirectOption_True() {
+            var options = NewOptions();
+            options.RemoteCertificateValidationCallback = RemoteCertificateValidationCallback;
+            options.RedirectOptions.FollowRedirectsToInsecure = true;
+            var client = new RestClient(options);
+
+            // This request redirects to insecure /dump-headers
+            // if the redirection is allowed.
+            var request = new RestRequest($"{_baseSecureUri}redirect-insecure") {
+                Method = Method.Get,
+            };
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-headers");
+            response.ResponseUri.Should().NotBe($"{_baseSecureUri}redirect-insecure");
+        }
+
+        [Fact]
+        public async Task Can_RedirectToSecureUrl() {
+            var options = NewOptions();
+            options.RemoteCertificateValidationCallback = RemoteCertificateValidationCallback;
+            var client = new RestClient(options);
+
+            // This request redirects to secure /dump-headers
+            // if the redirection is allowed.
+            var request = new RestRequest($"{_baseUri}redirect-secure") {
+                Method = Method.Get,
+            };
+
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseSecureUri}dump-headers");
+            response.ResponseUri.Should().NotBe($"{_baseUri}redirect-insecure");
+            var content = response.Content;
+            content.Should()
+                .Contain("'Accept':")
+                .And.Contain("'User-Agent':")
+                .And.Contain("'Host':")
+                .And.Contain("'Accept-Encoding':");
+        }
+
+        [Fact]
+        public async Task Can_NotFollowRedirect_WithRedirectOption_FollowRedirect_False() {
+            var options = NewOptions();
+            options.RedirectOptions.FollowRedirects = false;
+            var client = new RestClient(options);
+
+            // This request issues redirections to itself subracting 1
+            // from n until n == 1.
+            var request = new RestRequest($"{_baseUri}redirect-countdown") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("n", "17");
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.TemporaryRedirect);
+            response.ResponseUri.Should().Be($"{_baseUri}redirect-countdown?n=17");
+            HeaderParameter? locationHeader = null;
+            response.Headers.Should().Contain((header) => string.Compare(header.Name, "Location", StringComparison.InvariantCultureIgnoreCase) == 0);
+            locationHeader = (from header in response.Headers
+                              where string.Compare(header.Name, "Location", StringComparison.InvariantCultureIgnoreCase) == 0
+                              select header).First();
+            locationHeader.Value.Should().Be("/redirect-countdown?n=16");
+        }
+
+        [Fact]
+        public async Task Can_NotFollowRedirect_WithOption_FollowRedirect_False() {
+            var options = NewOptions();
+            options.FollowRedirects = false;
+            var client = new RestClient(options);
+
+            // This request issues redirections to itself subracting 1
+            // from n until n == 1.
+            var request = new RestRequest($"{_baseUri}redirect-countdown") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("n", "17");
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.TemporaryRedirect);
+            response.ResponseUri.Should().Be($"{_baseUri}redirect-countdown?n=17");
+            HeaderParameter? locationHeader = null;
+            response.Headers.Should().Contain((header) => string.Compare(header.Name, "Location", StringComparison.InvariantCultureIgnoreCase) == 0);
+            locationHeader = (from header in response.Headers
+                              where string.Compare(header.Name, "Location", StringComparison.InvariantCultureIgnoreCase) == 0
+                              select header).First();
+            locationHeader.Value.Should().Be("/redirect-countdown?n=16");
+        }
+
+        [Fact]
+        public async Task Can_NotAlterVerb_WithRedirectOption_AllowForcedRedirectVerbChange_False_WithStatusCode_302() {
+            var options = NewOptions();
+            // NOTE: This isn't required, it just makes the test simpler:
+            options.RedirectOptions.ForwardQuery = false;
+            // This is the setting for the test:
+            options.RedirectOptions.AllowForcedRedirectVerbChange = false;
+            var client = new RestClient(options);
+
+            // This request issues redirections to the url parameter or /dump-headers
+            // with a 302 status code.
+            var request = new RestRequest($"{_baseUri}redirect-forcechangeverb") {
+                Method = Method.Post,
+            };
+            request.AddQueryParameter("url", $"{_baseUri}dump-request");
+            request.AddStringBody("blah blah blah", DataFormat.None);
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-request");
+            var content = response.Content;
+            content.Should().Contain("POST")
+                .And.Contain("blah blah blah");
+        }
+
+        [Fact]
+        public async Task Can_NotAlterVerb_WithRedirectOption_AllowRedirectMethodStatusCodeToAlterVerb_WithStatusCode_303() {
+            var options = NewOptions();
+            // NOTE: This isn't required, it just makes the test simpler:
+            options.RedirectOptions.ForwardQuery = false;
+            // This is the setting for the test:
+            options.RedirectOptions.AllowRedirectMethodStatusCodeToAlterVerb = false;
+            var client = new RestClient(options);
+            // This request issues redirections to the url parameter or /dump-headers
+            // with a 303 status code.
+            var request = new RestRequest($"{_baseUri}redirect-changeverb") {
+                Method = Method.Post,
+            };
+            request.AddQueryParameter("url", $"{_baseUri}dump-request");
+            request.AddStringBody("blah blah blah", DataFormat.None);
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-request");
+            var content = response.Content;
+            content.Should().Contain("POST")
+                .And.Contain("blah blah blah");
+        }
+
+        [Fact]
+        public async Task Can_AlterVerb_WithStatusCode302() {
+            var options = NewOptions();
+            // NOTE: This isn't required, it just makes the test simpler:
+            options.RedirectOptions.ForwardQuery = false;
+            var client = new RestClient(options);
+            // This request issues redirections to the url parameter or /dump-headers
+            // with a 302 status code.
+            var request = new RestRequest($"{_baseUri}redirect-forcechangeverb") {
+                Method = Method.Post,
+            };
+            request.AddQueryParameter("url", $"{_baseUri}dump-request");
+            request.AddStringBody("blah blah blah", DataFormat.None);
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-request");
+            var content = response.Content;
+            content.Should().Contain("GET")
+                .And.NotContain("blah blah blah", "Altered verbs MUST NOT foward along the body");
+        }
+
+        [Fact]
+        public async Task Can_AlterVerb_WithStatusCode_303() {
+            var options = NewOptions();
+            // NOTE: This isn't required, it just makes the test simpler:
+            options.RedirectOptions.ForwardQuery = false;
+            var client = new RestClient(options);
+            // This request issues redirections to the url parameter or /dump-headers
+            // with a 303 status code.
+            var request = new RestRequest($"{_baseUri}redirect-changeverb") {
+                Method = Method.Post,
+            };
+            request.AddQueryParameter("url", $"{_baseUri}dump-request");
+            request.AddStringBody("blah blah blah", DataFormat.None);
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-request");
+            var content = response.Content;
+            content.Should().Contain("GET")
+                .And.NotContain("blah blah blah", "Altered verbs MUST NOT foward along the body");
+        }
+
+        [Fact]
+        public async Task Can_RedirectWithoutChangingVerb_With_RedirectStatus_307() {
+            var options = NewOptions();
+            // NOTE: This isn't required, it just makes the test simpler:
+            options.RedirectOptions.ForwardQuery = false;
+            var client = new RestClient(options);
+            // This request issues redirections to the url parameter or /dump-headers
+            // with a 307 status code.
+            var request = new RestRequest($"{_baseUri}redirect-keepverb") {
+                Method = Method.Post,
+            };
+            request.AddQueryParameter("url", $"{_baseUri}dump-request");
+            request.AddStringBody("blah blah blah", DataFormat.None);
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-request");
+            var content = response.Content;
+            content.Should().Contain("POST")
+                .And.Contain("blah blah blah", "Altered verbs MUST NOT foward along the body");
+        }
+
+        [Fact]
+        public async Task Can_RedirectWithCookies_HavingOptionLevel_CookieContainer() {
+            var options = NewOptions();
+            // NOTE: This isn't required, it just makes the test simpler:
+            options.RedirectOptions.ForwardQuery = false;
+            options.CookieContainer = new ();
+            var client = new RestClient(options);
+            // This request issues redirections to the url parameter or /dump-headers
+            // with a 307 status code.
+            var request = new RestRequest($"{_baseUri}get-cookies-redirect") {
+                Method = Method.Get,
+            };
+            request.AddQueryParameter("url", $"{_baseUri}set-cookies");
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}set-cookies");
+            response.Cookies!.Count.Should().Be(5);
+            response.Cookies.Should()
+                .ContainCookieWithNameAndValue("redirectCookie", "value1")
+                .And.ContainCookieWithNameAndValue("cookie1", "value1")
+                // This cookie is excluded from the response CookieCollection because /path_extra
+                // doesn't intersect with the ResponseUri.
+                .And.NotContainCookieWithNameAndValue("cookie2", "value2")
+                .And.ContainCookieWithNameAndValue("cookie3", "value3")
+                .And.ContainCookieWithNameAndValue("cookie4", "value4")
+                // This cookie is excluded from the response CookieCollection because
+                // it was marked as secure.
+                .And.NotContainCookieWithNameAndValue("cookie5", "value5")
+                .And.ContainCookieWithNameAndValue("cookie6", "value6");
+            verifyAllCookies(request.CookieContainer!.GetAllCookies());
+            verifyAllCookies(options.CookieContainer!.GetAllCookies());
+
+            void verifyAllCookies(CookieCollection cookies) {
+                cookies.Should()
+                    .ContainCookieWithNameAndValue("redirectCookie", "value1")
+                    .And.ContainCookieWithNameAndValue("cookie1", "value1")
+                    .And.ContainCookieWithNameAndValue("cookie2", "value2")
+                    .And.ContainCookieWithNameAndValue("cookie3", "value3")
+                    .And.ContainCookieWithNameAndValue("cookie4", "value4")
+                    .And.ContainCookieWithNameAndValue("cookie5", "value5")
+                    .And.ContainCookieWithNameAndValue("cookie6", "value6");
+            }
+        }
+
+        [Fact]
+        public async Task Can_AlterVerb_WithRedirectStatusCode_303_AndForwardBody() {
+            var options = NewOptions();
+            // NOTE: This isn't required, it just makes the test simpler:
+            options.RedirectOptions.ForwardQuery = false;
+            options.RedirectOptions.ForceForwardBody = true;
+            var client = new RestClient(options);
+            // This request issues redirections to the url parameter or /dump-headers
+            // with a 303 status code.
+            var request = new RestRequest($"{_baseUri}redirect-changeverb") {
+                Method = Method.Post,
+            };
+            request.AddQueryParameter("url", $"{_baseUri}dump-request");
+            request.AddStringBody("blah blah blah", DataFormat.None);
+            var response = await client.ExecuteAsync(request);
+
+            response.StatusCode.Should().Be(HttpStatusCode.OK);
+            response.ResponseUri.Should().Be($"{_baseUri}dump-request");
+            var content = response.Content;
+            content.Should().Contain("GET")
+                .And.Contain("blah blah blah", "ForwardBody");
+        }
+    }
+}
diff --git a/test/RestSharp.Tests.Integrated/RedirectTests.cs b/test/RestSharp.Tests.Integrated/RedirectTests.cs
index 47b4954a2..51a02c7f1 100644
--- a/test/RestSharp.Tests.Integrated/RedirectTests.cs
+++ b/test/RestSharp.Tests.Integrated/RedirectTests.cs
@@ -15,18 +15,21 @@
 
 using System.Net;
 using RestSharp.Tests.Integrated.Server;
+using RestSharp.Tests.Shared.Extensions;
 
 namespace RestSharp.Tests.Integrated;
 
 [Collection(nameof(TestServerCollection))]
 public class RedirectTests {
     readonly RestClient _client;
+    readonly string     _host;
 
     public RedirectTests(TestServerFixture fixture) {
         var options = new RestClientOptions(fixture.Server.Url) {
             FollowRedirects = true
         };
         _client = new RestClient(options);
+        _host   = _client.Options.BaseUrl!.Host;
     }
 
     [Fact]
@@ -40,6 +43,105 @@ public async Task Can_Perform_GET_Async_With_Redirect() {
         response.Data!.Message.Should().Be(val);
     }
 
+    [Fact]
+    public async Task Can_Perform_GET_Async_With_Request_Cookies_And_RedirectCookie() {
+        var request = new RestRequest("get-cookies-redirect") {
+            CookieContainer = new CookieContainer(),
+        };
+        request.AddQueryParameter("url", "set-cookies");
+        request.CookieContainer.Add(new Cookie("cookie", "value", null, _host));
+        request.CookieContainer.Add(new Cookie("cookie2", "value2", null, _host));
+        var response = await _client.ExecuteAsync(request);
+        response.Content.Should().Contain("success");
+        request.CookieContainer!.Count.Should().Be(9);
+        request.CookieContainer!.GetAllCookies().Should()
+                .ContainCookieWithNameAndValue("cookie", "value")
+                .And.ContainCookieWithNameAndValue("cookie2", "value2")
+                .And.ContainCookieWithNameAndValue("redirectCookie", "value1")
+                .And.ContainCookieWithNameAndValue("cookie1", "value1")
+                .And.ContainCookieWithNameAndValue("cookie2", "value2")
+                .And.ContainCookieWithNameAndValue("cookie3", "value3")
+                .And.ContainCookieWithNameAndValue("cookie4", "value4")
+                .And.ContainCookieWithNameAndValue("cookie5", "value5")
+                .And.ContainCookieWithNameAndValue("cookie6", "value6");
+    }
+
+    [Fact]
+    public async Task Can_Perform_POST_Async_With_RedirectionResponse_Cookies() {
+        var request = new RestRequest("/post/set-cookie-redirect") {
+            Method = Method.Post,
+        };
+
+        var response = await _client.ExecuteAsync(request);
+
+        // Verify the cookie exists from the POST:
+        response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+        response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "value1");
+        // Make sure the redirected location spits out the correct content:
+        response.Content.Should().Be("[\"redirectCookie=value1\"]", "was successfully redirected to get-cookies");
+    }
+
+    [Fact]
+    public async Task Can_Perform_POST_Async_With_SeeOtherRedirectionResponse_Cookies() {
+        var request = new RestRequest("/post/set-cookie-seeother") {
+            Method = Method.Post,
+        };
+
+        var response = await _client.ExecuteAsync(request);
+
+        // Verify the cookie exists from the POST:
+        response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+        response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "seeOtherValue1");
+        // Make sure the redirected location spits out the correct content:
+        response.Content.Should().Be("[\"redirectCookie=seeOtherValue1\"]", "was successfully redirected to get-cookies");
+    }
+
+    [Fact]
+    public async Task Can_Perform_PUT_Async_With_RedirectionResponse_Cookies() {
+        var request = new RestRequest("/put/set-cookie-redirect") {
+            Method = Method.Put,
+        };
+
+        var response = await _client.ExecuteAsync(request);
+
+        // Verify the cookie exists from the PUT:
+        response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+        response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "putCookieValue1");
+        // However, the redirection status code should be a 405 (Method Not Allowed):
+        response.StatusCode.Should().Be(HttpStatusCode.MethodNotAllowed);
+    }
+
+    [Fact]
+    public async Task Can_ForwardHeadersTrue_OnRedirect() {
+        // This request sets cookies and redirects to url param value
+        // if supplied, otherwise redirects to /get-cookies
+        var request = new RestRequest("/get-cookies-redirect") {
+            Method = Method.Get,
+        };
+        request.AddQueryParameter("url", "/dump-headers");
+
+        var response = await _client.ExecuteAsync(request);
+        response.ResponseUri.Should().Be($"{_client.Options.BaseUrl}dump-headers?url=%2fdump-headers");
+        var content = response.Content;
+        content.Should()
+            .Contain("'Accept':")
+            .And.Contain($"'Host': {_client.Options.BaseHost}")
+            .And.Contain("'User-Agent':")
+            .And.Contain("'Accept-Encoding':")
+            .And.Contain("'Cookie':");
+
+        // Verify the cookie exists from the redirected get:
+        response.Cookies!.Count.Should().BeGreaterThan(0).And.Be(1);
+        response.Cookies.Should().ContainCookieWithNameAndValue("redirectCookie", "value1");
+    }
+
+    // Needed tests:
+    //Test: ForwardBody = true (default, might not need test)
+    //Test: ForwardBody = false
+    //Test: ForceForwardBody = false (default, might not need test)
+    //Test: Altered Redirect Status Codes list
+
+
     class Response {
         public string? Message { get; set; }
     }
diff --git a/test/RestSharp.Tests.Integrated/RestSharp.Tests.Integrated.csproj b/test/RestSharp.Tests.Integrated/RestSharp.Tests.Integrated.csproj
index cd511eb9b..22ca7a974 100644
--- a/test/RestSharp.Tests.Integrated/RestSharp.Tests.Integrated.csproj
+++ b/test/RestSharp.Tests.Integrated/RestSharp.Tests.Integrated.csproj
@@ -20,8 +20,14 @@
         <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.21" />
         <PackageReference Include="Polly" Version="7.2.4" />
         <PackageReference Include="Xunit.Extensions.Logging" Version="1.1.0" />
+        <PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.9.0" />
+        <PackageReference Update="xunit" Version="2.7.0" />
+        <PackageReference Update="xunit.runner.visualstudio" Version="2.5.7" />
     </ItemGroup>
     <ItemGroup>
+        <None Update="Server\testCert.pfx">
+          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+        </None>
         <None Update="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
     </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/test/RestSharp.Tests.Integrated/Server/Handlers/RedirectWithStatusCodeResult.cs b/test/RestSharp.Tests.Integrated/Server/Handlers/RedirectWithStatusCodeResult.cs
new file mode 100644
index 000000000..d5cc79f3d
--- /dev/null
+++ b/test/RestSharp.Tests.Integrated/Server/Handlers/RedirectWithStatusCodeResult.cs
@@ -0,0 +1,33 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace RestSharp.Tests.Integrated.Server.Handlers;
+
+/// <summary>
+/// An <see cref="IResult"/> that returns a redirection with a supplied status code value. 
+/// Created in order to easily return a SeeOther status code.
+/// </summary>
+class RedirectWithStatusCodeResult : IResult {
+    public int StatusCode { get; }
+    public string Uri { get; }
+
+    public RedirectWithStatusCodeResult(int statusCode, string url) {
+        Uri = url;
+        StatusCode = statusCode;
+    }
+
+    public Task ExecuteAsync(HttpContext httpContext) {
+        ArgumentNullException.ThrowIfNull(httpContext);
+
+        httpContext.Response.StatusCode = StatusCode;
+        httpContext.Response.Headers.Location = Uri;
+
+        return Task.CompletedTask;
+    }
+}
diff --git a/test/RestSharp.Tests.Integrated/Server/TestServer.cs b/test/RestSharp.Tests.Integrated/Server/TestServer.cs
index dd075532a..495e2ef4d 100644
--- a/test/RestSharp.Tests.Integrated/Server/TestServer.cs
+++ b/test/RestSharp.Tests.Integrated/Server/TestServer.cs
@@ -5,6 +5,13 @@
 using Microsoft.Extensions.Logging;
 using RestSharp.Tests.Integrated.Server.Handlers;
 using RestSharp.Tests.Shared.Extensions;
+using System.Net;
+using System.Reflection;
+using System.Security;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Web;
+
 // ReSharper disable ConvertClosureToMethodGroup
 
 namespace RestSharp.Tests.Integrated.Server;
@@ -13,6 +20,7 @@ public sealed class HttpServer {
     readonly WebApplication _app;
 
     const string Address = "http://localhost:5151";
+    const string SecureAddress = "https://localhost:5152";
 
     public const string ContentResource = "content";
     public const string TimeoutResource = "timeout";
@@ -22,8 +30,23 @@ public HttpServer(ITestOutputHelper? output = null) {
 
         if (output != null) builder.Logging.AddXunit(output, LogLevel.Debug);
 
+        var currentAssemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
         builder.Services.AddControllers().AddApplicationPart(typeof(UploadController).Assembly);
-        builder.WebHost.UseUrls(Address);
+        builder.WebHost.UseUrls(Address, SecureAddress).UseKestrel(options => {
+            options.ListenAnyIP(5151, listenOptions => { return; });
+            // Yes, this is lame, but dotnet dev-certs was giving me grief trying to export
+            // the public key using an empty password... :(
+            var secureString = new SecureString();
+            secureString.AppendChar('b');
+            secureString.AppendChar('l');
+            secureString.AppendChar('a');
+            secureString.AppendChar('h');
+            secureString.MakeReadOnly();
+            options.ListenAnyIP(5152,
+                listenOptions => listenOptions.UseHttps(
+                    new X509Certificate2(Path.Join(currentAssemblyPath, "Server\\testCert.pfx"),
+                    secureString)));
+        });
         _app = builder.Build();
 
         _app.MapControllers();
@@ -36,11 +59,119 @@ public HttpServer(ITestOutputHelper? output = null) {
         _app.MapGet("headers", HeaderHandlers.HandleHeaders);
         _app.MapGet("request-echo", async context => await context.Request.BodyReader.AsStream().CopyToAsync(context.Response.BodyWriter.AsStream()));
         _app.MapDelete("delete", () => new TestResponse { Message = "Works!" });
+        _app.MapPost("redirect-forcechangeverb",
+            (HttpContext ctx) => {
+                string redirectDestination = "/dump-headers";
+                var queryString = HttpUtility.ParseQueryString(ctx.Request.QueryString.Value ?? string.Empty);
+                var urlParameter = queryString.Get("url");
+                if (!string.IsNullOrEmpty(urlParameter)) {
+                    redirectDestination = urlParameter;
+                }
+                // This forces the verb to change on the redirect to GET, unless the client has set the correct
+                // RedirectOption setting. (302)
+                return new RedirectWithStatusCodeResult((int)HttpStatusCode.Redirect, redirectDestination);
+            });
+        _app.MapPost("redirect-changeverb",
+            (HttpContext ctx) => {
+                string redirectDestination = "/dump-headers";
+                var queryString = HttpUtility.ParseQueryString(ctx.Request.QueryString.Value ?? string.Empty);
+                var urlParameter = queryString.Get("url");
+                if (!string.IsNullOrEmpty(urlParameter)) {
+                    redirectDestination = urlParameter;
+                }
+                // This allows the method to change to GET on redirect on purpose, unless the client has set the correct
+                // RedirectOption setting. (303)
+                return new RedirectWithStatusCodeResult((int)HttpStatusCode.RedirectMethod, redirectDestination);
+            });
+        _app.MapPost("redirect-keepverb",
+            (HttpContext ctx) => {
+                string redirectDestination = "/dump-headers";
+                var queryString = HttpUtility.ParseQueryString(ctx.Request.QueryString.Value ?? string.Empty);
+                var urlParameter = queryString.Get("url");
+                if (!string.IsNullOrEmpty(urlParameter)) {
+                    redirectDestination = urlParameter;
+                }
+                // This prevents the method to change on redirect. (307)
+                return new RedirectWithStatusCodeResult((int)HttpStatusCode.RedirectKeepVerb, redirectDestination);
+            });
+        _app.MapGet("redirect-insecure", (HttpContext ctx) => {
+            string destination = $"{Address}/dump-headers";
+            return Results.Redirect(destination, false, true);
+        });
+        _app.MapGet("redirect-secure", (HttpContext ctx) => {
+            string destination = $"{SecureAddress}/dump-headers";
+            return Results.Redirect(destination, false, true);
+        });
+        _app.MapGet("redirect-countdown",
+            (HttpContext ctx) => {
+                string redirectDestination = "/redirect-countdown";
+                var queryString = HttpUtility.ParseQueryString(ctx.Request.QueryString.Value ?? string.Empty);
+                int redirectsLeft = -1;
+                redirectsLeft = int.Parse(queryString.Get("n"));
+                if (redirectsLeft != -1
+                    && redirectsLeft > 1) {
+                    redirectDestination = $"{redirectDestination}?n={redirectsLeft - 1}";
+                    return Results.Redirect(redirectDestination, false, true);
+                }
+                return Results.Ok("Stopped redirection countdown!");
+            });
+
+        _app.MapGet("dump-headers",
+            (HttpContext ctx) => {
+                var headers = ctx.Request.Headers;
+                StringBuilder sb = new StringBuilder();
+                foreach (var kvp in headers) {
+                    sb.Append($"'{kvp.Key}': '{kvp.Value}',");
+                }
+                return new TestResponse { Message = sb.ToString() };
+            });
+
+        _app.MapGet("dump-request", DumpRequest);
+        _app.MapPut("dump-request", DumpRequest);
+        _app.MapPost("dump-request", DumpRequest);
+        _app.MapDelete("dump-request", DumpRequest);
 
         // Cookies
         _app.MapGet("get-cookies", CookieHandlers.HandleCookies);
+        _app.MapPut("get-cookies",
+            (HttpContext cxt) => {
+                // Make sure we get the status code we expect:
+                return Results.StatusCode(405);
+            });
         _app.MapGet("set-cookies", CookieHandlers.HandleSetCookies);
         _app.MapGet("redirect", () => Results.Redirect("/success", false, true));
+        _app.MapGet(
+            "get-cookies-redirect",
+            (HttpContext ctx) => {
+                ctx.Response.Cookies.Append("redirectCookie", "value1");
+                string redirectDestination = "/get-cookies";
+                var queryString = HttpUtility.ParseQueryString(ctx.Request.QueryString.Value ?? string.Empty);
+                var urlParameter = queryString.Get("url");
+                if (!string.IsNullOrEmpty(urlParameter)) {
+                    redirectDestination = urlParameter;
+                }
+                return Results.Redirect(redirectDestination, false, true);
+            }
+        );
+
+        _app.MapPost(
+            "/post/set-cookie-redirect",
+            (HttpContext ctx) => {
+                ctx.Response.Cookies.Append("redirectCookie", "value1");
+                return Results.Redirect("/get-cookies", permanent: false, preserveMethod: false);
+            });
+        _app.MapPost(
+            "/post/set-cookie-seeother",
+            (HttpContext ctx) => {
+                ctx.Response.Cookies.Append("redirectCookie", "seeOtherValue1");
+                return new RedirectWithStatusCodeResult((int)HttpStatusCode.SeeOther, "/get-cookies");
+            });
+        _app.MapPut(
+            "/put/set-cookie-redirect",
+            (HttpContext ctx) => {
+                ctx.Response.Cookies.Append("redirectCookie", "putCookieValue1");
+                return Results.Redirect("/get-cookies", permanent: false, preserveMethod: false);
+            });
 
         // PUT
         _app.MapPut(
@@ -64,9 +195,19 @@ public HttpServer(ITestOutputHelper? output = null) {
         );
 
         _app.MapPost("/post/data", FormRequestHandler.HandleForm);
+
+        // Dump the request verb and body into the response.
+        TestResponse DumpRequest(HttpContext ctx) {
+            var method = ctx.Request.Method;
+            var task = ctx.Request.Body.StreamToStringAsync();
+            task.Wait();
+            var body = task.Result;
+            return new TestResponse { Message = $"Method: {method}\r\nBody: {body}" };
+        }
     }
 
     public Uri Url => new(Address);
+    public Uri SecureUrl => new(SecureAddress);
 
     public Task Start() => _app.StartAsync();
 
diff --git a/test/RestSharp.Tests.Integrated/Server/testCert.pfx b/test/RestSharp.Tests.Integrated/Server/testCert.pfx
new file mode 100644
index 000000000..bb6e35812
Binary files /dev/null and b/test/RestSharp.Tests.Integrated/Server/testCert.pfx differ
diff --git a/test/RestSharp.Tests.Serializers.Csv/RestSharp.Tests.Serializers.Csv.csproj b/test/RestSharp.Tests.Serializers.Csv/RestSharp.Tests.Serializers.Csv.csproj
index 4477eea34..7cda432ff 100644
--- a/test/RestSharp.Tests.Serializers.Csv/RestSharp.Tests.Serializers.Csv.csproj
+++ b/test/RestSharp.Tests.Serializers.Csv/RestSharp.Tests.Serializers.Csv.csproj
@@ -1,6 +1,11 @@
 <Project Sdk="Microsoft.NET.Sdk">
     <ItemGroup>
-        <ProjectReference Include="$(RepoRoot)\src\RestSharp.Serializers.CsvHelper\RestSharp.Serializers.CsvHelper.csproj"/>
-        <ProjectReference Include="..\RestSharp.Tests.Shared\RestSharp.Tests.Shared.csproj"/>
+        <ProjectReference Include="$(RepoRoot)\src\RestSharp.Serializers.CsvHelper\RestSharp.Serializers.CsvHelper.csproj" />
+        <ProjectReference Include="..\RestSharp.Tests.Shared\RestSharp.Tests.Shared.csproj" />
+    </ItemGroup>
+    <ItemGroup>
+      <PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.9.0" />
+      <PackageReference Update="xunit" Version="2.7.0" />
+      <PackageReference Update="xunit.runner.visualstudio" Version="2.5.7" />
     </ItemGroup>
 </Project>
diff --git a/test/RestSharp.Tests.Serializers.Json/RestSharp.Tests.Serializers.Json.csproj b/test/RestSharp.Tests.Serializers.Json/RestSharp.Tests.Serializers.Json.csproj
index a7703166c..f1b45e9b1 100644
--- a/test/RestSharp.Tests.Serializers.Json/RestSharp.Tests.Serializers.Json.csproj
+++ b/test/RestSharp.Tests.Serializers.Json/RestSharp.Tests.Serializers.Json.csproj
@@ -15,4 +15,9 @@
         <PackageReference Include="rest-mock-core" Version="0.7.12" />
         <Compile Include="NewtonsoftJson\IntegratedTests.cs" />
     </ItemGroup>
+    <ItemGroup>
+      <PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.9.0" />
+      <PackageReference Update="xunit" Version="2.7.0" />
+      <PackageReference Update="xunit.runner.visualstudio" Version="2.5.7" />
+    </ItemGroup>
 </Project>
diff --git a/test/RestSharp.Tests.Serializers.Xml/RestSharp.Tests.Serializers.Xml.csproj b/test/RestSharp.Tests.Serializers.Xml/RestSharp.Tests.Serializers.Xml.csproj
index 10c42ccc4..2625d739f 100644
--- a/test/RestSharp.Tests.Serializers.Xml/RestSharp.Tests.Serializers.Xml.csproj
+++ b/test/RestSharp.Tests.Serializers.Xml/RestSharp.Tests.Serializers.Xml.csproj
@@ -23,5 +23,10 @@
         <None Update="SampleData\xmllists.xml" CopyToOutputDirectory="PreserveNewest" />
         <None Update="SampleData\restsharp.nuspec" CopyToOutputDirectory="PreserveNewest" />
     </ItemGroup>
+    <ItemGroup>
+      <PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.9.0" />
+      <PackageReference Update="xunit" Version="2.7.0" />
+      <PackageReference Update="xunit.runner.visualstudio" Version="2.5.7" />
+    </ItemGroup>
 
 </Project>
diff --git a/test/RestSharp.Tests.Shared/Extensions/FluentAssertionCookieExtensions.cs b/test/RestSharp.Tests.Shared/Extensions/FluentAssertionCookieExtensions.cs
new file mode 100644
index 000000000..b326045ac
--- /dev/null
+++ b/test/RestSharp.Tests.Shared/Extensions/FluentAssertionCookieExtensions.cs
@@ -0,0 +1,104 @@
+using FluentAssertions.Collections;
+using FluentAssertions.Execution;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+// Since the generic types are so long, lets simplify them:
+using CookieCollection = FluentAssertions.Collections.GenericCollectionAssertions<System.Net.Cookie>;
+using AndWhich = FluentAssertions.AndWhichConstraint<
+    FluentAssertions.Collections.GenericCollectionAssertions<System.Net.Cookie>, System.Net.Cookie>;
+
+namespace RestSharp.Tests.Shared.Extensions;
+
+/// <summary>
+/// Some Fluent Assertion helper extensions for verifying CookieCollection contents.
+/// </summary>
+public static class FluentAssertionCookieExtensions {
+    /// <summary>
+    /// Allow FluentAssertions to be able to easily verify name/value cookies exist.
+    /// </summary>
+    /// <param name="genericCollection"></param>
+    /// <param name="name"></param>
+    /// <param name="value"></param>
+    /// <param name="because"></param>
+    /// <param name="becauseArgs"></param>
+    /// <returns></returns>
+    static public AndWhich ContainCookieWithNameAndValue(this CookieCollection genericCollection, string name, string value, string because = "", params object[] becauseArgs) {
+        bool success = Execute.Assertion
+            .BecauseOf(because, becauseArgs)
+            .ForCondition(genericCollection.Subject is not null)
+            .FailWith("Expected Cookie {context:collection} to contain Name: '{0}', Value: '{1}'{reason}, but found <null>.", name, value);
+
+        IEnumerable<Cookie> matches = Enumerable.Empty<Cookie>();
+
+        if (success) {
+            IEnumerable<Cookie> collection = genericCollection.Subject;
+
+            Execute.Assertion
+                .BecauseOf(because, becauseArgs)
+                .ForCondition(ContainsCookieWithNameAndValue(collection, name, value))
+                .FailWith("Expected Cookie {context:collection} {0} to contain cookie with Name: '{1}' Value: '{2}'{reason}.", collection, name, value);
+
+            matches = collection.Where(item => ContainsCookieWithNameAndValue(collection, name, value));
+        }
+
+        return new AndWhich(genericCollection, matches);
+    }
+
+    /// <summary>
+    /// Allow FluentAssertions to be able to easily verify that the supplied name/value cookie does NOT exist.
+    /// </summary>
+    /// <param name="genericCollection"></param>
+    /// <param name="name"></param>
+    /// <param name="value"></param>
+    /// <param name="because"></param>
+    /// <param name="becauseArgs"></param>
+    /// <returns></returns>
+    static public AndWhich NotContainCookieWithNameAndValue(this CookieCollection genericCollection, string name, string value, string because = "", params object[] becauseArgs) {
+        bool success = Execute.Assertion
+            .BecauseOf(because, becauseArgs)
+            .ForCondition(genericCollection.Subject is not null)
+            .FailWith("Expected {context:collection} to not contain Name: '{0}', Value: '{1}'{reason}, but found <null>.", name, value);
+
+        IEnumerable<Cookie> matched = Enumerable.Empty<Cookie>();
+
+        if (success) {
+            IEnumerable<Cookie> collection = genericCollection.Subject;
+
+            if (ContainsCookieWithNameAndValue(collection, name, value)) {
+                Execute.Assertion
+                    .BecauseOf(because, becauseArgs)
+                    .FailWith("Expected {context:collection} {0} to not contain cookie with Name: '{1}' Value: '{2}'{reason}.", collection, name, value);
+            }
+
+            matched = collection.Where(item => ContainsCookieWithNameAndValue(collection, name, value));
+        }
+
+        return new AndWhich(genericCollection, matched);
+    }
+
+    /// <summary>
+    /// Determine if the collection contains a name/value matching cookie.
+    /// </summary>
+    /// <param name="collection"></param>
+    /// <param name="name"></param>
+    /// <param name="value"></param>
+    /// <returns></returns>
+    /// <remarks>
+    /// NOTE: There are other important criteria in Cookies like domain, path, etc...
+    /// If you want to check everything, don't use these extensions..
+    /// </remarks>
+    private static bool ContainsCookieWithNameAndValue(IEnumerable<Cookie> collection, string name, string value) {
+        foreach (Cookie cookie in collection) {
+            if (string.Compare(cookie.Name, name, StringComparison.OrdinalIgnoreCase) == 0
+                && string.Compare(cookie.Value, value, StringComparison.Ordinal) == 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs b/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs
index d53863c2f..ea753ac68 100644
--- a/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs
+++ b/test/RestSharp.Tests.Shared/Fixtures/SimpleServer.cs
@@ -32,7 +32,15 @@ public static SimpleServer Create(
         Action<HttpListenerContext> handler               = null,
         AuthenticationSchemes       authenticationSchemes = AuthenticationSchemes.Anonymous
     ) {
+    TryAgain:
         var port = Random.Next(1000, 9999);
+        // Don't use Fiddler's default port,
+        // or the TestServer insecure/secure ports:
+        if (port == 8888
+            || port == 5151
+            || port == 5152) {
+            goto TryAgain;
+        }
         return new SimpleServer(port, handler, authenticationSchemes);
     }
 
diff --git a/test/RestSharp.Tests.Shared/RestSharp.Tests.Shared.csproj b/test/RestSharp.Tests.Shared/RestSharp.Tests.Shared.csproj
index 274f12fb9..befda2aa8 100644
--- a/test/RestSharp.Tests.Shared/RestSharp.Tests.Shared.csproj
+++ b/test/RestSharp.Tests.Shared/RestSharp.Tests.Shared.csproj
@@ -2,4 +2,7 @@
     <PropertyGroup>
         <IsTestProject>false</IsTestProject>
     </PropertyGroup>
+    <ItemGroup>
+      <PackageReference Update="xunit" Version="2.7.0" />
+    </ItemGroup>
 </Project>
diff --git a/test/RestSharp.Tests/OptionsTests.cs b/test/RestSharp.Tests/OptionsTests.cs
index e1270a792..d6410345f 100644
--- a/test/RestSharp.Tests/OptionsTests.cs
+++ b/test/RestSharp.Tests/OptionsTests.cs
@@ -2,11 +2,11 @@ namespace RestSharp.Tests;
 
 public class OptionsTests {
     [Fact]
-    public void Ensure_follow_redirect() {
+    public void Ensure_no_httpclient_follow_redirect() {
         var value   = false;
         var options = new RestClientOptions { FollowRedirects = true, ConfigureMessageHandler = Configure};
         var _  = new RestClient(options);
-        value.Should().BeTrue();
+        value.Should().BeFalse();
 
         HttpMessageHandler Configure(HttpMessageHandler handler) {
             value = (handler as HttpClientHandler)!.AllowAutoRedirect;
diff --git a/test/RestSharp.Tests/RestSharp.Tests.csproj b/test/RestSharp.Tests/RestSharp.Tests.csproj
index eda460e5b..27f00528b 100644
--- a/test/RestSharp.Tests/RestSharp.Tests.csproj
+++ b/test/RestSharp.Tests/RestSharp.Tests.csproj
@@ -4,9 +4,17 @@
     <PackageReference Include="RichardSzalay.MockHttp" Version="6.0.0" />
     <PackageReference Include="System.Net.Http.Json" Version="7.0.1" />
   </ItemGroup>
+    <PropertyGroup>
+        <IsTestProject>true</IsTestProject>
+    </PropertyGroup>
   <ItemGroup>
     <ProjectReference Include="$(RepoRoot)\src\RestSharp\RestSharp.csproj" />
   </ItemGroup>
+  <ItemGroup Condition="'$(TargetFramework)' == 'net472'">
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Web" />
+    <PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="All" />
+  </ItemGroup>
   <ItemGroup>
     <None Update="SampleData\4sq.json" CopyToOutputDirectory="PreserveNewest" />
     <None Update="SampleData\bearertoken.json" CopyToOutputDirectory="PreserveNewest" />
@@ -27,4 +35,9 @@
     <None Update="SampleData\timespans.json" CopyToOutputDirectory="PreserveNewest" />
     <None Update="SampleData\underscore_prefix.json" CopyToOutputDirectory="PreserveNewest" />
   </ItemGroup>
+  <ItemGroup>
+    <PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.9.0" />
+    <PackageReference Update="xunit" Version="2.7.0" />
+    <PackageReference Update="xunit.runner.visualstudio" Version="2.5.7" />
+  </ItemGroup>
 </Project>
\ No newline at end of file