diff --git a/src/Microsoft.AspNetCore.WebUtilities/Base64UrlTextEncoder.cs b/src/Microsoft.AspNetCore.WebUtilities/Base64UrlTextEncoder.cs
new file mode 100644
index 0000000000..0402429878
--- /dev/null
+++ b/src/Microsoft.AspNetCore.WebUtilities/Base64UrlTextEncoder.cs
@@ -0,0 +1,42 @@
+// 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.WebUtilities
+{
+ public static class Base64UrlTextEncoder
+ {
+ ///
+ /// Encodes supplied data into Base64 and replaces any URL encodable characters into non-URL encodable
+ /// characters.
+ ///
+ /// Data to be encoded.
+ /// Base64 encoded string modified with non-URL encodable characters
+ public static string Encode(byte[] data)
+ {
+ return Convert.ToBase64String(data).TrimEnd('=').Replace('+', '-').Replace('/', '_');
+ }
+
+ ///
+ /// Decodes supplied string by replacing the non-URL encodable characters with URL encodable characters and
+ /// then decodes the Base64 string.
+ ///
+ /// The string to be decoded.
+ /// The decoded data.
+ public static byte[] Decode(string text)
+ {
+ return Convert.FromBase64String(Pad(text.Replace('-', '+').Replace('_', '/')));
+ }
+
+ private static string Pad(string text)
+ {
+ var padding = 3 - ((text.Length + 3) % 4);
+ if (padding == 0)
+ {
+ return text;
+ }
+ return text + new string('=', padding);
+ }
+ }
+}
diff --git a/test/Microsoft.AspNetCore.WebUtilities.Tests/Base64UrlTextEncoderTests.cs b/test/Microsoft.AspNetCore.WebUtilities.Tests/Base64UrlTextEncoderTests.cs
new file mode 100644
index 0000000000..2034ea33d7
--- /dev/null
+++ b/test/Microsoft.AspNetCore.WebUtilities.Tests/Base64UrlTextEncoderTests.cs
@@ -0,0 +1,30 @@
+// 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 Xunit;
+
+namespace Microsoft.AspNetCore.WebUtilities
+{
+ public class Base64UrlTextEncoderTests
+ {
+ [Fact]
+ public void DataOfVariousLengthRoundTripCorrectly()
+ {
+ for (int length = 0; length != 256; ++length)
+ {
+ var data = new byte[length];
+ for (int index = 0; index != length; ++index)
+ {
+ data[index] = (byte)(5 + length + (index * 23));
+ }
+ string text = Base64UrlTextEncoder.Encode(data);
+ byte[] result = Base64UrlTextEncoder.Decode(text);
+
+ for (int index = 0; index != length; ++index)
+ {
+ Assert.Equal(data[index], result[index]);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file