diff --git a/src/Microsoft.AspNetCore.Http.Abstractions/CookieBuilder.cs b/src/Microsoft.AspNetCore.Http.Abstractions/CookieBuilder.cs
new file mode 100644
index 0000000000..d2aa125ff3
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Http.Abstractions/CookieBuilder.cs
@@ -0,0 +1,93 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNetCore.Http
+{
+ ///
+ /// Defines settings used to create a cookie.
+ ///
+ public class CookieBuilder
+ {
+ ///
+ /// The name of the cookie.
+ ///
+ public virtual string Name { get; set; }
+
+ ///
+ /// The cookie path.
+ ///
+ ///
+ /// Determines the value that will set on .
+ ///
+ public virtual string Path { get; set; }
+
+ ///
+ /// The domain to associate the cookie with.
+ ///
+ ///
+ /// Determines the value that will set on .
+ ///
+ public virtual string Domain { get; set; }
+
+ ///
+ /// Indicates whether a cookie is accessible by client-side script.
+ ///
+ ///
+ /// Determines the value that will set on .
+ ///
+ public virtual bool HttpOnly { get; set; }
+
+ ///
+ /// The SameSite attribute of the cookie. The default value is
+ ///
+ ///
+ /// Determines the value that will set on .
+ ///
+ public virtual SameSiteMode SameSite { get; set; } = SameSiteMode.Lax;
+
+ ///
+ /// The policy that will be used to determine .
+ /// This is determined from the passed to .
+ ///
+ public virtual CookieSecurePolicy SecurePolicy { get; set; }
+
+
+ ///
+ /// Gets or sets the lifespan of a cookie.
+ ///
+ public virtual TimeSpan? Expiration { get; set; }
+
+ ///
+ /// Creates the cookie options from the given .
+ ///
+ /// The .
+ /// The cookie options.
+ public virtual CookieOptions Build(HttpContext context) => Build(context, DateTimeOffset.Now);
+
+ ///
+ /// Creates the cookie options from the given with an expiration based on and .
+ ///
+ /// The .
+ /// The time to use as the base for computing .
+ /// The cookie options.
+ public virtual CookieOptions Build(HttpContext context, DateTimeOffset expiresFrom)
+ {
+ if (context == null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ return new CookieOptions
+ {
+ Path = Path ?? "/",
+ SameSite = SameSite,
+ HttpOnly = HttpOnly,
+ Domain = Domain,
+ Secure = SecurePolicy == CookieSecurePolicy.Always || (SecurePolicy == CookieSecurePolicy.SameAsRequest && context.Request.IsHttps),
+ Expires = Expiration.HasValue ? expiresFrom.Add(Expiration.Value) : default(DateTimeOffset?)
+ };
+ }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.Http.Features/CookieOptions.cs b/src/Microsoft.AspNetCore.Http.Features/CookieOptions.cs
index d9e0047dca..017b6520fb 100644
--- a/src/Microsoft.AspNetCore.Http.Features/CookieOptions.cs
+++ b/src/Microsoft.AspNetCore.Http.Features/CookieOptions.cs
@@ -42,7 +42,6 @@ namespace Microsoft.AspNetCore.Http
/// true to transmit the cookie only over an SSL connection (HTTPS); otherwise, false.
public bool Secure { get; set; }
-
///
/// Gets or sets the value for the SameSite attribute of the cookie. The default value is
///
diff --git a/test/Microsoft.AspNetCore.Http.Abstractions.Tests/CookieBuilderTests.cs b/test/Microsoft.AspNetCore.Http.Abstractions.Tests/CookieBuilderTests.cs
new file mode 100644
index 0000000000..386374b211
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Http.Abstractions.Tests/CookieBuilderTests.cs
@@ -0,0 +1,47 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Http.Abstractions.Tests
+{
+ public class CookieBuilderTests
+ {
+ [Theory]
+ [InlineData(CookieSecurePolicy.Always, false, true)]
+ [InlineData(CookieSecurePolicy.Always, true, true)]
+ [InlineData(CookieSecurePolicy.SameAsRequest, true, true)]
+ [InlineData(CookieSecurePolicy.SameAsRequest, false, false)]
+ [InlineData(CookieSecurePolicy.None, true, false)]
+ [InlineData(CookieSecurePolicy.None, false, false)]
+ public void ConfiguresSecurePolicy(CookieSecurePolicy policy, bool requestIsHttps, bool secure)
+ {
+ var builder = new CookieBuilder
+ {
+ SecurePolicy = policy
+ };
+ var context = new DefaultHttpContext();
+ context.Request.IsHttps = requestIsHttps;
+ var options = builder.Build(context);
+
+ Assert.Equal(secure, options.Secure);
+ }
+
+ [Fact]
+ public void ComputesExpiration()
+ {
+ Assert.Null(new CookieBuilder().Build(new DefaultHttpContext()).Expires);
+
+ var now = DateTimeOffset.Now;
+ var options = new CookieBuilder { Expiration = TimeSpan.FromHours(1) }.Build(new DefaultHttpContext(), now);
+ Assert.Equal(now.AddHours(1), options.Expires);
+ }
+
+ [Fact]
+ public void CookieBuilderPreservesDefaultPath()
+ {
+ Assert.Equal(new CookieOptions().Path, new CookieBuilder().Build(new DefaultHttpContext()).Path);
+ }
+ }
+}