Просмотр исходного кода

Merge remote-tracking branch 'Security/rybrande/release21ToSrc' into rybrande/Mondo2.1

Ryan Brandenburg 7 лет назад
Родитель
Сommit
db7b28d475
100 измененных файлов с 8656 добавлено и 0 удалено
  1. 32 0
      src/Security/.gitignore
  2. 20 0
      src/Security/Directory.Build.props
  3. 7 0
      src/Security/Directory.Build.targets
  4. 13 0
      src/Security/NuGetPackageVerifier.json
  5. 17 0
      src/Security/README.md
  6. 556 0
      src/Security/Security.sln
  7. BIN
      src/Security/build/Key.snk
  8. 58 0
      src/Security/build/dependencies.props
  9. 18 0
      src/Security/build/repo.props
  10. 17 0
      src/Security/build/sources.props
  11. 18 0
      src/Security/samples/CookiePolicySample/CookiePolicySample.csproj
  12. 26 0
      src/Security/samples/CookiePolicySample/Program.cs
  13. 27 0
      src/Security/samples/CookiePolicySample/Properties/launchSettings.json
  14. 118 0
      src/Security/samples/CookiePolicySample/Startup.cs
  15. 20 0
      src/Security/samples/CookieSample/CookieSample.csproj
  16. 26 0
      src/Security/samples/CookieSample/Program.cs
  17. 27 0
      src/Security/samples/CookieSample/Properties/launchSettings.json
  18. 45 0
      src/Security/samples/CookieSample/Startup.cs
  19. 20 0
      src/Security/samples/CookieSessionSample/CookieSessionSample.csproj
  20. 55 0
      src/Security/samples/CookieSessionSample/MemoryCacheTicketStore.cs
  21. 26 0
      src/Security/samples/CookieSessionSample/Program.cs
  22. 27 0
      src/Security/samples/CookieSessionSample/Properties/launchSettings.json
  23. 54 0
      src/Security/samples/CookieSessionSample/Startup.cs
  24. 21 0
      src/Security/samples/JwtBearerSample/JwtBearerSample.csproj
  25. 21 0
      src/Security/samples/JwtBearerSample/Program.cs
  26. 27 0
      src/Security/samples/JwtBearerSample/Properties/launchSettings.json
  27. 111 0
      src/Security/samples/JwtBearerSample/Startup.cs
  28. 8 0
      src/Security/samples/JwtBearerSample/Todo.cs
  29. 28 0
      src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/app.js
  30. 13 0
      src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/homeCtrl.js
  31. 5 0
      src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/indexCtrl.js
  32. 71 0
      src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/todoListCtrl.js
  33. 24 0
      src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/todoListSvc.js
  34. 6 0
      src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/userDataCtrl.js
  35. 3 0
      src/Security/samples/JwtBearerSample/wwwroot/App/Views/Home.html
  36. 24 0
      src/Security/samples/JwtBearerSample/wwwroot/App/Views/TodoList.html
  37. 23 0
      src/Security/samples/JwtBearerSample/wwwroot/App/Views/UserData.html
  38. 68 0
      src/Security/samples/JwtBearerSample/wwwroot/index.html
  39. 97 0
      src/Security/samples/OpenIdConnect.AzureAdSample/AuthPropertiesTokenCache.cs
  40. 23 0
      src/Security/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.csproj
  41. 27 0
      src/Security/samples/OpenIdConnect.AzureAdSample/Program.cs
  42. 27 0
      src/Security/samples/OpenIdConnect.AzureAdSample/Properties/launchSettings.json
  43. 20 0
      src/Security/samples/OpenIdConnect.AzureAdSample/Readme.md
  44. 203 0
      src/Security/samples/OpenIdConnect.AzureAdSample/Startup.cs
  45. 33 0
      src/Security/samples/OpenIdConnectSample/OpenIdConnectSample.csproj
  46. 59 0
      src/Security/samples/OpenIdConnectSample/Program.cs
  47. 28 0
      src/Security/samples/OpenIdConnectSample/Properties/launchSettings.json
  48. 44 0
      src/Security/samples/OpenIdConnectSample/Readme.md
  49. 297 0
      src/Security/samples/OpenIdConnectSample/Startup.cs
  50. BIN
      src/Security/samples/OpenIdConnectSample/compiler/resources/cert.pfx
  51. 57 0
      src/Security/samples/SocialSample/Program.cs
  52. 28 0
      src/Security/samples/SocialSample/Properties/launchSettings.json
  53. 36 0
      src/Security/samples/SocialSample/SocialSample.csproj
  54. 502 0
      src/Security/samples/SocialSample/Startup.cs
  55. BIN
      src/Security/samples/SocialSample/compiler/resources/cert.pfx
  56. 9 0
      src/Security/samples/SocialSample/web.config
  57. 64 0
      src/Security/samples/WsFedSample/Program.cs
  58. 28 0
      src/Security/samples/WsFedSample/Properties/launchSettings.json
  59. 168 0
      src/Security/samples/WsFedSample/Startup.cs
  60. 27 0
      src/Security/samples/WsFedSample/WsFedSample.csproj
  61. BIN
      src/Security/samples/WsFedSample/compiler/resources/cert.pfx
  62. 309 0
      src/Security/shared/Microsoft.AspNetCore.ChunkingCookieManager.Sources/ChunkingCookieManager.cs
  63. 7 0
      src/Security/src/Directory.Build.props
  64. 13 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Constants.cs
  65. 37 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAppBuilderExtensions.cs
  66. 46 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationDefaults.cs
  67. 451 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationHandler.cs
  68. 214 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationOptions.cs
  69. 32 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/CookieExtensions.cs
  70. 158 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieAuthenticationEvents.cs
  71. 33 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSignedInContext.cs
  72. 42 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningInContext.cs
  73. 36 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningOutContext.cs
  74. 51 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieValidatePrincipalContext.cs
  75. 39 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/ICookieManager.cs
  76. 43 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/ITicketStore.cs
  77. 35 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/LoggingExtensions.cs
  78. 20 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.csproj
  79. 59 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/PostConfigureCookieAuthenticationOptions.cs
  80. 1621 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/baseline.netcore.json
  81. 37 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookAppBuilderExtensions.cs
  82. 18 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookDefaults.cs
  83. 24 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookExtensions.cs
  84. 80 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookHandler.cs
  85. 102 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookOptions.cs
  86. 15 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.csproj
  87. 44 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/Properties/Resources.Designer.cs
  88. 123 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/Resources.resx
  89. 390 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/baseline.netcore.json
  90. 37 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleAppBuilderExtensions.cs
  91. 89 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleChallengeProperties.cs
  92. 21 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleDefaults.cs
  93. 24 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleExtensions.cs
  94. 108 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleHandler.cs
  95. 50 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleHelper.cs
  96. 42 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleOptions.cs
  97. 15 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.csproj
  98. 58 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Google/Properties/Resources.Designer.cs
  99. 126 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Google/Resources.resx
  100. 550 0
      src/Security/src/Microsoft.AspNetCore.Authentication.Google/baseline.netcore.json

+ 32 - 0
src/Security/.gitignore

@@ -0,0 +1,32 @@
+[Oo]bj/
+[Bb]in/
+TestResults/
+.nuget/
+_ReSharper.*/
+packages/
+artifacts/
+PublishProfiles/
+*.user
+*.suo
+*.cache
+*.docstates
+_ReSharper.*
+nuget.exe
+*net45.csproj
+*net451.csproj
+*k10.csproj
+*.psess
+*.vsp
+*.pidb
+*.userprefs
+*DS_Store
+*.ncrunchsolution
+*.*sdf
+*.ipch
+*.sln.ide
+project.lock.json
+.build/
+.testPublish/
+/.vs/
+.vscode/
+global.json

+ 20 - 0
src/Security/Directory.Build.props

@@ -0,0 +1,20 @@
+<Project>
+  <Import
+    Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))\AspNetCoreSettings.props"
+    Condition=" '$(CI)' != 'true' AND '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), AspNetCoreSettings.props))' != '' " />
+
+  <Import Project="version.props" />
+  <Import Project="build\dependencies.props" />
+  <Import Project="build\sources.props" />
+
+  <PropertyGroup>
+    <Product>Microsoft ASP.NET Core</Product>
+    <RepositoryUrl>https://github.com/aspnet/Security</RepositoryUrl>
+    <RepositoryType>git</RepositoryType>
+    <RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>
+    <AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)build\Key.snk</AssemblyOriginatorKeyFile>
+    <SignAssembly>true</SignAssembly>
+    <PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+  </PropertyGroup>
+</Project>

+ 7 - 0
src/Security/Directory.Build.targets

@@ -0,0 +1,7 @@
+<Project>
+  <PropertyGroup>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">$(MicrosoftNETCoreApp20PackageVersion)</RuntimeFrameworkVersion>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">$(MicrosoftNETCoreApp21PackageVersion)</RuntimeFrameworkVersion>
+    <NETStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard2.0' ">$(NETStandardLibrary20PackageVersion)</NETStandardImplicitPackageVersion>
+  </PropertyGroup>
+</Project>

+ 13 - 0
src/Security/NuGetPackageVerifier.json

@@ -0,0 +1,13 @@
+{
+  "adx-nonshipping": {
+    "rules": [],
+    "packages": {
+      "Microsoft.AspNetCore.ChunkingCookieManager.Sources": {}
+    }
+  },
+  "Default": {
+    "rules": [
+      "DefaultCompositeRule"
+    ]
+  }
+}

+ 17 - 0
src/Security/README.md

@@ -0,0 +1,17 @@
+ASP.NET Security
+========
+
+AppVeyor: [![AppVeyor](https://ci.appveyor.com/api/projects/status/fujhh8n956v5ohfd/branch/dev?svg=true)](https://ci.appveyor.com/project/aspnetci/Security/branch/dev)
+
+Travis:   [![Travis](https://travis-ci.org/aspnet/Security.svg?branch=dev)](https://travis-ci.org/aspnet/Security)
+
+Contains the security and authorization middlewares for ASP.NET Core.
+
+A list of community projects related to authentication and security for ASP.NET Core are listed in the [documentation](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/community).
+
+### Notes
+
+ASP.NET Security will not include Basic Authentication middleware due to its potential insecurity and performance problems. If you host under IIS you can enable it via IIS configuration.
+
+
+This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo.

+ 556 - 0
src/Security/Security.sln

@@ -0,0 +1,556 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27130.2027
+MinimumVisualStudioVersion = 15.0.26730.03
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4D2B6A51-2F9F-44F5-8131-EA5CAC053652}"
+	ProjectSection(SolutionItems) = preProject
+		src\Directory.Build.props = src\Directory.Build.props
+	EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CookieSample", "samples\CookieSample\CookieSample.csproj", "{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{7BF11F3A-60B6-4796-B504-579C67FFBA34}"
+	ProjectSection(SolutionItems) = preProject
+		test\Directory.Build.props = test\Directory.Build.props
+	EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SocialSample", "samples\SocialSample\SocialSample.csproj", "{8C73D216-332D-41D8-BFD0-45BC4BC36552}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CookieSessionSample", "samples\CookieSessionSample\CookieSessionSample.csproj", "{19711880-46DA-4A26-9E0F-9B2E41D27651}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIdConnectSample", "samples\OpenIdConnectSample\OpenIdConnectSample.csproj", "{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Cookies", "src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj", "{FC152CC4-054B-457E-8D91-389C5DE3C561}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication", "src\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj", "{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Facebook", "src\Microsoft.AspNetCore.Authentication.Facebook\Microsoft.AspNetCore.Authentication.Facebook.csproj", "{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Google", "src\Microsoft.AspNetCore.Authentication.Google\Microsoft.AspNetCore.Authentication.Google.csproj", "{76579C39-B829-490D-B8BE-1BD35FE8412E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.OpenIdConnect", "src\Microsoft.AspNetCore.Authentication.OpenIdConnect\Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj", "{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.MicrosoftAccount", "src\Microsoft.AspNetCore.Authentication.MicrosoftAccount\Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj", "{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Twitter", "src\Microsoft.AspNetCore.Authentication.Twitter\Microsoft.AspNetCore.Authentication.Twitter.csproj", "{0330FFF6-B4B5-42DD-8C99-26A789569000}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.OAuth", "src\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj", "{1657C79E-7755-4AEE-9D61-571295B69A30}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.Test", "test\Microsoft.AspNetCore.Authentication.Test\Microsoft.AspNetCore.Authentication.Test.csproj", "{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization.Test", "test\Microsoft.AspNetCore.Authorization.Test\Microsoft.AspNetCore.Authorization.Test.csproj", "{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization", "src\Microsoft.AspNetCore.Authorization\Microsoft.AspNetCore.Authorization.csproj", "{6AB3E514-5894-4131-9399-DC7D5284ADDB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.CookiePolicy", "src\Microsoft.AspNetCore.CookiePolicy\Microsoft.AspNetCore.CookiePolicy.csproj", "{86183DC3-02A8-4A68-8B60-71ECEC066E79}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.CookiePolicy.Test", "test\Microsoft.AspNetCore.CookiePolicy.Test\Microsoft.AspNetCore.CookiePolicy.Test.csproj", "{1790E052-646F-4529-B90E-6FEA95520D69}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.JwtBearer", "src\Microsoft.AspNetCore.Authentication.JwtBearer\Microsoft.AspNetCore.Authentication.JwtBearer.csproj", "{2755BFE5-7421-4A31-A644-F817DF5CAA98}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtBearerSample", "samples\JwtBearerSample\JwtBearerSample.csproj", "{D399B84F-591B-4E98-92BA-B0F63E7B6957}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Owin.Security.Interop", "src\Microsoft.Owin.Security.Interop\Microsoft.Owin.Security.Interop.csproj", "{A7922DD8-09F1-43E4-938B-CC523EA08898}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Owin.Security.Interop.Test", "test\Microsoft.Owin.Security.Interop.Test\Microsoft.Owin.Security.Interop.Test.csproj", "{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenIdConnect.AzureAdSample", "samples\OpenIdConnect.AzureAdSample\OpenIdConnect.AzureAdSample.csproj", "{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test", "test\Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test\Microsoft.AspNetCore.ChunkingCookieManager.Sources.Test.csproj", "{51563775-C659-4907-9BAF-9995BAB87D01}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{86BD08B1-F978-4F58-9982-2A017807F01C}"
+	ProjectSection(SolutionItems) = preProject
+		build\dependencies.props = build\dependencies.props
+		Directory.Build.props = Directory.Build.props
+		Directory.Build.targets = Directory.Build.targets
+		build\Key.snk = build\Key.snk
+		NuGet.config = NuGet.config
+		build\repo.props = build\repo.props
+		build\sources.props = build\sources.props
+	EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization.Policy", "src\Microsoft.AspNetCore.Authorization.Policy\Microsoft.AspNetCore.Authorization.Policy.csproj", "{58194599-F07D-47A3-9DF2-E21A22C5EF9E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CookiePolicySample", "samples\CookiePolicySample\CookiePolicySample.csproj", "{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.WsFederation", "src\Microsoft.AspNetCore.Authentication.WsFederation\Microsoft.AspNetCore.Authentication.WsFederation.csproj", "{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WsFedSample", "samples\WsFedSample\WsFedSample.csproj", "{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|Mixed Platforms = Debug|Mixed Platforms
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|Mixed Platforms = Release|Mixed Platforms
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|x64.Build.0 = Debug|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Any CPU.Build.0 = Release|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|x64.ActiveCfg = Release|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|x64.Build.0 = Release|Any CPU
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714}.Release|x86.ActiveCfg = Release|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|x64.Build.0 = Debug|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|x64.ActiveCfg = Release|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|x64.Build.0 = Release|Any CPU
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552}.Release|x86.ActiveCfg = Release|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|x64.Build.0 = Debug|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Any CPU.Build.0 = Release|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|x64.ActiveCfg = Release|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|x64.Build.0 = Release|Any CPU
+		{19711880-46DA-4A26-9E0F-9B2E41D27651}.Release|x86.ActiveCfg = Release|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|x64.Build.0 = Debug|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Debug|x86.Build.0 = Debug|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|x64.ActiveCfg = Release|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|x64.Build.0 = Release|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|x86.ActiveCfg = Release|Any CPU
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B}.Release|x86.Build.0 = Release|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|x64.Build.0 = Debug|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Debug|x86.Build.0 = Debug|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|x64.ActiveCfg = Release|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|x64.Build.0 = Release|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|x86.ActiveCfg = Release|Any CPU
+		{FC152CC4-054B-457E-8D91-389C5DE3C561}.Release|x86.Build.0 = Release|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|x64.Build.0 = Debug|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Debug|x86.Build.0 = Debug|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|x64.ActiveCfg = Release|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|x64.Build.0 = Release|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|x86.ActiveCfg = Release|Any CPU
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB}.Release|x86.Build.0 = Release|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|x64.Build.0 = Debug|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Debug|x86.Build.0 = Debug|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|x64.ActiveCfg = Release|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|x64.Build.0 = Release|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|x86.ActiveCfg = Release|Any CPU
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A}.Release|x86.Build.0 = Release|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|x64.Build.0 = Debug|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Debug|x86.Build.0 = Debug|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|x64.ActiveCfg = Release|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|x64.Build.0 = Release|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|x86.ActiveCfg = Release|Any CPU
+		{76579C39-B829-490D-B8BE-1BD35FE8412E}.Release|x86.Build.0 = Release|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|x64.Build.0 = Debug|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Debug|x86.Build.0 = Debug|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|x64.ActiveCfg = Release|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|x64.Build.0 = Release|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|x86.ActiveCfg = Release|Any CPU
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A}.Release|x86.Build.0 = Release|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|x64.Build.0 = Debug|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Debug|x86.Build.0 = Debug|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|x64.ActiveCfg = Release|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|x64.Build.0 = Release|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|x86.ActiveCfg = Release|Any CPU
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE}.Release|x86.Build.0 = Release|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|x64.Build.0 = Debug|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Debug|x86.Build.0 = Debug|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|x64.ActiveCfg = Release|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|x64.Build.0 = Release|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|x86.ActiveCfg = Release|Any CPU
+		{0330FFF6-B4B5-42DD-8C99-26A789569000}.Release|x86.Build.0 = Release|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|x64.Build.0 = Debug|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Debug|x86.Build.0 = Debug|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|x64.ActiveCfg = Release|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|x64.Build.0 = Release|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|x86.ActiveCfg = Release|Any CPU
+		{1657C79E-7755-4AEE-9D61-571295B69A30}.Release|x86.Build.0 = Release|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|x64.Build.0 = Debug|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Debug|x86.Build.0 = Debug|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|x64.ActiveCfg = Release|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|x64.Build.0 = Release|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|x86.ActiveCfg = Release|Any CPU
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B}.Release|x86.Build.0 = Release|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|x64.Build.0 = Debug|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Debug|x86.Build.0 = Debug|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|x64.ActiveCfg = Release|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|x64.Build.0 = Release|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|x86.ActiveCfg = Release|Any CPU
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2}.Release|x86.Build.0 = Release|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|x64.Build.0 = Debug|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Debug|x86.Build.0 = Debug|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x64.ActiveCfg = Release|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x64.Build.0 = Release|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x86.ActiveCfg = Release|Any CPU
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x86.Build.0 = Release|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x64.Build.0 = Debug|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x86.Build.0 = Debug|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Any CPU.Build.0 = Release|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x64.ActiveCfg = Release|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x64.Build.0 = Release|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x86.ActiveCfg = Release|Any CPU
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x86.Build.0 = Release|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x64.Build.0 = Debug|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x86.Build.0 = Debug|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Release|x64.ActiveCfg = Release|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Release|x64.Build.0 = Release|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Release|x86.ActiveCfg = Release|Any CPU
+		{1790E052-646F-4529-B90E-6FEA95520D69}.Release|x86.Build.0 = Release|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|x64.Build.0 = Debug|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Debug|x86.Build.0 = Debug|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x64.ActiveCfg = Release|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x64.Build.0 = Release|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x86.ActiveCfg = Release|Any CPU
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98}.Release|x86.Build.0 = Release|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|x64.Build.0 = Debug|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Debug|x86.Build.0 = Debug|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x64.ActiveCfg = Release|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x64.Build.0 = Release|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x86.ActiveCfg = Release|Any CPU
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957}.Release|x86.Build.0 = Release|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x64.Build.0 = Debug|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Debug|x86.Build.0 = Debug|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x64.ActiveCfg = Release|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x64.Build.0 = Release|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x86.ActiveCfg = Release|Any CPU
+		{A7922DD8-09F1-43E4-938B-CC523EA08898}.Release|x86.Build.0 = Release|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x64.Build.0 = Debug|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Debug|x86.Build.0 = Debug|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x64.ActiveCfg = Release|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x64.Build.0 = Release|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x86.ActiveCfg = Release|Any CPU
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24}.Release|x86.Build.0 = Release|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|x64.Build.0 = Debug|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Debug|x86.Build.0 = Debug|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|x64.ActiveCfg = Release|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|x64.Build.0 = Release|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|x86.ActiveCfg = Release|Any CPU
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E}.Release|x86.Build.0 = Release|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|x64.Build.0 = Debug|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Debug|x86.Build.0 = Debug|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Release|Any CPU.Build.0 = Release|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Release|x64.ActiveCfg = Release|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Release|x64.Build.0 = Release|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Release|x86.ActiveCfg = Release|Any CPU
+		{51563775-C659-4907-9BAF-9995BAB87D01}.Release|x86.Build.0 = Release|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x64.Build.0 = Debug|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Debug|x86.Build.0 = Debug|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x64.ActiveCfg = Release|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x64.Build.0 = Release|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x86.ActiveCfg = Release|Any CPU
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E}.Release|x86.Build.0 = Release|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|x64.Build.0 = Debug|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Debug|x86.Build.0 = Debug|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|x64.ActiveCfg = Release|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|x64.Build.0 = Release|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|x86.ActiveCfg = Release|Any CPU
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E}.Release|x86.Build.0 = Release|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|x64.Build.0 = Debug|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Debug|x86.Build.0 = Debug|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|x64.ActiveCfg = Release|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|x64.Build.0 = Release|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|x86.ActiveCfg = Release|Any CPU
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29}.Release|x86.Build.0 = Release|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|x64.Build.0 = Debug|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Debug|x86.Build.0 = Debug|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|x64.ActiveCfg = Release|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|x64.Build.0 = Release|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|x86.ActiveCfg = Release|Any CPU
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{558C2C2A-AED8-49DE-BB60-D5F8AE06C714} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
+		{8C73D216-332D-41D8-BFD0-45BC4BC36552} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
+		{19711880-46DA-4A26-9E0F-9B2E41D27651} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
+		{BEF0F5C3-EF4E-4649-9C49-D5E279A3CA2B} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
+		{FC152CC4-054B-457E-8D91-389C5DE3C561} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{BC0D4B56-1A5B-4D88-AFBF-68C0F2D545FB} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{EEAAEE68-607B-4E33-AF3E-45C66B4DBA5A} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{76579C39-B829-490D-B8BE-1BD35FE8412E} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{35115D55-B69E-46D4-BB33-C9E9E6EC5E7A} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{ACB45E19-F520-4D0C-8916-B0CEB9C017FE} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{0330FFF6-B4B5-42DD-8C99-26A789569000} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{1657C79E-7755-4AEE-9D61-571295B69A30} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{8DA26CD1-1302-4CFD-9270-9FA1B7C6138B} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
+		{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
+		{6AB3E514-5894-4131-9399-DC7D5284ADDB} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{86183DC3-02A8-4A68-8B60-71ECEC066E79} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{1790E052-646F-4529-B90E-6FEA95520D69} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
+		{2755BFE5-7421-4A31-A644-F817DF5CAA98} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{D399B84F-591B-4E98-92BA-B0F63E7B6957} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
+		{A7922DD8-09F1-43E4-938B-CC523EA08898} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{A2B5DC39-68D5-4145-A8CC-6AEAB7D33A24} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
+		{3A7AD414-EBDE-4F92-B307-4E8F19B6117E} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
+		{51563775-C659-4907-9BAF-9995BAB87D01} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
+		{58194599-F07D-47A3-9DF2-E21A22C5EF9E} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{24A28F5D-E5A9-4CA8-B0D2-924A1F8BE14E} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
+		{B1FC6AAF-9BF2-4CDA-84A2-AA8BF7603F29} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
+		{5EC2E398-E46A-430D-8E4B-E91C8FC3E800} = {F8C0AA27-F3FB-4286-8E4C-47EF86B539FF}
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {ABF8089E-43D0-4010-84A7-7A9DCFE49357}
+	EndGlobalSection
+EndGlobal

BIN
src/Security/build/Key.snk


+ 58 - 0
src/Security/build/dependencies.props

@@ -0,0 +1,58 @@
+<Project>
+  <PropertyGroup>
+    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+  </PropertyGroup>
+
+  <!-- These package versions may be overridden or updated by automation. -->
+  <PropertyGroup Label="Package Versions: Auto">
+    <InternalAspNetCoreSdkPackageVersion>2.1.3-rtm-15802</InternalAspNetCoreSdkPackageVersion>
+    <MicrosoftIdentityModelClientsActiveDirectoryPackageVersion>3.14.2</MicrosoftIdentityModelClientsActiveDirectoryPackageVersion>
+    <MicrosoftIdentityModelProtocolsOpenIdConnectPackageVersion>5.2.0</MicrosoftIdentityModelProtocolsOpenIdConnectPackageVersion>
+    <MicrosoftIdentityModelProtocolsWsFederationPackageVersion>5.2.0</MicrosoftIdentityModelProtocolsWsFederationPackageVersion>
+    <MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
+    <MicrosoftNETCoreApp21PackageVersion>2.1.2</MicrosoftNETCoreApp21PackageVersion>
+    <MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
+    <MicrosoftOwinSecurityCookiesPackageVersion>3.0.1</MicrosoftOwinSecurityCookiesPackageVersion>
+    <MicrosoftOwinSecurityPackageVersion>3.0.1</MicrosoftOwinSecurityPackageVersion>
+    <MicrosoftOwinTestingPackageVersion>3.0.1</MicrosoftOwinTestingPackageVersion>
+    <NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
+    <NewtonsoftJsonPackageVersion>11.0.2</NewtonsoftJsonPackageVersion>
+    <SystemIdentityModelTokensJwtPackageVersion>5.2.0</SystemIdentityModelTokensJwtPackageVersion>
+    <XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
+    <XunitPackageVersion>2.3.1</XunitPackageVersion>
+    <XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>
+  </PropertyGroup>
+
+  <!-- This may import a generated file which may override the variables above. -->
+  <Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " />
+
+  <!-- These are package versions that should not be overridden or updated by automation. -->
+  <PropertyGroup Label="Package Versions: Pinned">
+    <MicrosoftAspNetCoreAuthenticationAbstractionsPackageVersion>2.1.1</MicrosoftAspNetCoreAuthenticationAbstractionsPackageVersion>
+    <MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.1.1</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
+    <MicrosoftAspNetCoreDataProtectionExtensionsPackageVersion>2.1.1</MicrosoftAspNetCoreDataProtectionExtensionsPackageVersion>
+    <MicrosoftAspNetCoreDataProtectionPackageVersion>2.1.1</MicrosoftAspNetCoreDataProtectionPackageVersion>
+    <MicrosoftAspNetCoreDiagnosticsPackageVersion>2.1.1</MicrosoftAspNetCoreDiagnosticsPackageVersion>
+    <MicrosoftAspNetCoreHostingPackageVersion>2.1.1</MicrosoftAspNetCoreHostingPackageVersion>
+    <MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.1.1</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
+    <MicrosoftAspNetCoreHttpPackageVersion>2.1.1</MicrosoftAspNetCoreHttpPackageVersion>
+    <MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.1.1</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
+    <MicrosoftAspNetCoreServerKestrelHttpsPackageVersion>2.1.2</MicrosoftAspNetCoreServerKestrelHttpsPackageVersion>
+    <MicrosoftAspNetCoreServerKestrelPackageVersion>2.1.2</MicrosoftAspNetCoreServerKestrelPackageVersion>
+    <MicrosoftAspNetCoreStaticFilesPackageVersion>2.1.1</MicrosoftAspNetCoreStaticFilesPackageVersion>
+    <MicrosoftAspNetCoreTestHostPackageVersion>2.1.1</MicrosoftAspNetCoreTestHostPackageVersion>
+    <MicrosoftAspNetCoreTestingPackageVersion>2.1.0</MicrosoftAspNetCoreTestingPackageVersion>
+    <MicrosoftExtensionsCachingMemoryPackageVersion>2.1.1</MicrosoftExtensionsCachingMemoryPackageVersion>
+    <MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.1.1</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
+    <MicrosoftExtensionsConfigurationUserSecretsPackageVersion>2.1.1</MicrosoftExtensionsConfigurationUserSecretsPackageVersion>
+    <MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.1</MicrosoftExtensionsDependencyInjectionPackageVersion>
+    <MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>2.1.1</MicrosoftExtensionsFileProvidersEmbeddedPackageVersion>
+    <MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.1</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
+    <MicrosoftExtensionsLoggingConsolePackageVersion>2.1.1</MicrosoftExtensionsLoggingConsolePackageVersion>
+    <MicrosoftExtensionsLoggingDebugPackageVersion>2.1.1</MicrosoftExtensionsLoggingDebugPackageVersion>
+    <MicrosoftExtensionsLoggingPackageVersion>2.1.1</MicrosoftExtensionsLoggingPackageVersion>
+    <MicrosoftExtensionsOptionsPackageVersion>2.1.1</MicrosoftExtensionsOptionsPackageVersion>
+    <MicrosoftExtensionsSecurityHelperSourcesPackageVersion>2.1.1</MicrosoftExtensionsSecurityHelperSourcesPackageVersion>
+    <MicrosoftExtensionsWebEncodersPackageVersion>2.1.1</MicrosoftExtensionsWebEncodersPackageVersion>
+  </PropertyGroup>
+</Project>

+ 18 - 0
src/Security/build/repo.props

@@ -0,0 +1,18 @@
+<Project>
+  <Import Project="dependencies.props" />
+
+  <ItemGroup>
+    <ExcludeFromTest Include="$(RepositoryRoot)test\Microsoft.Owin.Security.Interop.Test\*.csproj" Condition="'$(OS)' != 'Windows_NT'" />
+  </ItemGroup>
+  <PropertyGroup>
+    <!-- These properties are use by the automation that updates dependencies.props -->
+    <LineupPackageId>Internal.AspNetCore.Universe.Lineup</LineupPackageId>
+    <LineupPackageVersion>2.1.0-rc1-*</LineupPackageVersion>
+    <LineupPackageRestoreSource>https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json</LineupPackageRestoreSource>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <DotNetCoreRuntime Include="$(MicrosoftNETCoreApp20PackageVersion)" />
+    <DotNetCoreRuntime Include="$(MicrosoftNETCoreApp21PackageVersion)" />
+  </ItemGroup>
+</Project>

+ 17 - 0
src/Security/build/sources.props

@@ -0,0 +1,17 @@
+<Project>
+  <Import Project="$(DotNetRestoreSourcePropsPath)" Condition="'$(DotNetRestoreSourcePropsPath)' != ''"/>
+
+  <PropertyGroup Label="RestoreSources">
+    <RestoreSources>$(DotNetRestoreSources)</RestoreSources>
+    <RestoreSources Condition="'$(DotNetBuildOffline)' != 'true' AND '$(AspNetUniverseBuildOffline)' != 'true' ">
+      $(RestoreSources);
+      https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
+      https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
+      https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;
+    </RestoreSources>
+    <RestoreSources Condition="'$(DotNetBuildOffline)' != 'true'">
+      $(RestoreSources);
+      https://api.nuget.org/v3/index.json;
+    </RestoreSources>
+  </PropertyGroup>
+</Project>

+ 18 - 0
src/Security/samples/CookiePolicySample/CookiePolicySample.csproj

@@ -0,0 +1,18 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.CookiePolicy\Microsoft.AspNetCore.CookiePolicy.csproj" />
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
+  </ItemGroup>
+
+</Project>

+ 26 - 0
src/Security/samples/CookiePolicySample/Program.cs

@@ -0,0 +1,26 @@
+using System.IO;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace CookiePolicySample
+{
+    public static class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .ConfigureLogging(factory =>
+                {
+                    factory.AddConsole();
+                    factory.AddFilter("Microsoft", LogLevel.Trace);
+                })
+                .UseKestrel()
+                .UseContentRoot(Directory.GetCurrentDirectory())
+                .UseIISIntegration()
+                .UseStartup<Startup>()
+                .Build();
+
+            host.Run();
+        }
+    }
+}

+ 27 - 0
src/Security/samples/CookiePolicySample/Properties/launchSettings.json

@@ -0,0 +1,27 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:1788/",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "CookieSample": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "applicationUrl": "http://localhost:12345",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 118 - 0
src/Security/samples/CookiePolicySample/Startup.cs

@@ -0,0 +1,118 @@
+using System;
+using System.Linq;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Net.Http.Headers;
+
+namespace CookiePolicySample
+{
+    public class Startup
+    {
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
+                .AddCookie();
+            services.Configure<CookiePolicyOptions>(options =>
+            {
+                options.CheckConsentNeeded = context => context.Request.PathBase.Equals("/NeedsConsent");
+
+                options.OnAppendCookie = context => { };
+            });
+        }
+
+        public void Configure(IApplicationBuilder app)
+        {
+            app.UseCookiePolicy();
+            app.UseAuthentication();
+
+            app.Map("/NeedsConsent", NestedApp);
+            app.Map("/NeedsNoConsent", NestedApp);
+            NestedApp(app);
+        }
+
+        private void NestedApp(IApplicationBuilder app)
+        {
+            app.Run(async context =>
+            {
+                var path = context.Request.Path;
+                switch (path)
+                {
+                    case "/Login":
+                        var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "bob") },
+                            CookieAuthenticationDefaults.AuthenticationScheme));
+                        await context.SignInAsync(user);
+                        break;
+                    case "/Logout":
+                        await context.SignOutAsync();
+                        break;
+                    case "/CreateTempCookie":
+                        context.Response.Cookies.Append("Temp", "1");
+                        break;
+                    case "/RemoveTempCookie":
+                        context.Response.Cookies.Delete("Temp");
+                        break;
+                    case "/GrantConsent":
+                        context.Features.Get<ITrackingConsentFeature>().GrantConsent();
+                        break;
+                    case "/WithdrawConsent":
+                        context.Features.Get<ITrackingConsentFeature>().WithdrawConsent();
+                        break;
+                }
+
+                // TODO: Debug log when cookie is suppressed
+
+                await HomePage(context);
+            });
+        }
+
+        private async Task HomePage(HttpContext context)
+        {
+            var response = context.Response;
+            var cookies = context.Request.Cookies;
+            response.ContentType = "text/html";
+            await response.WriteAsync("<html><body>\r\n");
+
+            await response.WriteAsync($"<a href=\"{context.Request.PathBase}/\">Home</a><br>\r\n");
+            await response.WriteAsync($"<a href=\"{context.Request.PathBase}/Login\">Login</a><br>\r\n");
+            await response.WriteAsync($"<a href=\"{context.Request.PathBase}/Logout\">Logout</a><br>\r\n");
+            await response.WriteAsync($"<a href=\"{context.Request.PathBase}/CreateTempCookie\">Create Temp Cookie</a><br>\r\n");
+            await response.WriteAsync($"<a href=\"{context.Request.PathBase}/RemoveTempCookie\">Remove Temp Cookie</a><br>\r\n");
+            await response.WriteAsync($"<a href=\"{context.Request.PathBase}/GrantConsent\">Grant Consent</a><br>\r\n");
+            await response.WriteAsync($"<a href=\"{context.Request.PathBase}/WithdrawConsent\">Withdraw Consent</a><br>\r\n");
+            await response.WriteAsync("<br>\r\n");
+            await response.WriteAsync($"<a href=\"/NeedsConsent{context.Request.Path}\">Needs Consent</a><br>\r\n");
+            await response.WriteAsync($"<a href=\"/NeedsNoConsent{context.Request.Path}\">Needs No Consent</a><br>\r\n");
+            await response.WriteAsync("<br>\r\n");
+
+            var feature = context.Features.Get<ITrackingConsentFeature>();
+            await response.WriteAsync($"Consent: <br>\r\n");
+            await response.WriteAsync($" - IsNeeded: {feature.IsConsentNeeded} <br>\r\n");
+            await response.WriteAsync($" - Has: {feature.HasConsent} <br>\r\n");
+            await response.WriteAsync($" - Can Track: {feature.CanTrack} <br>\r\n");
+            await response.WriteAsync("<br>\r\n");
+
+            await response.WriteAsync($"{cookies.Count} Request Cookies:<br>\r\n");
+            foreach (var cookie in cookies)
+            {
+                await response.WriteAsync($" - {cookie.Key} = {cookie.Value} <br>\r\n");
+            }
+            await response.WriteAsync("<br>\r\n");
+
+            var responseCookies = response.Headers[HeaderNames.SetCookie];
+            await response.WriteAsync($"{responseCookies.Count} Response Cookies:<br>\r\n");
+            foreach (var cookie in responseCookies)
+            {
+                await response.WriteAsync($" - {cookie} <br>\r\n");
+            }          
+
+            await response.WriteAsync("</body></html>");
+        }
+    }
+}

+ 20 - 0
src/Security/samples/CookieSample/CookieSample.csproj

@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.DataProtection" Version="$(MicrosoftAspNetCoreDataProtectionPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
+  </ItemGroup>
+
+</Project>

+ 26 - 0
src/Security/samples/CookieSample/Program.cs

@@ -0,0 +1,26 @@
+using System.IO;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace CookieSample
+{
+    public static class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .ConfigureLogging(factory =>
+                {
+                    factory.AddConsole();
+                    factory.AddFilter("Console", level => level >= LogLevel.Information);
+                })
+                .UseKestrel()
+                .UseContentRoot(Directory.GetCurrentDirectory())
+                .UseIISIntegration()
+                .UseStartup<Startup>()
+                .Build();
+
+            host.Run();
+        }
+    }
+}

+ 27 - 0
src/Security/samples/CookieSample/Properties/launchSettings.json

@@ -0,0 +1,27 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:1788/",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "CookieSample": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "applicationUrl": "http://localhost:12345",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 45 - 0
src/Security/samples/CookieSample/Startup.cs

@@ -0,0 +1,45 @@
+using System.Linq;
+using System.Security.Claims;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace CookieSample
+{
+    public class Startup
+    {
+        public void ConfigureServices(IServiceCollection services)
+        {
+            // This can be removed after https://github.com/aspnet/IISIntegration/issues/371
+            services.AddAuthentication(options =>
+            {
+                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+            }).AddCookie();
+        }
+
+        public void Configure(IApplicationBuilder app)
+        {
+            app.UseAuthentication();
+
+            app.Run(async context =>
+            {
+                if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
+                {
+                    var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "bob") }, CookieAuthenticationDefaults.AuthenticationScheme));
+                    await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);
+
+                    context.Response.ContentType = "text/plain";
+                    await context.Response.WriteAsync("Hello First timer");
+                    return;
+                }
+
+                context.Response.ContentType = "text/plain";
+                await context.Response.WriteAsync("Hello old timer");
+            });
+        }
+    }
+}

+ 20 - 0
src/Security/samples/CookieSessionSample/CookieSessionSample.csproj

@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.DataProtection" Version="$(MicrosoftAspNetCoreDataProtectionPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftExtensionsCachingMemoryPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
+  </ItemGroup>
+
+</Project>

+ 55 - 0
src/Security/samples/CookieSessionSample/MemoryCacheTicketStore.cs

@@ -0,0 +1,55 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.Extensions.Caching.Memory;
+
+namespace CookieSessionSample
+{
+    public class MemoryCacheTicketStore : ITicketStore
+    {
+        private const string KeyPrefix = "AuthSessionStore-";
+        private IMemoryCache _cache;
+
+        public MemoryCacheTicketStore()
+        {
+            _cache = new MemoryCache(new MemoryCacheOptions());
+        }
+
+        public async Task<string> StoreAsync(AuthenticationTicket ticket)
+        {
+            var guid = Guid.NewGuid();
+            var key = KeyPrefix + guid.ToString();
+            await RenewAsync(key, ticket);
+            return key;
+        }
+
+        public Task RenewAsync(string key, AuthenticationTicket ticket)
+        {
+            var options = new MemoryCacheEntryOptions();
+            var expiresUtc = ticket.Properties.ExpiresUtc;
+            if (expiresUtc.HasValue)
+            {
+                options.SetAbsoluteExpiration(expiresUtc.Value);
+            }
+            options.SetSlidingExpiration(TimeSpan.FromHours(1)); // TODO: configurable.
+
+            _cache.Set(key, ticket, options);
+
+            return Task.FromResult(0);
+        }
+
+        public Task<AuthenticationTicket> RetrieveAsync(string key)
+        {
+            AuthenticationTicket ticket;
+            _cache.TryGetValue(key, out ticket);
+            return Task.FromResult(ticket);
+        }
+
+        public Task RemoveAsync(string key)
+        {
+            _cache.Remove(key);
+            return Task.FromResult(0);
+        }
+    }
+}

+ 26 - 0
src/Security/samples/CookieSessionSample/Program.cs

@@ -0,0 +1,26 @@
+using System.IO;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace CookieSessionSample
+{
+    public static class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .ConfigureLogging(factory =>
+                {
+                    factory.AddConsole();
+                    factory.AddFilter("Console", level => level >= LogLevel.Information);
+                })
+                .UseKestrel()
+                .UseContentRoot(Directory.GetCurrentDirectory())
+                .UseIISIntegration()
+                .UseStartup<Startup>()
+                .Build();
+
+            host.Run();
+        }
+    }
+}

+ 27 - 0
src/Security/samples/CookieSessionSample/Properties/launchSettings.json

@@ -0,0 +1,27 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:1790/",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "CookieSessionSample": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "applicationUrl": "http://localhost:12345",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 54 - 0
src/Security/samples/CookieSessionSample/Startup.cs

@@ -0,0 +1,54 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace CookieSessionSample
+{
+    public class Startup
+    {
+        public void ConfigureServices(IServiceCollection services)
+        {
+            // This can be removed after https://github.com/aspnet/IISIntegration/issues/371
+            services.AddAuthentication(options =>
+            {
+                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+            }).AddCookie(o => o.SessionStore = new MemoryCacheTicketStore());
+        }
+
+        public void Configure(IApplicationBuilder app)
+        {
+            app.UseAuthentication();
+
+            app.Run(async context =>
+            {
+                if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
+                {
+                    // Make a large identity
+                    var claims = new List<Claim>(1001);
+                    claims.Add(new Claim(ClaimTypes.Name, "bob"));
+                    for (int i = 0; i < 1000; i++)
+                    {
+                        claims.Add(new Claim(ClaimTypes.Role, "SomeRandomGroup" + i, ClaimValueTypes.String, "IssuedByBob", "OriginalIssuerJoe"));
+                    }
+
+                    await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
+                        new ClaimsPrincipal(new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme)));
+
+                    context.Response.ContentType = "text/plain";
+                    await context.Response.WriteAsync("Hello First timer");
+                    return;
+                }
+
+                context.Response.ContentType = "text/plain";
+                await context.Response.WriteAsync("Hello old timer");
+            });
+        }
+    }
+}

+ 21 - 0
src/Security/samples/JwtBearerSample/JwtBearerSample.csproj

@@ -0,0 +1,21 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
+    <UserSecretsId>aspnet5-JwtBearerSample-20151210102827</UserSecretsId>
+ </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.JwtBearer\Microsoft.AspNetCore.Authentication.JwtBearer.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(MicrosoftAspNetCoreStaticFilesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(MicrosoftExtensionsConfigurationUserSecretsPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
+  </ItemGroup>
+
+</Project>

+ 21 - 0
src/Security/samples/JwtBearerSample/Program.cs

@@ -0,0 +1,21 @@
+using System.IO;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+
+namespace JwtBearerSample
+{
+    public static class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .UseKestrel()
+                .UseContentRoot(Directory.GetCurrentDirectory())
+                .UseIISIntegration()
+                .UseStartup<Startup>()
+                .Build();
+
+            host.Run();
+        }
+    }
+}

+ 27 - 0
src/Security/samples/JwtBearerSample/Properties/launchSettings.json

@@ -0,0 +1,27 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:42023",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "JwtBearer": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "applicationUrl": "http://localhost:42023",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 111 - 0
src/Security/samples/JwtBearerSample/Startup.cs

@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.ExceptionServices;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Net.Http.Headers;
+using Newtonsoft.Json.Linq;
+
+namespace JwtBearerSample
+{
+    public class Startup
+    {
+        public Startup(IHostingEnvironment env)
+        {
+            Environment = env;
+
+            var builder = new ConfigurationBuilder()
+                .SetBasePath(env.ContentRootPath);
+
+            if (env.IsDevelopment())
+            {
+                // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
+                builder.AddUserSecrets<Startup>();
+            }
+
+            builder.AddEnvironmentVariables();
+            Configuration = builder.Build();
+        }
+
+        public IConfiguration Configuration { get; set; }
+
+        public IHostingEnvironment Environment { get; set; }
+
+        // Shared between users in memory
+        public IList<Todo> Todos { get; } = new List<Todo>();
+
+        // This method gets called by the runtime. Use this method to add services to the container.
+        // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+                .AddJwtBearer(o =>
+                {
+                    // You also need to update /wwwroot/app/scripts/app.js
+                    o.Authority = Configuration["oidc:authority"];
+                    o.Audience = Configuration["oidc:clientid"];
+                });
+        }
+
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app)
+        {
+            app.UseDeveloperExceptionPage();
+
+            app.UseDefaultFiles();
+            app.UseStaticFiles();
+
+            app.UseAuthentication();
+
+            // [Authorize] would usually handle this
+            app.Use(async (context, next) =>
+            {
+                // Use this if there are multiple authentication schemes
+                var authResult = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
+                if (authResult.Succeeded && authResult.Principal.Identity.IsAuthenticated)
+                {
+                    await next();
+                }
+                else if (authResult.Failure != null)
+                {
+                    // Rethrow, let the exception page handle it.
+                    ExceptionDispatchInfo.Capture(authResult.Failure).Throw();
+                }
+                else
+                {
+                    await context.ChallengeAsync();
+                }
+            });
+
+            // MVC would usually handle this:
+            app.Map("/api/TodoList", todoApp =>
+            {
+                todoApp.Run(async context =>
+                {
+                    var response = context.Response;
+                    if (context.Request.Method.Equals("POST", System.StringComparison.OrdinalIgnoreCase))
+                    {
+                        var reader = new StreamReader(context.Request.Body);
+                        var body = await reader.ReadToEndAsync();
+                        var obj = JObject.Parse(body);
+                        var todo = new Todo() { Description = obj["Description"].Value<string>(), Owner = context.User.Identity.Name };
+                        Todos.Add(todo);
+                    }
+                    else
+                    {
+                        response.ContentType = "application/json";
+                        response.Headers[HeaderNames.CacheControl] = "no-cache";
+                        var json = JToken.FromObject(Todos);
+                        await response.WriteAsync(json.ToString());
+                    }
+                });
+            });
+        }
+    }
+}

+ 8 - 0
src/Security/samples/JwtBearerSample/Todo.cs

@@ -0,0 +1,8 @@
+namespace JwtBearerSample
+{
+    public class Todo
+    {
+        public string Description { get; set; }
+        public string Owner { get; set; }
+    }
+}

+ 28 - 0
src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/app.js

@@ -0,0 +1,28 @@
+'use strict';
+angular.module('todoApp', ['ngRoute','AdalAngular'])
+.config(['$routeProvider', '$httpProvider', 'adalAuthenticationServiceProvider', function ($routeProvider, $httpProvider, adalProvider) {
+
+    $routeProvider.when("/Home", {
+        controller: "homeCtrl",
+        templateUrl: "/App/Views/Home.html",
+    }).when("/TodoList", {
+        controller: "todoListCtrl",
+        templateUrl: "/App/Views/TodoList.html",
+        requireADLogin: true,
+    }).when("/UserData", {
+        controller: "userDataCtrl",
+        templateUrl: "/App/Views/UserData.html",
+    }).otherwise({ redirectTo: "/Home" });
+
+    adalProvider.init(
+        {
+            instance: 'https://login.microsoftonline.com/', 
+            tenant: 'tratcheroutlook.onmicrosoft.com',
+            clientId: '63a87a83-64b9-4ac1-b2c5-092126f8474f',
+            extraQueryParameter: 'nux=1',
+            // cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost.
+        },
+        $httpProvider
+        );
+   
+}]);

+ 13 - 0
src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/homeCtrl.js

@@ -0,0 +1,13 @@
+'use strict';
+angular.module('todoApp')
+.controller('homeCtrl', ['$scope', 'adalAuthenticationService','$location', function ($scope, adalService, $location) {
+    $scope.login = function () {
+        adalService.login();
+    };
+    $scope.logout = function () {
+        adalService.logOut();
+    };
+    $scope.isActive = function (viewLocation) {        
+        return viewLocation === $location.path();
+    };
+}]);

+ 5 - 0
src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/indexCtrl.js

@@ -0,0 +1,5 @@
+'use strict';
+angular.module('todoApp')
+.controller('indexCtrl', ['$scope', 'adalAuthenticationService', function ($scope, adalService) {
+
+}]);

+ 71 - 0
src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/todoListCtrl.js

@@ -0,0 +1,71 @@
+'use strict';
+angular.module('todoApp')
+.controller('todoListCtrl', ['$scope', '$location', 'todoListSvc', 'adalAuthenticationService', function ($scope, $location, todoListSvc, adalService) {
+    $scope.error = "";
+    $scope.loadingMessage = "Loading...";
+    $scope.todoList = null;
+    $scope.editingInProgress = false;
+    $scope.newTodoCaption = "";
+
+
+    $scope.editInProgressTodo = {
+        Description: "",
+        ID: 0
+    };
+
+    
+
+    $scope.editSwitch = function (todo) {
+        todo.edit = !todo.edit;
+        if (todo.edit) {
+            $scope.editInProgressTodo.Description = todo.Description;
+            $scope.editInProgressTodo.ID = todo.ID;
+            $scope.editingInProgress = true;
+        } else {
+            $scope.editingInProgress = false;
+        }
+    };
+
+    $scope.populate = function () {
+        todoListSvc.getItems().success(function (results) {
+            $scope.todoList = results;
+            $scope.loadingMessage = "";
+        }).error(function (err) {
+            $scope.error = err;
+            $scope.loadingMessage = "";
+        })
+    };
+    $scope.delete = function (id) {
+        todoListSvc.deleteItem(id).success(function (results) {
+            $scope.loadingMessage = "";
+            $scope.populate();
+        }).error(function (err) {
+            $scope.error = err;
+            $scope.loadingMessage = "";
+        })
+    };
+    $scope.update = function (todo) {
+        todoListSvc.putItem($scope.editInProgressTodo).success(function (results) {
+            $scope.loadingMsg = "";
+            $scope.populate();
+            $scope.editSwitch(todo);
+        }).error(function (err) {
+            $scope.error = err;
+            $scope.loadingMessage = "";
+        })
+    };
+    $scope.add = function () {
+
+        todoListSvc.postItem({
+            'Description': $scope.newTodoCaption,
+            'Owner': adalService.userInfo.userName
+        }).success(function (results) {
+            $scope.loadingMsg = "";
+            $scope.newTodoCaption = "";
+            $scope.populate();
+        }).error(function (err) {
+            $scope.error = err;
+            $scope.loadingMsg = "";
+        })
+    };
+}]);

+ 24 - 0
src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/todoListSvc.js

@@ -0,0 +1,24 @@
+'use strict';
+angular.module('todoApp')
+.factory('todoListSvc', ['$http', function ($http) {
+    return {
+        getItems : function(){
+            return $http.get('/api/TodoList');
+        },
+        getItem : function(id){
+            return $http.get('/api/TodoList/' + id);
+        },
+        postItem : function(item){
+            return $http.post('/api/TodoList/',item);
+        },
+        putItem : function(item){
+            return $http.put('/api/TodoList/', item);
+        },
+        deleteItem : function(id){
+            return $http({
+                method: 'DELETE',
+                url: '/api/TodoList/' + id
+            });
+        }
+    };
+}]);

+ 6 - 0
src/Security/samples/JwtBearerSample/wwwroot/App/Scripts/userDataCtrl.js

@@ -0,0 +1,6 @@
+'use strict';
+angular.module('todoApp')
+.controller('userDataCtrl', ['$scope', 'adalAuthenticationService', function ($scope, adalService) {
+
+
+}]);

+ 3 - 0
src/Security/samples/JwtBearerSample/wwwroot/App/Views/Home.html

@@ -0,0 +1,3 @@
+<div>
+    home sweet home
+</div>

+ 24 - 0
src/Security/samples/JwtBearerSample/wwwroot/App/Views/TodoList.html

@@ -0,0 +1,24 @@
+<div ng-init="populate()">
+    <p class="error">{{error}}</p>
+    <p>{{loadingMessage}}</p>
+    <div class="panel">
+        <div class="input-group">
+            <input ng-model="newTodoCaption" class="form-control" />
+            <span class="input-group-btn">
+                <button ng-click="add();" class="btn btn-default">Add</button>
+            </span>
+        </div>
+        <table class="table table-striped">
+            <tbody>
+                <tr data-ng-repeat="item in todoList">
+                    <td>
+                        <p data-ng-hide="item.edit">{{item.Description}}</p>                      
+                    </td>
+                    <td>
+                        <p data-ng-hide="item.edit">{{item.Owner}}</p>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+</div>

+ 23 - 0
src/Security/samples/JwtBearerSample/wwwroot/App/Views/UserData.html

@@ -0,0 +1,23 @@
+<div>
+    <h3>
+        Id_token content
+    </h3>
+    <p>{{userInfo.userName}}</p>
+    <p>aud:{{userInfo.profile.aud}}</p>
+    <p>iss:{{userInfo.profile.iss}}</p>
+    <p>iat:{{userInfo.profile.iat}}</p>
+    <p>nbf:{{userInfo.profile.nbf}}</p>
+    <p>exp:{{userInfo.profile.exp}}</p>
+    <p>ver:{{userInfo.profile.ver}}</p>
+    <p>tid:{{userInfo.profile.tid}}</p>
+    <p>amr:{{userInfo.profile.amr}}</p>
+    <p>oid:{{userInfo.profile.oid}}</p>
+    <p>upn:{{userInfo.profile.upn}}</p>
+    <p>unique_name:{{userInfo.profile.unique_name}}</p>
+    <p>sub:{{userInfo.profile.sub}}</p>
+    <p>family_name:{{userInfo.profile.family_name}}</p>
+    <p>given_name:{{userInfo.profile.given_name}}</p>
+    <p>pwd_exp:{{userInfo.profile.pwd_exp}}</p>
+    <p>pwd_url:{{userInfo.profile.pwd_url}}</p>
+
+</div>

+ 68 - 0
src/Security/samples/JwtBearerSample/wwwroot/index.html

@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <title>Todo List: a SPA sample demonstrating Azure AD and ADAL JS</title>
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
+</head>
+<body ng-app="todoApp" ng-controller="homeCtrl" role="document">
+
+
+    <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
+        <div class="container">
+            <div class="navbar-header">
+                <button type="button" class="navbar-toggle collapsed"
+                        data-toggle="collapse"
+                        data-target=".navbar-collapse">
+
+                    <span class="icon-bar"></span>
+                    <span class="icon-bar"></span>
+                    <span class="icon-bar"></span>
+                </button>
+                <a class="navbar-brand" href="#/Home">ADAL JS Sample</a>
+            </div>
+            <div class="navbar-collapse collapse">
+                <ul class="nav navbar-nav">
+                    <li ng-class="{ active: isActive('/Home') }"><a href="#/Home">Home</a></li>
+                    <li ng-class="{ active: isActive('/TodoList') }"><a href="#/TodoList">Todo List</a></li>
+                    <li ng-class="{ active: isActive('/UserData') }"><a href="#/UserData" ng-show="userInfo.isAuthenticated">User</a></li>
+                </ul>
+                <ul class="nav navbar-nav navbar-right">
+                    <li><a class="btn btn-link" ng-show="userInfo.isAuthenticated" ng-click="logout()">Logout</a></li>
+                    <li><a class="btn btn-link" ng-hide="userInfo.isAuthenticated" ng-click="login()">Login</a></li>
+                </ul>
+            </div>
+        </div>
+    </div>
+
+
+    <br />
+    <div class="container" role="main">
+        <div class="row">
+            <div class="col-xs-10 col-xs-offset-1" style="background-color:azure">
+                <div class="page-header">
+                    <h1>Todo List</h1>
+                </div>
+                <p>This sample demonstrates how to take advantage of ADAL JS for adding Azure AD authentication to your AngularJS apps.</p>
+            </div>
+        </div>
+        <div class="row">
+            <div class="col-xs-10 col-xs-offset-1">
+                <div ng-view class="panel-body">
+
+                </div>
+            </div>
+        </div>
+        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
+        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.min.js"></script>
+        <script src="https://code.angularjs.org/1.2.25/angular-route.js"></script>
+        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
+        <script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal.min.js"></script>
+        <script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal-angular.min.js"></script>
+        <script src="App/Scripts/app.js"></script>
+        <script src="App/Scripts/homeCtrl.js"></script>
+        <script src="App/Scripts/userDataCtrl.js"></script>
+        <script src="App/Scripts/todoListCtrl.js"></script>
+        <script src="App/Scripts/todoListSvc.js"></script>
+</body>
+</html>

+ 97 - 0
src/Security/samples/OpenIdConnect.AzureAdSample/AuthPropertiesTokenCache.cs

@@ -0,0 +1,97 @@
+using System;
+using System.Security.Claims;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Http;
+using Microsoft.IdentityModel.Clients.ActiveDirectory;
+
+namespace OpenIdConnect.AzureAdSample
+{
+    public class AuthPropertiesTokenCache : TokenCache
+    {
+        private const string TokenCacheKey = ".TokenCache";
+
+        private HttpContext _httpContext;
+        private ClaimsPrincipal _principal;
+        private AuthenticationProperties _authProperties;
+        private string _signInScheme;
+
+        private AuthPropertiesTokenCache(AuthenticationProperties authProperties) : base()
+        {
+            _authProperties = authProperties;
+            BeforeAccess = BeforeAccessNotificationWithProperties;
+            AfterAccess = AfterAccessNotificationWithProperties;
+            BeforeWrite = BeforeWriteNotification;
+        }
+
+        private AuthPropertiesTokenCache(HttpContext httpContext, string signInScheme) : base()
+        {
+            _httpContext = httpContext;
+            _signInScheme = signInScheme;
+            BeforeAccess = BeforeAccessNotificationWithContext;
+            AfterAccess = AfterAccessNotificationWithContext;
+            BeforeWrite = BeforeWriteNotification;
+        }
+
+        public static TokenCache ForCodeRedemption(AuthenticationProperties authProperties)
+        {
+            return new AuthPropertiesTokenCache(authProperties);
+        }
+
+        public static TokenCache ForApiCalls(HttpContext httpContext,
+            string signInScheme = CookieAuthenticationDefaults.AuthenticationScheme)
+        {
+            return new AuthPropertiesTokenCache(httpContext, signInScheme);
+        }
+
+        private void BeforeAccessNotificationWithProperties(TokenCacheNotificationArgs args)
+        {
+            string cachedTokensText;
+            if (_authProperties.Items.TryGetValue(TokenCacheKey, out cachedTokensText))
+            {
+                var cachedTokens = Convert.FromBase64String(cachedTokensText);
+                Deserialize(cachedTokens);
+            }
+        }
+
+        private void BeforeAccessNotificationWithContext(TokenCacheNotificationArgs args)
+        {
+            // Retrieve the auth session with the cached tokens
+            var result = _httpContext.AuthenticateAsync(_signInScheme).Result;
+            _authProperties = result.Ticket.Properties;
+            _principal = result.Ticket.Principal;
+
+            BeforeAccessNotificationWithProperties(args);
+        }
+
+        private void AfterAccessNotificationWithProperties(TokenCacheNotificationArgs args)
+        {
+            // if state changed
+            if (HasStateChanged)
+            {
+                var cachedTokens = Serialize();
+                var cachedTokensText = Convert.ToBase64String(cachedTokens);
+                _authProperties.Items[TokenCacheKey] = cachedTokensText;
+            }
+        }
+
+        private void AfterAccessNotificationWithContext(TokenCacheNotificationArgs args)
+        {
+            // if state changed
+            if (HasStateChanged)
+            {
+                AfterAccessNotificationWithProperties(args);
+
+                var cachedTokens = Serialize();
+                var cachedTokensText = Convert.ToBase64String(cachedTokens);
+                _authProperties.Items[TokenCacheKey] = cachedTokensText;
+                _httpContext.SignInAsync(_signInScheme, _principal, _authProperties).Wait();
+            }
+        }
+
+        private void BeforeWriteNotification(TokenCacheNotificationArgs args)
+        {
+            // if you want to ensure that no concurrent write take place, use this notification to place a lock on the entry
+        }
+    }
+}

+ 23 - 0
src/Security/samples/OpenIdConnect.AzureAdSample/OpenIdConnect.AzureAdSample.csproj

@@ -0,0 +1,23 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
+    <UserSecretsId>aspnet5-OpenIdConnectSample-20151210110318</UserSecretsId>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.OpenIdConnect\Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(MicrosoftExtensionsConfigurationUserSecretsPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
+    <PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="$(MicrosoftIdentityModelClientsActiveDirectoryPackageVersion)" />
+  </ItemGroup>
+
+</Project>

+ 27 - 0
src/Security/samples/OpenIdConnect.AzureAdSample/Program.cs

@@ -0,0 +1,27 @@
+using System.IO;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace OpenIdConnect.AzureAdSample
+{
+    public static class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .ConfigureLogging(factory =>
+                {
+                    factory.AddConsole();
+                    factory.AddFilter("Console", level => level >= LogLevel.Information);
+                })
+                .UseKestrel()
+                .UseUrls("http://localhost:42023")
+                .UseContentRoot(Directory.GetCurrentDirectory())
+                .UseIISIntegration()
+                .UseStartup<Startup>()
+                .Build();
+
+            host.Run();
+        }
+    }
+}

+ 27 - 0
src/Security/samples/OpenIdConnect.AzureAdSample/Properties/launchSettings.json

@@ -0,0 +1,27 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:42023",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "OpenIdConnect": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "applicationUrl": "http://localhost:42023",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 20 - 0
src/Security/samples/OpenIdConnect.AzureAdSample/Readme.md

@@ -0,0 +1,20 @@
+# How to set up the sample locally
+
+## Set up [Azure Active Directory](https://azure.microsoft.com/en-us/documentation/services/active-directory/)
+
+1. Create your own Azure Active Directory (AD). Save the "tenent name".
+2. Add a new Application: in the Azure AD portal, select Application, and click Add in the drawer.
+3. Set the sign-on url to `http://localhost:42023`.
+4. Select the newly created Application, navigate to the Configure tab.
+5. Find and save the "Client Id"
+8. In the keys section add a new key. A key value will be generated. Save the value as "Client Secret"
+
+## Configure the local environment
+1. Set environment ASPNETCORE_ENVIRONMENT to DEVELOPMENT. ([Working with Multiple Environments](https://docs.asp.net/en/latest/fundamentals/environments.html))
+2. Set up user secrets:
+```
+dotnet user-secrets set oidc:clientid <Client Id>
+dotnet user-secrets set oidc:clientsecret <Client Secret>
+dotnet user-secrets set oidc:authority https://login.windows.net/<Tenent Name>.onmicrosoft.com
+```
+

+ 203 - 0
src/Security/samples/OpenIdConnect.AzureAdSample/Startup.cs

@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Extensions;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.IdentityModel.Clients.ActiveDirectory;
+using Microsoft.IdentityModel.Protocols.OpenIdConnect;
+
+namespace OpenIdConnect.AzureAdSample
+{
+    public class Startup
+    {
+        public Startup(IHostingEnvironment env)
+        {
+            var builder = new ConfigurationBuilder()
+                .SetBasePath(env.ContentRootPath);
+
+            if (env.IsDevelopment())
+            {
+                // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
+                builder.AddUserSecrets<Startup>();
+            }
+
+            builder.AddEnvironmentVariables();
+            Configuration = builder.Build();
+        }
+
+        public IConfiguration Configuration { get; set; }
+
+        private string ClientId => Configuration["oidc:clientid"];
+        private string ClientSecret => Configuration["oidc:clientsecret"];
+        private string Authority => Configuration["oidc:authority"];
+        private string Resource => "https://graph.windows.net";
+
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.AddAuthentication(sharedOptions =>
+            {
+                sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+                sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
+            })
+                .AddCookie()
+                .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, "AAD", o =>
+            {
+                o.ClientId = ClientId;
+                o.ClientSecret = ClientSecret; // for code flow
+                o.Authority = Authority;
+                o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
+                o.SignedOutRedirectUri = "/signed-out";
+                // GetClaimsFromUserInfoEndpoint = true,
+                o.Events = new OpenIdConnectEvents()
+                {
+                    OnAuthorizationCodeReceived = async context =>
+                    {
+                        var request = context.HttpContext.Request;
+                        var currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
+                        var credential = new ClientCredential(ClientId, ClientSecret);
+                        var authContext = new AuthenticationContext(Authority, AuthPropertiesTokenCache.ForCodeRedemption(context.Properties));
+
+                        var result = await authContext.AcquireTokenByAuthorizationCodeAsync(
+                            context.ProtocolMessage.Code, new Uri(currentUri), credential, Resource);
+
+                        context.HandleCodeRedemption(result.AccessToken, result.IdToken);
+                    }
+                };
+            });
+        }
+
+        public void Configure(IApplicationBuilder app)
+        {
+            app.UseDeveloperExceptionPage();
+
+            app.UseAuthentication();
+
+            app.Run(async context =>
+            {
+                if (context.Request.Path.Equals("/signin"))
+                {
+                    if (context.User.Identities.Any(identity => identity.IsAuthenticated))
+                    {
+                        // User has already signed in
+                        context.Response.Redirect("/");
+                        return;
+                    }
+
+                    await context.ChallengeAsync(new AuthenticationProperties { RedirectUri = "/" });
+                }
+                else if (context.Request.Path.Equals("/signout"))
+                {
+                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+                    await WriteHtmlAsync(context.Response,
+                        async response =>
+                        {
+                            await response.WriteAsync($"<h1>Signed out locally: {HtmlEncode(context.User.Identity.Name)}</h1>");
+                            await response.WriteAsync("<a class=\"btn btn-primary\" href=\"/\">Sign In</a>");
+                        });
+                }
+                else if (context.Request.Path.Equals("/signout-remote"))
+                {
+                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+                    await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
+                }
+                else if (context.Request.Path.Equals("/signed-out"))
+                {
+                    await WriteHtmlAsync(context.Response, 
+                        async response =>
+                        {
+                            await response.WriteAsync($"<h1>You have been signed out.</h1>");
+                            await response.WriteAsync("<a class=\"btn btn-primary\" href=\"/signin\">Sign In</a>");
+                        });
+                }
+                else if (context.Request.Path.Equals("/remote-signedout"))
+                {
+                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+                    await WriteHtmlAsync(context.Response,
+                        async response =>
+                        {
+                            await response.WriteAsync($"<h1>Signed out remotely: {HtmlEncode(context.User.Identity.Name)}</h1>");
+                            await response.WriteAsync("<a class=\"btn btn-primary\" href=\"/\">Sign In</a>");
+                        });
+                }
+                else
+                {
+                    if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
+                    {
+                        await context.ChallengeAsync(new AuthenticationProperties { RedirectUri = "/" });
+                        return;
+                    }
+
+                    await WriteHtmlAsync(context.Response, async response =>
+                    {
+                        await response.WriteAsync($"<h1>Hello Authenticated User {HtmlEncode(context.User.Identity.Name)}</h1>");
+                        await response.WriteAsync("<a class=\"btn btn-default\" href=\"/signout\">Sign Out Locally</a>");
+                        await response.WriteAsync("<a class=\"btn btn-default\" href=\"/signout-remote\">Sign Out Remotely</a>");
+
+                        await response.WriteAsync("<h2>Claims:</h2>");
+                        await WriteTableHeader(response, new string[] { "Claim Type", "Value" }, context.User.Claims.Select(c => new string[] { c.Type, c.Value }));
+
+                        await response.WriteAsync("<h2>Tokens:</h2>");
+                        try
+                        {
+                            // Use ADAL to get the right token
+                            var authContext = new AuthenticationContext(Authority, AuthPropertiesTokenCache.ForApiCalls(context, CookieAuthenticationDefaults.AuthenticationScheme));
+                            var credential = new ClientCredential(ClientId, ClientSecret);
+                            string userObjectID = context.User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
+                            var result = await authContext.AcquireTokenSilentAsync(Resource, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
+
+                            await response.WriteAsync($"<h3>access_token</h3><code>{HtmlEncode(result.AccessToken)}</code><br>");
+                        }
+                        catch (Exception ex)
+                        {
+                            await response.WriteAsync($"AquireToken error: {ex.Message}");
+                        }
+                    });
+                }
+            });
+        }
+
+        private static async Task WriteHtmlAsync(HttpResponse response, Func<HttpResponse, Task> writeContent)
+        {
+            var bootstrap = "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u\" crossorigin=\"anonymous\">";
+
+            response.ContentType = "text/html";
+            await response.WriteAsync($"<html><head>{bootstrap}</head><body><div class=\"container\">");
+            await writeContent(response);
+            await response.WriteAsync("</div></body></html>");
+        }
+
+        private static async Task WriteTableHeader(HttpResponse response, IEnumerable<string> columns, IEnumerable<IEnumerable<string>> data)
+        {
+            await response.WriteAsync("<table class=\"table table-condensed\">");
+            await response.WriteAsync("<tr>");
+            foreach (var column in columns)
+            {
+                await response.WriteAsync($"<th>{HtmlEncode(column)}</th>");
+            }
+            await response.WriteAsync("</tr>");
+            foreach (var row in data)
+            {
+                await response.WriteAsync("<tr>");
+                foreach (var column in row)
+                {
+                    await response.WriteAsync($"<td>{HtmlEncode(column)}</td>");
+                }
+                await response.WriteAsync("</tr>");
+            }
+            await response.WriteAsync("</table>");
+        }
+
+        private static string HtmlEncode(string content) =>
+            string.IsNullOrEmpty(content) ? string.Empty : HtmlEncoder.Default.Encode(content);
+    }
+}
+

+ 33 - 0
src/Security/samples/OpenIdConnectSample/OpenIdConnectSample.csproj

@@ -0,0 +1,33 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
+    <UserSecretsId>aspnet5-OpenIdConnectSample-20151210110318</UserSecretsId>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <None Remove="compiler\resources\cert.pfx" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.OpenIdConnect\Microsoft.AspNetCore.Authentication.OpenIdConnect.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(MicrosoftAspNetCoreServerKestrelHttpsPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(MicrosoftExtensionsConfigurationUserSecretsPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(MicrosoftExtensionsFileProvidersEmbeddedPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(MicrosoftExtensionsLoggingDebugPackageVersion)" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <EmbeddedResource Include="compiler\resources\cert.pfx" />
+  </ItemGroup>
+
+</Project>

+ 59 - 0
src/Security/samples/OpenIdConnectSample/Program.cs

@@ -0,0 +1,59 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.FileProviders;
+using Microsoft.Extensions.Logging;
+
+namespace OpenIdConnectSample
+{
+    public static class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .ConfigureLogging(factory =>
+                {
+                    factory.AddConsole();
+                    factory.AddDebug();
+                    factory.AddFilter("Console", level => level >= LogLevel.Information);
+                    factory.AddFilter("Debug", level => level >= LogLevel.Information);
+                })
+                .UseKestrel(options =>
+                {
+                    options.Listen(IPAddress.Loopback, 44318, listenOptions =>
+                    {
+                        // Configure SSL
+                        var serverCertificate = LoadCertificate();
+                        listenOptions.UseHttps(serverCertificate);
+                    });
+                })
+                .UseContentRoot(Directory.GetCurrentDirectory())
+                .UseIISIntegration()
+                .UseStartup<Startup>()
+                .Build();
+
+            host.Run();
+        }
+
+        private static X509Certificate2 LoadCertificate()
+        {
+            var assembly = typeof(Startup).GetTypeInfo().Assembly;
+            var embeddedFileProvider = new EmbeddedFileProvider(assembly, "OpenIdConnectSample");
+            var certificateFileInfo = embeddedFileProvider.GetFileInfo("compiler/resources/cert.pfx");
+            using (var certificateStream = certificateFileInfo.CreateReadStream())
+            {
+                byte[] certificatePayload;
+                using (var memoryStream = new MemoryStream())
+                {
+                    certificateStream.CopyTo(memoryStream);
+                    certificatePayload = memoryStream.ToArray();
+                }
+
+                return new X509Certificate2(certificatePayload, "testPassword");
+            }
+        }
+    }
+}

+ 28 - 0
src/Security/samples/OpenIdConnectSample/Properties/launchSettings.json

@@ -0,0 +1,28 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:42023",
+      "sslPort": 44318
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "https://localhost:44318/",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "OpenIdConnectSample": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "applicationUrl": "https://localhost:44318/",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 44 - 0
src/Security/samples/OpenIdConnectSample/Readme.md

@@ -0,0 +1,44 @@
+# How to set up the sample locally
+
+The OpenIdConnect sample supports multilpe authentication providers. In these instruction, we will explore how to set up this sample with both Azure Active Directory and Google Identity Platform.
+
+## Determine your development environment and a few key variables
+
+This sample is configured to run on port __44318__ locally. In Visual Studio, the setting is carried out in `.\properties\launchSettings.json`. When the application is run from command line, the URL is coded in `Program.cs`.
+
+If the application is run from command line or terminal, environment variable ASPNETCORE_ENVIRONMENT should be set to DEVELOPMENT to enable user secret.
+
+## Configure the Authorization server
+
+### Configure with Azure Active Directory
+
+1. Set up a new Azure Active Directory (AAD) in your Azure Subscription.
+2. Open the newly created AAD in Azure web portal.
+3. Navigate to the Applications tab.
+4. Add a new Application to the AAD. Set the "Sign-on URL" to sample application's URL.
+5. Naigate to the Application, and click the Configure tab.
+6. Find and save the "Client Id".
+7. Add a new key in the "Keys" section. Save value of the key, which is the "Client Secret".
+8. Click the "View Endpoints" on the drawer, a dialog will shows six endpoint URLs. Copy the "OAuth 2.0 Authorization Endpoint" to a text editor and remove the "/oauth2/authorize" from the string. The remaining part is the __authority URL__. It looks like `https://login.microsoftonline.com/<guid>`.
+
+### Configure with Google Identity Platform 
+
+1. Create a new project through [Google APIs](https://console.developers.google.com).
+2. In the sidebar choose "Credentials".
+3. Navigate to "OAuth consent screen" tab, fill in the project name and save.
+4. Navigate to "Credentials" tab. Click "Create credentials". Choose "OAuth client ID". 
+5. Select "Web application" as the application type. Fill in the "Authorized redirect URIs" with `https://localhost:44318/signin-oidc`.
+6. Save the "Client ID" and "Client Secret" shown in the dialog.
+7. The "Authority URL" for Google Authentication is `https://accounts.google.com/`.
+
+## Configure the sample application
+
+1. Restore the application.
+2. Set user secrets:
+
+ ```
+dotnet user-secrets set oidc:clientid <Client Id>
+dotnet user-secrets set oidc:clientsecret <Client Secret>
+dotnet user-secrets set oidc:authority <Authority URL>
+```
+

+ 297 - 0
src/Security/samples/OpenIdConnectSample/Startup.cs

@@ -0,0 +1,297 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IdentityModel.Tokens.Jwt;
+using System.Linq;
+using System.Net.Http;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Microsoft.IdentityModel.Protocols.OpenIdConnect;
+using Newtonsoft.Json.Linq;
+
+namespace OpenIdConnectSample
+{
+    public class Startup
+    {
+        public Startup(IHostingEnvironment env)
+        {
+            Environment = env;
+
+            var builder = new ConfigurationBuilder()
+                .SetBasePath(env.ContentRootPath);
+
+            if (env.IsDevelopment())
+            {
+                // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
+                builder.AddUserSecrets<Startup>();
+            }
+
+            builder.AddEnvironmentVariables();
+            Configuration = builder.Build();
+        }
+
+        public IConfiguration Configuration { get; set; }
+
+        public IHostingEnvironment Environment { get; set; }
+
+        public void ConfigureServices(IServiceCollection services)
+        {
+            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
+
+            services.AddAuthentication(sharedOptions =>
+            {
+                sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+                sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+                sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
+            })
+                .AddCookie()
+                .AddOpenIdConnect(o =>
+            {
+                o.ClientId = Configuration["oidc:clientid"];
+                o.ClientSecret = Configuration["oidc:clientsecret"]; // for code flow
+                o.Authority = Configuration["oidc:authority"];
+
+                o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
+                o.SaveTokens = true;
+                o.GetClaimsFromUserInfoEndpoint = true;
+
+                o.ClaimActions.MapAllExcept("aud", "iss", "iat", "nbf", "exp", "aio", "c_hash", "uti", "nonce");
+
+                o.Events = new OpenIdConnectEvents()
+                {
+                    OnAuthenticationFailed = c =>
+                    {
+                        c.HandleResponse();
+
+                        c.Response.StatusCode = 500;
+                        c.Response.ContentType = "text/plain";
+                        if (Environment.IsDevelopment())
+                        {
+                            // Debug only, in production do not share exceptions with the remote host.
+                            return c.Response.WriteAsync(c.Exception.ToString());
+                        }
+                        return c.Response.WriteAsync("An error occurred processing your authentication.");
+                    }
+                };
+            });
+        }
+
+        public void Configure(IApplicationBuilder app, IOptionsMonitor<OpenIdConnectOptions> optionsMonitor)
+        {
+            app.UseDeveloperExceptionPage();
+            app.UseAuthentication();
+
+            app.Run(async context =>
+            {
+                var response = context.Response;
+
+                if (context.Request.Path.Equals("/signedout"))
+                {
+                    await WriteHtmlAsync(response, async res =>
+                    {
+                        await res.WriteAsync($"<h1>You have been signed out.</h1>");
+                        await res.WriteAsync("<a class=\"btn btn-default\" href=\"/\">Home</a>");
+                    });
+                    return;
+                }
+
+                if (context.Request.Path.Equals("/signout"))
+                {
+                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+                    await WriteHtmlAsync(response, async res =>
+                    {
+                        await res.WriteAsync($"<h1>Signed out {HtmlEncode(context.User.Identity.Name)}</h1>");
+                        await res.WriteAsync("<a class=\"btn btn-default\" href=\"/\">Home</a>");
+                    });
+                    return;
+                }
+
+                if (context.Request.Path.Equals("/signout-remote"))
+                {
+                    // Redirects
+                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+                    await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties()
+                    {
+                        RedirectUri = "/signedout"
+                    });
+                    return;
+                }
+
+                if (context.Request.Path.Equals("/Account/AccessDenied"))
+                {
+                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+                    await WriteHtmlAsync(response, async res =>
+                    {
+                        await res.WriteAsync($"<h1>Access Denied for user {HtmlEncode(context.User.Identity.Name)} to resource '{HtmlEncode(context.Request.Query["ReturnUrl"])}'</h1>");
+                        await res.WriteAsync("<a class=\"btn btn-default\" href=\"/signout\">Sign Out</a>");
+                        await res.WriteAsync("<a class=\"btn btn-default\" href=\"/\">Home</a>");
+                    });
+                    return;
+                }
+
+                // DefaultAuthenticateScheme causes User to be set
+                // var user = context.User;
+
+                // This is what [Authorize] calls
+                var userResult = await context.AuthenticateAsync();
+                var user = userResult.Principal;
+                var props = userResult.Properties;
+
+                // This is what [Authorize(ActiveAuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] calls
+                // var user = await context.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme);
+
+                // Not authenticated
+                if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated))
+                {
+                    // This is what [Authorize] calls
+                    await context.ChallengeAsync();
+
+                    // This is what [Authorize(ActiveAuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] calls
+                    // await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme);
+
+                    return;
+                }
+
+                // Authenticated, but not authorized
+                if (context.Request.Path.Equals("/restricted") && !user.Identities.Any(identity => identity.HasClaim("special", "true")))
+                {
+                    await context.ForbidAsync();
+                    return;
+                }
+
+                if (context.Request.Path.Equals("/refresh"))
+                {
+                    var refreshToken = props.GetTokenValue("refresh_token");
+
+                    if (string.IsNullOrEmpty(refreshToken))
+                    {
+                        await WriteHtmlAsync(response, async res =>
+                        {
+                            await res.WriteAsync($"No refresh_token is available.<br>");
+                            await res.WriteAsync("<a class=\"btn btn-link\" href=\"/signout\">Sign Out</a>");
+                        });
+
+                        return;
+                    }
+
+                    var options = optionsMonitor.Get(OpenIdConnectDefaults.AuthenticationScheme);
+                    var metadata = await options.ConfigurationManager.GetConfigurationAsync(context.RequestAborted);
+
+                    var pairs = new Dictionary<string, string>()
+                    {
+                        { "client_id", options.ClientId },
+                        { "client_secret", options.ClientSecret },
+                        { "grant_type", "refresh_token" },
+                        { "refresh_token", refreshToken }
+                    };
+                    var content = new FormUrlEncodedContent(pairs);
+                    var tokenResponse = await options.Backchannel.PostAsync(metadata.TokenEndpoint, content, context.RequestAborted);
+                    tokenResponse.EnsureSuccessStatusCode();
+
+                    var payload = JObject.Parse(await tokenResponse.Content.ReadAsStringAsync());
+
+                    // Persist the new acess token
+                    props.UpdateTokenValue("access_token", payload.Value<string>("access_token"));
+                    props.UpdateTokenValue("refresh_token", payload.Value<string>("refresh_token"));
+                    if (int.TryParse(payload.Value<string>("expires_in"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var seconds))
+                    {
+                        var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
+                        props.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
+                    }
+                    await context.SignInAsync(user, props);
+
+                    await WriteHtmlAsync(response, async res =>
+                    {
+                        await res.WriteAsync($"<h1>Refreshed.</h1>");
+                        await res.WriteAsync("<a class=\"btn btn-default\" href=\"/refresh\">Refresh tokens</a>");
+                        await res.WriteAsync("<a class=\"btn btn-default\" href=\"/\">Home</a>");
+
+                        await res.WriteAsync("<h2>Tokens:</h2>");
+                        await WriteTableHeader(res, new string[] { "Token Type", "Value" }, props.GetTokens().Select(token => new string[] { token.Name, token.Value }));
+
+                        await res.WriteAsync("<h2>Payload:</h2>");
+                        await res.WriteAsync(HtmlEncoder.Default.Encode(payload.ToString()).Replace(",", ",<br>") + "<br>");
+                    });
+
+                    return;
+                }
+
+                if (context.Request.Path.Equals("/login-challenge"))
+                {
+                    // Challenge the user authentication, and force a login prompt by overwriting the
+                    // "prompt". This could be used for example to require the user to re-enter their
+                    // credentials at the authentication provider, to add an extra confirmation layer.
+                    await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new OpenIdConnectChallengeProperties()
+                    {
+                        Prompt = "login",
+
+                        // it is also possible to specify different scopes, e.g.
+                        // Scope = new string[] { "openid", "profile", "other" }
+                    });
+
+                    return;
+                }
+
+                await WriteHtmlAsync(response, async res =>
+                {
+                    await res.WriteAsync($"<h1>Hello Authenticated User {HtmlEncode(user.Identity.Name)}</h1>");
+                    await res.WriteAsync("<a class=\"btn btn-default\" href=\"/refresh\">Refresh tokens</a>");
+                    await res.WriteAsync("<a class=\"btn btn-default\" href=\"/restricted\">Restricted</a>");
+                    await res.WriteAsync("<a class=\"btn btn-default\" href=\"/login-challenge\">Login challenge</a>");
+                    await res.WriteAsync("<a class=\"btn btn-default\" href=\"/signout\">Sign Out</a>");
+                    await res.WriteAsync("<a class=\"btn btn-default\" href=\"/signout-remote\">Sign Out Remote</a>");
+
+                    await res.WriteAsync("<h2>Claims:</h2>");
+                    await WriteTableHeader(res, new string[] { "Claim Type", "Value" }, context.User.Claims.Select(c => new string[] { c.Type, c.Value }));
+
+                    await res.WriteAsync("<h2>Tokens:</h2>");
+                    await WriteTableHeader(res, new string[] { "Token Type", "Value" }, props.GetTokens().Select(token => new string[] { token.Name, token.Value }));
+                });
+            });
+        }
+
+        private static async Task WriteHtmlAsync(HttpResponse response, Func<HttpResponse, Task> writeContent)
+        {
+            var bootstrap = "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u\" crossorigin=\"anonymous\">";
+
+            response.ContentType = "text/html";
+            await response.WriteAsync($"<html><head>{bootstrap}</head><body><div class=\"container\">");
+            await writeContent(response);
+            await response.WriteAsync("</div></body></html>");
+        }
+
+        private static async Task WriteTableHeader(HttpResponse response, IEnumerable<string> columns, IEnumerable<IEnumerable<string>> data)
+        {
+            await response.WriteAsync("<table class=\"table table-condensed\">");
+            await response.WriteAsync("<tr>");
+            foreach (var column in columns)
+            {
+                await response.WriteAsync($"<th>{HtmlEncode(column)}</th>");
+            }
+            await response.WriteAsync("</tr>");
+            foreach (var row in data)
+            {
+                await response.WriteAsync("<tr>");
+                foreach (var column in row)
+                {
+                    await response.WriteAsync($"<td>{HtmlEncode(column)}</td>");
+                }
+                await response.WriteAsync("</tr>");
+            }
+            await response.WriteAsync("</table>");
+        }
+
+        private static string HtmlEncode(string content) =>
+            string.IsNullOrEmpty(content) ? string.Empty : HtmlEncoder.Default.Encode(content);
+    }
+}
+

BIN
src/Security/samples/OpenIdConnectSample/compiler/resources/cert.pfx


+ 57 - 0
src/Security/samples/SocialSample/Program.cs

@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.FileProviders;
+using Microsoft.Extensions.Logging;
+
+namespace SocialSample
+{
+    public static class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .ConfigureLogging(factory =>
+                {
+                    factory.AddConsole();
+                    factory.AddFilter("Console", level => level >= LogLevel.Information);
+                })
+                .UseKestrel(options =>
+                {
+                    options.Listen(IPAddress.Loopback, 44318, listenOptions =>
+                    {
+                        // Configure SSL
+                        var serverCertificate = LoadCertificate();
+                        listenOptions.UseHttps(serverCertificate);
+                    });
+                })
+                .UseContentRoot(Directory.GetCurrentDirectory())
+                .UseIISIntegration()
+                .UseStartup<Startup>()
+                .Build();
+
+            host.Run();
+        }
+
+        private static X509Certificate2 LoadCertificate()
+        {
+            var socialSampleAssembly = typeof(Startup).GetTypeInfo().Assembly;
+            var embeddedFileProvider = new EmbeddedFileProvider(socialSampleAssembly, "SocialSample");
+            var certificateFileInfo = embeddedFileProvider.GetFileInfo("compiler/resources/cert.pfx");
+            using (var certificateStream = certificateFileInfo.CreateReadStream())
+            {
+                byte[] certificatePayload;
+                using (var memoryStream = new MemoryStream())
+                {
+                    certificateStream.CopyTo(memoryStream);
+                    certificatePayload = memoryStream.ToArray();
+                }
+
+                return new X509Certificate2(certificatePayload, "testPassword");
+            }
+        }
+    }
+}

+ 28 - 0
src/Security/samples/SocialSample/Properties/launchSettings.json

@@ -0,0 +1,28 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:54540",
+      "sslPort": 44318
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "https://localhost:44318/",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "SocialSample": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "applicationUrl": "https://localhost:44318/",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 36 - 0
src/Security/samples/SocialSample/SocialSample.csproj

@@ -0,0 +1,36 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
+    <UserSecretsId>aspnet5-SocialSample-20151210111056</UserSecretsId>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <None Remove="compiler\resources\cert.pfx" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <EmbeddedResource Include="compiler\resources\cert.pfx" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Facebook\Microsoft.AspNetCore.Authentication.Facebook.csproj" />
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Google\Microsoft.AspNetCore.Authentication.Google.csproj" />
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.MicrosoftAccount\Microsoft.AspNetCore.Authentication.MicrosoftAccount.csproj" />
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Twitter\Microsoft.AspNetCore.Authentication.Twitter.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.DataProtection" Version="$(MicrosoftAspNetCoreDataProtectionPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(MicrosoftAspNetCoreServerKestrelHttpsPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="$(MicrosoftExtensionsConfigurationUserSecretsPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(MicrosoftExtensionsFileProvidersEmbeddedPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
+  </ItemGroup>
+
+</Project>

+ 502 - 0
src/Security/samples/SocialSample/Startup.cs

@@ -0,0 +1,502 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Security.Claims;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authentication.Facebook;
+using Microsoft.AspNetCore.Authentication.Google;
+using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
+using Microsoft.AspNetCore.Authentication.OAuth;
+using Microsoft.AspNetCore.Authentication.Twitter;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Extensions;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json.Linq;
+
+namespace SocialSample
+{
+    /* Note all servers must use the same address and port because these are pre-registered with the various providers. */
+    public class Startup
+    {
+        public Startup(IHostingEnvironment env)
+        {
+            var builder = new ConfigurationBuilder()
+                .SetBasePath(env.ContentRootPath)
+                .AddJsonFile("appsettings.json", optional: true);
+
+            if (env.IsDevelopment())
+            {
+                // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
+                builder.AddUserSecrets<Startup>();
+            }
+
+            builder.AddEnvironmentVariables();
+            Configuration = builder.Build();
+        }
+
+        public IConfiguration Configuration { get; set; }
+
+        public void ConfigureServices(IServiceCollection services)
+        {
+            if (string.IsNullOrEmpty(Configuration["facebook:appid"]))
+            {
+                // User-Secrets: https://docs.asp.net/en/latest/security/app-secrets.html
+                // See below for registration instructions for each provider.
+                throw new InvalidOperationException("User secrets must be configured for each authentication provider.");
+            }
+
+            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
+                .AddCookie(o => o.LoginPath = new PathString("/login"))
+                // You must first create an app with Facebook and add its ID and Secret to your user-secrets.
+                // https://developers.facebook.com/apps/
+                .AddFacebook(o =>
+            {
+                o.AppId = Configuration["facebook:appid"];
+                o.AppSecret = Configuration["facebook:appsecret"];
+                o.Scope.Add("email");
+                o.Fields.Add("name");
+                o.Fields.Add("email");
+                o.SaveTokens = true;
+                o.Events = new OAuthEvents()
+                {
+                    OnRemoteFailure = HandleOnRemoteFailure
+                };
+            })
+                // You must first create an app with Google and add its ID and Secret to your user-secrets.
+                // https://console.developers.google.com/project
+                .AddOAuth("Google-AccessToken", "Google AccessToken only", o =>
+            {
+                o.ClientId = Configuration["google:clientid"];
+                o.ClientSecret = Configuration["google:clientsecret"];
+                o.CallbackPath = new PathString("/signin-google-token");
+                o.AuthorizationEndpoint = GoogleDefaults.AuthorizationEndpoint;
+                o.TokenEndpoint = GoogleDefaults.TokenEndpoint;
+                o.Scope.Add("openid");
+                o.Scope.Add("profile");
+                o.Scope.Add("email");
+                o.SaveTokens = true;
+                o.Events = new OAuthEvents()
+                {
+                    OnRemoteFailure = HandleOnRemoteFailure
+                };
+            })
+                // You must first create an app with Google and add its ID and Secret to your user-secrets.
+                // https://console.developers.google.com/project
+                .AddGoogle(o =>
+            {
+                o.ClientId = Configuration["google:clientid"];
+                o.ClientSecret = Configuration["google:clientsecret"];
+                o.AuthorizationEndpoint += "?prompt=consent"; // Hack so we always get a refresh token, it only comes on the first authorization response
+                o.AccessType = "offline";
+                o.SaveTokens = true;
+                o.Events = new OAuthEvents()
+                {
+                    OnRemoteFailure = HandleOnRemoteFailure
+                };
+                o.ClaimActions.MapJsonSubKey("urn:google:image", "image", "url");
+                o.ClaimActions.Remove(ClaimTypes.GivenName);
+            })
+                // You must first create an app with Twitter and add its key and Secret to your user-secrets.
+                // https://apps.twitter.com/
+                .AddTwitter(o =>
+            {
+                o.ConsumerKey = Configuration["twitter:consumerkey"];
+                o.ConsumerSecret = Configuration["twitter:consumersecret"];
+                // http://stackoverflow.com/questions/22627083/can-we-get-email-id-from-twitter-oauth-api/32852370#32852370
+                // http://stackoverflow.com/questions/36330675/get-users-email-from-twitter-api-for-external-login-authentication-asp-net-mvc?lq=1
+                o.RetrieveUserDetails = true;
+                o.SaveTokens = true;
+                o.ClaimActions.MapJsonKey("urn:twitter:profilepicture", "profile_image_url", ClaimTypes.Uri);
+                o.Events = new TwitterEvents()
+                {
+                    OnRemoteFailure = HandleOnRemoteFailure
+                };
+            })
+                /* Azure AD app model v2 has restrictions that prevent the use of plain HTTP for redirect URLs.
+                   Therefore, to authenticate through microsoft accounts, tryout the sample using the following URL:
+                   https://localhost:44318/
+                */
+                // You must first create an app with Microsoft Account and add its ID and Secret to your user-secrets.
+                // https://apps.dev.microsoft.com/
+                .AddOAuth("Microsoft-AccessToken", "Microsoft AccessToken only", o =>
+            {
+                o.ClientId = Configuration["microsoftaccount:clientid"];
+                o.ClientSecret = Configuration["microsoftaccount:clientsecret"];
+                o.CallbackPath = new PathString("/signin-microsoft-token");
+                o.AuthorizationEndpoint = MicrosoftAccountDefaults.AuthorizationEndpoint;
+                o.TokenEndpoint = MicrosoftAccountDefaults.TokenEndpoint;
+                o.Scope.Add("https://graph.microsoft.com/user.read");
+                o.SaveTokens = true;
+                o.Events = new OAuthEvents()
+                {
+                    OnRemoteFailure = HandleOnRemoteFailure
+                };
+            })
+                // You must first create an app with Microsoft Account and add its ID and Secret to your user-secrets.
+                // https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-app-registration/
+                .AddMicrosoftAccount(o =>
+            {
+                o.ClientId = Configuration["microsoftaccount:clientid"];
+                o.ClientSecret = Configuration["microsoftaccount:clientsecret"];
+                o.SaveTokens = true;
+                o.Scope.Add("offline_access");
+                o.Events = new OAuthEvents()
+                {
+                    OnRemoteFailure = HandleOnRemoteFailure
+                };
+            })
+                // You must first create an app with GitHub and add its ID and Secret to your user-secrets.
+                // https://github.com/settings/applications/
+                .AddOAuth("GitHub-AccessToken", "GitHub AccessToken only", o =>
+            {
+                o.ClientId = Configuration["github-token:clientid"];
+                o.ClientSecret = Configuration["github-token:clientsecret"];
+                o.CallbackPath = new PathString("/signin-github-token");
+                o.AuthorizationEndpoint = "https://github.com/login/oauth/authorize";
+                o.TokenEndpoint = "https://github.com/login/oauth/access_token";
+                o.SaveTokens = true;
+                o.Events = new OAuthEvents()
+                {
+                    OnRemoteFailure = HandleOnRemoteFailure
+                };
+            })
+                // You must first create an app with GitHub and add its ID and Secret to your user-secrets.
+                // https://github.com/settings/applications/
+                .AddOAuth("GitHub", "Github", o =>
+            {
+                o.ClientId = Configuration["github:clientid"];
+                o.ClientSecret = Configuration["github:clientsecret"];
+                o.CallbackPath = new PathString("/signin-github");
+                o.AuthorizationEndpoint = "https://github.com/login/oauth/authorize";
+                o.TokenEndpoint = "https://github.com/login/oauth/access_token";
+                o.UserInformationEndpoint = "https://api.github.com/user";
+                o.ClaimsIssuer = "OAuth2-Github";
+                o.SaveTokens = true;
+                // Retrieving user information is unique to each provider.
+                o.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
+                o.ClaimActions.MapJsonKey(ClaimTypes.Name, "login");
+                o.ClaimActions.MapJsonKey("urn:github:name", "name");
+                o.ClaimActions.MapJsonKey(ClaimTypes.Email, "email", ClaimValueTypes.Email);
+                o.ClaimActions.MapJsonKey("urn:github:url", "url");
+                o.Events = new OAuthEvents
+                {
+                    OnRemoteFailure = HandleOnRemoteFailure,
+                    OnCreatingTicket = async context =>
+                    {
+                        // Get the GitHub user
+                        var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
+                        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
+                        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+
+                        var response = await context.Backchannel.SendAsync(request, context.HttpContext.RequestAborted);
+                        response.EnsureSuccessStatusCode();
+
+                        var user = JObject.Parse(await response.Content.ReadAsStringAsync());
+
+                        context.RunClaimActions(user);
+                    }
+                };
+            });
+        }
+
+        private async Task HandleOnRemoteFailure(RemoteFailureContext context)
+        {
+            context.Response.StatusCode = 500;
+            context.Response.ContentType = "text/html";
+            await context.Response.WriteAsync("<html><body>");
+            await context.Response.WriteAsync("A remote failure has occurred: " + UrlEncoder.Default.Encode(context.Failure.Message) + "<br>");
+
+            if (context.Properties != null)
+            {
+                await context.Response.WriteAsync("Properties:<br>");
+                foreach (var pair in context.Properties.Items)
+                {
+                    await context.Response.WriteAsync($"-{ UrlEncoder.Default.Encode(pair.Key)}={ UrlEncoder.Default.Encode(pair.Value)}<br>");
+                }
+            }
+
+            await context.Response.WriteAsync("<a href=\"/\">Home</a>");
+            await context.Response.WriteAsync("</body></html>");
+
+            // context.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(context.Failure.Message));
+
+            context.HandleResponse();
+        }
+
+        public void Configure(IApplicationBuilder app)
+        {
+            app.UseDeveloperExceptionPage();
+
+            app.UseAuthentication();
+
+            // Choose an authentication type
+            app.Map("/login", signinApp =>
+            {
+                signinApp.Run(async context =>
+                {
+                    var authType = context.Request.Query["authscheme"];
+                    if (!string.IsNullOrEmpty(authType))
+                    {
+                        // By default the client will be redirect back to the URL that issued the challenge (/login?authtype=foo),
+                        // send them to the home page instead (/).
+                        await context.ChallengeAsync(authType, new AuthenticationProperties() { RedirectUri = "/" });
+                        return;
+                    }
+
+                    var response = context.Response;
+                    response.ContentType = "text/html";
+                    await response.WriteAsync("<html><body>");
+                    await response.WriteAsync("Choose an authentication scheme: <br>");
+                    var schemeProvider = context.RequestServices.GetRequiredService<IAuthenticationSchemeProvider>();
+                    foreach (var provider in await schemeProvider.GetAllSchemesAsync())
+                    {
+                        await response.WriteAsync("<a href=\"?authscheme=" + provider.Name + "\">" + (provider.DisplayName ?? "(suppressed)") + "</a><br>");
+                    }
+                    await response.WriteAsync("</body></html>");
+                });
+            });
+
+            // Refresh the access token
+            app.Map("/refresh_token", signinApp =>
+            {
+                signinApp.Run(async context =>
+                {
+                    var response = context.Response;
+
+                    // Setting DefaultAuthenticateScheme causes User to be set
+                    // var user = context.User;
+
+                    // This is what [Authorize] calls
+                    var userResult = await context.AuthenticateAsync();
+                    var user = userResult.Principal;
+                    var authProperties = userResult.Properties;
+
+                    // This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls
+                    // var user = await context.AuthenticateAsync(MicrosoftAccountDefaults.AuthenticationScheme);
+
+                    // Deny anonymous request beyond this point.
+                    if (!userResult.Succeeded || user == null || !user.Identities.Any(identity => identity.IsAuthenticated))
+                    {
+                        // This is what [Authorize] calls
+                        // The cookie middleware will handle this and redirect to /login
+                        await context.ChallengeAsync();
+
+                        // This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls
+                        // await context.ChallengeAsync(MicrosoftAccountDefaults.AuthenticationScheme);
+
+                        return;
+                    }
+
+                    var currentAuthType = user.Identities.First().AuthenticationType;
+                    if (string.Equals(GoogleDefaults.AuthenticationScheme, currentAuthType)
+                        || string.Equals(MicrosoftAccountDefaults.AuthenticationScheme, currentAuthType))
+                    {
+                        var refreshToken = authProperties.GetTokenValue("refresh_token");
+
+                        if (string.IsNullOrEmpty(refreshToken))
+                        {
+                            response.ContentType = "text/html";
+                            await response.WriteAsync("<html><body>");
+                            await response.WriteAsync("No refresh_token is available.<br>");
+                            await response.WriteAsync("<a href=\"/\">Home</a>");
+                            await response.WriteAsync("</body></html>");
+                            return;
+                        }
+
+                        var options = await GetOAuthOptionsAsync(context, currentAuthType);
+
+                        var pairs = new Dictionary<string, string>()
+                        {
+                            { "client_id", options.ClientId },
+                            { "client_secret", options.ClientSecret },
+                            { "grant_type", "refresh_token" },
+                            { "refresh_token", refreshToken }
+                        };
+                        var content = new FormUrlEncodedContent(pairs);
+                        var refreshResponse = await options.Backchannel.PostAsync(options.TokenEndpoint, content, context.RequestAborted);
+                        refreshResponse.EnsureSuccessStatusCode();
+
+                        var payload = JObject.Parse(await refreshResponse.Content.ReadAsStringAsync());
+
+                        // Persist the new acess token
+                        authProperties.UpdateTokenValue("access_token", payload.Value<string>("access_token"));
+                        refreshToken = payload.Value<string>("refresh_token");
+                        if (!string.IsNullOrEmpty(refreshToken))
+                        {
+                            authProperties.UpdateTokenValue("refresh_token", refreshToken);
+                        }
+                        if (int.TryParse(payload.Value<string>("expires_in"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var seconds))
+                        {
+                            var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
+                            authProperties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
+                        }
+                        await context.SignInAsync(user, authProperties);
+
+                        await PrintRefreshedTokensAsync(response, payload, authProperties);
+
+                        return;
+                    }
+                    // https://developers.facebook.com/docs/facebook-login/access-tokens/expiration-and-extension
+                    else if (string.Equals(FacebookDefaults.AuthenticationScheme, currentAuthType))
+                    {
+                        var options = await GetOAuthOptionsAsync(context, currentAuthType);
+
+                        var accessToken = authProperties.GetTokenValue("access_token");
+
+                        var query = new QueryBuilder()
+                        {
+                            { "grant_type", "fb_exchange_token" },
+                            { "client_id", options.ClientId },
+                            { "client_secret", options.ClientSecret },
+                            { "fb_exchange_token", accessToken },
+                        }.ToQueryString();
+
+                        var refreshResponse = await options.Backchannel.GetStringAsync(options.TokenEndpoint + query);
+                        var payload = JObject.Parse(refreshResponse);
+
+                        authProperties.UpdateTokenValue("access_token", payload.Value<string>("access_token"));
+                        if (int.TryParse(payload.Value<string>("expires_in"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var seconds))
+                        {
+                            var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
+                            authProperties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
+                        }
+                        await context.SignInAsync(user, authProperties);
+
+                        await PrintRefreshedTokensAsync(response, payload, authProperties);
+
+                        return;
+                    }
+
+                    response.ContentType = "text/html";
+                    await response.WriteAsync("<html><body>");
+                    await response.WriteAsync("Refresh has not been implemented for this provider.<br>");
+                    await response.WriteAsync("<a href=\"/\">Home</a>");
+                    await response.WriteAsync("</body></html>");
+                });
+            });
+
+            // Sign-out to remove the user cookie.
+            app.Map("/logout", signoutApp =>
+            {
+                signoutApp.Run(async context =>
+                {
+                    var response = context.Response;
+                    response.ContentType = "text/html";
+                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+                    await response.WriteAsync("<html><body>");
+                    await response.WriteAsync("You have been logged out. Goodbye " + context.User.Identity.Name + "<br>");
+                    await response.WriteAsync("<a href=\"/\">Home</a>");
+                    await response.WriteAsync("</body></html>");
+                });
+            });
+
+            // Display the remote error
+            app.Map("/error", errorApp =>
+            {
+                errorApp.Run(async context =>
+                {
+                    var response = context.Response;
+                    response.ContentType = "text/html";
+                    await response.WriteAsync("<html><body>");
+                    await response.WriteAsync("An remote failure has occurred: " + context.Request.Query["FailureMessage"] + "<br>");
+                    await response.WriteAsync("<a href=\"/\">Home</a>");
+                    await response.WriteAsync("</body></html>");
+                });
+            });
+
+
+            app.Run(async context =>
+            {
+                // Setting DefaultAuthenticateScheme causes User to be set
+                var user = context.User;
+
+                // This is what [Authorize] calls
+                // var user = await context.AuthenticateAsync();
+
+                // This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls
+                // var user = await context.AuthenticateAsync(MicrosoftAccountDefaults.AuthenticationScheme);
+
+                // Deny anonymous request beyond this point.
+                if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated))
+                {
+                    // This is what [Authorize] calls
+                    // The cookie middleware will handle this and redirect to /login
+                    await context.ChallengeAsync();
+
+                    // This is what [Authorize(ActiveAuthenticationSchemes = MicrosoftAccountDefaults.AuthenticationScheme)] calls
+                    // await context.ChallengeAsync(MicrosoftAccountDefaults.AuthenticationScheme);
+
+                    return;
+                }
+
+                // Display user information
+                var response = context.Response;
+                response.ContentType = "text/html";
+                await response.WriteAsync("<html><body>");
+                await response.WriteAsync("Hello " + (context.User.Identity.Name ?? "anonymous") + "<br>");
+                foreach (var claim in context.User.Claims)
+                {
+                    await response.WriteAsync(claim.Type + ": " + claim.Value + "<br>");
+                }
+
+                await response.WriteAsync("Tokens:<br>");
+
+                await response.WriteAsync("Access Token: " + await context.GetTokenAsync("access_token") + "<br>");
+                await response.WriteAsync("Refresh Token: " + await context.GetTokenAsync("refresh_token") + "<br>");
+                await response.WriteAsync("Token Type: " + await context.GetTokenAsync("token_type") + "<br>");
+                await response.WriteAsync("expires_at: " + await context.GetTokenAsync("expires_at") + "<br>");
+                await response.WriteAsync("<a href=\"/logout\">Logout</a><br>");
+                await response.WriteAsync("<a href=\"/refresh_token\">Refresh Token</a><br>");
+                await response.WriteAsync("</body></html>");
+            });
+        }
+
+        private Task<OAuthOptions> GetOAuthOptionsAsync(HttpContext context, string currentAuthType)
+        {
+            if (string.Equals(GoogleDefaults.AuthenticationScheme, currentAuthType))
+            {
+                return Task.FromResult<OAuthOptions>(context.RequestServices.GetRequiredService<IOptionsMonitor<GoogleOptions>>().Get(currentAuthType));
+            }
+            else if (string.Equals(MicrosoftAccountDefaults.AuthenticationScheme, currentAuthType))
+            {
+                return Task.FromResult<OAuthOptions>(context.RequestServices.GetRequiredService<IOptionsMonitor<MicrosoftAccountOptions>>().Get(currentAuthType));
+            }
+            else if (string.Equals(FacebookDefaults.AuthenticationScheme, currentAuthType))
+            {
+                return Task.FromResult<OAuthOptions>(context.RequestServices.GetRequiredService<IOptionsMonitor<FacebookOptions>>().Get(currentAuthType));
+            }
+
+            throw new NotImplementedException(currentAuthType);
+        }
+
+        private async Task PrintRefreshedTokensAsync(HttpResponse response, JObject payload, AuthenticationProperties authProperties)
+        {
+            response.ContentType = "text/html";
+            await response.WriteAsync("<html><body>");
+            await response.WriteAsync("Refreshed.<br>");
+            await response.WriteAsync(HtmlEncoder.Default.Encode(payload.ToString()).Replace(",", ",<br>") + "<br>");
+
+            await response.WriteAsync("<br>Tokens:<br>");
+
+            await response.WriteAsync("Access Token: " + authProperties.GetTokenValue("access_token") + "<br>");
+            await response.WriteAsync("Refresh Token: " + authProperties.GetTokenValue("refresh_token") + "<br>");
+            await response.WriteAsync("Token Type: " + authProperties.GetTokenValue("token_type") + "<br>");
+            await response.WriteAsync("expires_at: " + authProperties.GetTokenValue("expires_at") + "<br>");
+
+            await response.WriteAsync("<a href=\"/\">Home</a><br>");
+            await response.WriteAsync("<a href=\"/refresh_token\">Refresh Token</a><br>");
+            await response.WriteAsync("</body></html>");
+        }
+    }
+}
+

BIN
src/Security/samples/SocialSample/compiler/resources/cert.pfx


+ 9 - 0
src/Security/samples/SocialSample/web.config

@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<configuration>
+  <system.webServer>
+    <handlers>
+      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
+    </handlers>
+    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" />
+  </system.webServer>
+</configuration>

+ 64 - 0
src/Security/samples/WsFedSample/Program.cs

@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.FileProviders;
+using Microsoft.Extensions.Logging;
+
+namespace WsFedSample
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            var host = new WebHostBuilder()
+                .ConfigureLogging(factory =>
+                {
+                    factory.AddConsole();
+                    factory.AddDebug();
+                    factory.AddFilter("Console", level => level >= LogLevel.Information);
+                    factory.AddFilter("Debug", level => level >= LogLevel.Information);
+                })
+                .UseKestrel(options =>
+                {
+                    options.Listen(IPAddress.Loopback, 44307, listenOptions =>
+                    {
+                        // Configure SSL
+                        var serverCertificate = LoadCertificate();
+                        listenOptions.UseHttps(serverCertificate);
+                    });
+                })
+                .UseContentRoot(Directory.GetCurrentDirectory())
+                .UseIISIntegration()
+                .UseStartup<Startup>()
+                .Build();
+
+            host.Run();
+        }
+
+        private static X509Certificate2 LoadCertificate()
+        {
+            var assembly = typeof(Startup).GetTypeInfo().Assembly;
+            var embeddedFileProvider = new EmbeddedFileProvider(assembly, "WsFedSample");
+            var certificateFileInfo = embeddedFileProvider.GetFileInfo("compiler/resources/cert.pfx");
+            using (var certificateStream = certificateFileInfo.CreateReadStream())
+            {
+                byte[] certificatePayload;
+                using (var memoryStream = new MemoryStream())
+                {
+                    certificateStream.CopyTo(memoryStream);
+                    certificatePayload = memoryStream.ToArray();
+                }
+
+                return new X509Certificate2(certificatePayload, "testPassword");
+            }
+        }
+    }
+}

+ 28 - 0
src/Security/samples/WsFedSample/Properties/launchSettings.json

@@ -0,0 +1,28 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "https://localhost:44307/",
+      "sslPort": 44318
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "https://localhost:44307/",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "WsFedSample": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "applicationUrl": "https://localhost:44307/",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 168 - 0
src/Security/samples/WsFedSample/Startup.cs

@@ -0,0 +1,168 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authentication.WsFederation;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace WsFedSample
+{
+    public class Startup
+    {
+        public Startup(IConfiguration configuration)
+        {
+            Configuration = configuration;
+        }
+
+        public IConfiguration Configuration { get; }
+
+        // This method gets called by the runtime. Use this method to add services to the container.
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.AddAuthentication(sharedOptions =>
+            {
+                sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+                sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+                sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
+            })
+            .AddWsFederation(options =>
+            {
+                options.Wtrealm = "https://Tratcheroutlook.onmicrosoft.com/WsFedSample";
+                options.MetadataAddress = "https://login.windows.net/cdc690f9-b6b8-4023-813a-bae7143d1f87/FederationMetadata/2007-06/FederationMetadata.xml";
+                // options.CallbackPath = "/";
+                // options.SkipUnrecognizedRequests = true;
+            })
+            .AddCookie();
+        }
+
+        public void Configure(IApplicationBuilder app)
+        {
+            app.UseDeveloperExceptionPage();
+            app.UseAuthentication();
+
+            app.Run(async context =>
+            {
+                if (context.Request.Path.Equals("/signedout"))
+                {
+                    await WriteHtmlAsync(context.Response, async res =>
+                    {
+                        await res.WriteAsync($"<h1>You have been signed out.</h1>");
+                        await res.WriteAsync("<a class=\"btn btn-link\" href=\"/\">Sign In</a>");
+                    });
+                    return;
+                }
+
+                if (context.Request.Path.Equals("/signout"))
+                {
+                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+                    await WriteHtmlAsync(context.Response, async res =>
+                    {
+                        await context.Response.WriteAsync($"<h1>Signed out {HtmlEncode(context.User.Identity.Name)}</h1>");
+                        await context.Response.WriteAsync("<a class=\"btn btn-link\" href=\"/\">Sign In</a>");
+                    });
+                    return;
+                }
+
+                if (context.Request.Path.Equals("/signout-remote"))
+                {
+                    // Redirects
+                    await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+                    await context.SignOutAsync(WsFederationDefaults.AuthenticationScheme, new AuthenticationProperties()
+                    {
+                        RedirectUri = "/signedout"
+                    });
+                    return;
+                }
+
+                if (context.Request.Path.Equals("/Account/AccessDenied"))
+                {
+                    await WriteHtmlAsync(context.Response, async res =>
+                    {
+                        await context.Response.WriteAsync($"<h1>Access Denied for user {HtmlEncode(context.User.Identity.Name)} to resource '{HtmlEncode(context.Request.Query["ReturnUrl"])}'</h1>");
+                        await context.Response.WriteAsync("<a class=\"btn btn-link\" href=\"/signout\">Sign Out</a>");
+                    });
+                    return;
+                }
+
+                // DefaultAuthenticateScheme causes User to be set
+                var user = context.User;
+
+                // This is what [Authorize] calls
+                // var user = await context.AuthenticateAsync();
+
+                // This is what [Authorize(ActiveAuthenticationSchemes = WsFederationDefaults.AuthenticationScheme)] calls
+                // var user = await context.AuthenticateAsync(WsFederationDefaults.AuthenticationScheme);
+
+                // Not authenticated
+                if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated))
+                {
+                    // This is what [Authorize] calls
+                    await context.ChallengeAsync();
+
+                    // This is what [Authorize(ActiveAuthenticationSchemes = WsFederationDefaults.AuthenticationScheme)] calls
+                    // await context.ChallengeAsync(WsFederationDefaults.AuthenticationScheme);
+
+                    return;
+                }
+
+                // Authenticated, but not authorized
+                if (context.Request.Path.Equals("/restricted") && !user.Identities.Any(identity => identity.HasClaim("special", "true")))
+                {
+                    await context.ForbidAsync();
+                    return;
+                }
+
+                await WriteHtmlAsync(context.Response, async response =>
+                {
+                    await response.WriteAsync($"<h1>Hello Authenticated User {HtmlEncode(user.Identity.Name)}</h1>");
+                    await response.WriteAsync("<a class=\"btn btn-default\" href=\"/restricted\">Restricted</a>");
+                    await response.WriteAsync("<a class=\"btn btn-default\" href=\"/signout\">Sign Out</a>");
+                    await response.WriteAsync("<a class=\"btn btn-default\" href=\"/signout-remote\">Sign Out Remote</a>");
+
+                    await response.WriteAsync("<h2>Claims:</h2>");
+                    await WriteTableHeader(response, new string[] { "Claim Type", "Value" }, context.User.Claims.Select(c => new string[] { c.Type, c.Value }));
+                });
+            });
+        }
+
+        private static async Task WriteHtmlAsync(HttpResponse response, Func<HttpResponse, Task> writeContent)
+        {
+            var bootstrap = "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u\" crossorigin=\"anonymous\">";
+
+            response.ContentType = "text/html";
+            await response.WriteAsync($"<html><head>{bootstrap}</head><body><div class=\"container\">");
+            await writeContent(response);
+            await response.WriteAsync("</div></body></html>");
+        }
+
+        private static async Task WriteTableHeader(HttpResponse response, IEnumerable<string> columns, IEnumerable<IEnumerable<string>> data)
+        {
+            await response.WriteAsync("<table class=\"table table-condensed\">");
+            await response.WriteAsync("<tr>");
+            foreach (var column in columns)
+            {
+                await response.WriteAsync($"<th>{HtmlEncode(column)}</th>");
+            }
+            await response.WriteAsync("</tr>");
+            foreach (var row in data)
+            {
+                await response.WriteAsync("<tr>");
+                foreach (var column in row)
+                {
+                    await response.WriteAsync($"<td>{HtmlEncode(column)}</td>");
+                }
+                await response.WriteAsync("</tr>");
+            }
+            await response.WriteAsync("</table>");
+        }
+
+        private static string HtmlEncode(string content) =>
+            string.IsNullOrEmpty(content) ? string.Empty : HtmlEncoder.Default.Encode(content);
+    }
+}

+ 27 - 0
src/Security/samples/WsFedSample/WsFedSample.csproj

@@ -0,0 +1,27 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.Cookies\Microsoft.AspNetCore.Authentication.Cookies.csproj" />
+    <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Authentication.WsFederation\Microsoft.AspNetCore.Authentication.WsFederation.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="$(MicrosoftAspNetCoreServerKestrelHttpsPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion)" />
+    <PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(MicrosoftExtensionsFileProvidersEmbeddedPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsolePackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="$(MicrosoftExtensionsLoggingDebugPackageVersion)" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <EmbeddedResource Include="compiler\resources\cert.pfx" />
+  </ItemGroup>
+
+</Project>

BIN
src/Security/samples/WsFedSample/compiler/resources/cert.pfx


+ 309 - 0
src/Security/shared/Microsoft.AspNetCore.ChunkingCookieManager.Sources/ChunkingCookieManager.cs

@@ -0,0 +1,309 @@
+// 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 System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Primitives;
+using Microsoft.Net.Http.Headers;
+
+// Keep the type public for Security repo as it would be a breaking change to change the accessor now.
+// Make this type internal for other repos as it could be used by multiple projects and having it public causes type conflicts.
+#if SECURITY
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    /// <summary>
+    /// This handles cookies that are limited by per cookie length. It breaks down long cookies for responses, and reassembles them
+    /// from requests.
+    /// </summary>
+    public class ChunkingCookieManager : ICookieManager
+    {
+#else
+namespace Microsoft.AspNetCore.Internal
+{
+    /// <summary>
+    /// This handles cookies that are limited by per cookie length. It breaks down long cookies for responses, and reassembles them
+    /// from requests.
+    /// </summary>
+    internal class ChunkingCookieManager
+    {
+#endif
+        /// <summary>
+        /// The default maximum size of characters in a cookie to send back to the client.
+        /// </summary>
+        public const int DefaultChunkSize = 4050;
+
+        private const string ChunkKeySuffix = "C";
+        private const string ChunkCountPrefix = "chunks-";
+
+        public ChunkingCookieManager()
+        {
+            // Lowest common denominator. Safari has the lowest known limit (4093), and we leave little extra just in case.
+            // See http://browsercookielimits.x64.me/.
+            // Leave at least 40 in case CookiePolicy tries to add 'secure', 'samesite=strict' and/or 'httponly'.
+            ChunkSize = DefaultChunkSize;
+        }
+
+        /// <summary>
+        /// The maximum size of cookie to send back to the client. If a cookie exceeds this size it will be broken down into multiple
+        /// cookies. Set this value to null to disable this behavior. The default is 4090 characters, which is supported by all
+        /// common browsers.
+        ///
+        /// Note that browsers may also have limits on the total size of all cookies per domain, and on the number of cookies per domain.
+        /// </summary>
+        public int? ChunkSize { get; set; }
+
+        /// <summary>
+        /// Throw if not all chunks of a cookie are available on a request for re-assembly.
+        /// </summary>
+        public bool ThrowForPartialCookies { get; set; }
+
+        // Parse the "chunks-XX" to determine how many chunks there should be.
+        private static int ParseChunksCount(string value)
+        {
+            if (value != null && value.StartsWith(ChunkCountPrefix, StringComparison.Ordinal))
+            {
+                var chunksCountString = value.Substring(ChunkCountPrefix.Length);
+                int chunksCount;
+                if (int.TryParse(chunksCountString, NumberStyles.None, CultureInfo.InvariantCulture, out chunksCount))
+                {
+                    return chunksCount;
+                }
+            }
+            return 0;
+        }
+
+        /// <summary>
+        /// Get the reassembled cookie. Non chunked cookies are returned normally.
+        /// Cookies with missing chunks just have their "chunks-XX" header returned.
+        /// </summary>
+        /// <param name="context"></param>
+        /// <param name="key"></param>
+        /// <returns>The reassembled cookie, if any, or null.</returns>
+        public string GetRequestCookie(HttpContext context, string key)
+        {
+            if (context == null)
+            {
+                throw new ArgumentNullException(nameof(context));
+            }
+
+            if (key == null)
+            {
+                throw new ArgumentNullException(nameof(key));
+            }
+
+            var requestCookies = context.Request.Cookies;
+            var value = requestCookies[key];
+            var chunksCount = ParseChunksCount(value);
+            if (chunksCount > 0)
+            {
+                var chunks = new string[chunksCount];
+                for (var chunkId = 1; chunkId <= chunksCount; chunkId++)
+                {
+                    var chunk = requestCookies[key + ChunkKeySuffix + chunkId.ToString(CultureInfo.InvariantCulture)];
+                    if (string.IsNullOrEmpty(chunk))
+                    {
+                        if (ThrowForPartialCookies)
+                        {
+                            var totalSize = 0;
+                            for (int i = 0; i < chunkId - 1; i++)
+                            {
+                                totalSize += chunks[i].Length;
+                            }
+                            throw new FormatException(
+                                string.Format(
+                                    CultureInfo.CurrentCulture,
+                                    "The chunked cookie is incomplete. Only {0} of the expected {1} chunks were found, totaling {2} characters. A client size limit may have been exceeded.",
+                                    chunkId - 1,
+                                    chunksCount,
+                                    totalSize));
+                        }
+                        // Missing chunk, abort by returning the original cookie value. It may have been a false positive?
+                        return value;
+                    }
+
+                    chunks[chunkId - 1] = chunk;
+                }
+
+                return string.Join(string.Empty, chunks);
+            }
+            return value;
+        }
+
+        /// <summary>
+        /// Appends a new response cookie to the Set-Cookie header. If the cookie is larger than the given size limit
+        /// then it will be broken down into multiple cookies as follows:
+        /// Set-Cookie: CookieName=chunks-3; path=/
+        /// Set-Cookie: CookieNameC1=Segment1; path=/
+        /// Set-Cookie: CookieNameC2=Segment2; path=/
+        /// Set-Cookie: CookieNameC3=Segment3; path=/
+        /// </summary>
+        /// <param name="context"></param>
+        /// <param name="key"></param>
+        /// <param name="value"></param>
+        /// <param name="options"></param>
+        public void AppendResponseCookie(HttpContext context, string key, string value, CookieOptions options)
+        {
+            if (context == null)
+            {
+                throw new ArgumentNullException(nameof(context));
+            }
+
+            if (key == null)
+            {
+                throw new ArgumentNullException(nameof(key));
+            }
+
+            if (options == null)
+            {
+                throw new ArgumentNullException(nameof(options));
+            }
+
+            var template = new SetCookieHeaderValue(key)
+            {
+                Domain = options.Domain,
+                Expires = options.Expires,
+                SameSite = (Net.Http.Headers.SameSiteMode)options.SameSite,
+                HttpOnly = options.HttpOnly,
+                Path = options.Path,
+                Secure = options.Secure,
+            };
+
+            var templateLength = template.ToString().Length;
+
+            value = value ?? string.Empty;
+
+            // Normal cookie
+            var responseCookies = context.Response.Cookies;
+            if (!ChunkSize.HasValue || ChunkSize.Value > templateLength + value.Length)
+            {
+                responseCookies.Append(key, value, options);
+            }
+            else if (ChunkSize.Value < templateLength + 10)
+            {
+                // 10 is the minimum data we want to put in an individual cookie, including the cookie chunk identifier "CXX".
+                // No room for data, we can't chunk the options and name
+                throw new InvalidOperationException("The cookie key and options are larger than ChunksSize, leaving no room for data.");
+            }
+            else
+            {
+                // Break the cookie down into multiple cookies.
+                // Key = CookieName, value = "Segment1Segment2Segment2"
+                // Set-Cookie: CookieName=chunks-3; path=/
+                // Set-Cookie: CookieNameC1="Segment1"; path=/
+                // Set-Cookie: CookieNameC2="Segment2"; path=/
+                // Set-Cookie: CookieNameC3="Segment3"; path=/
+                var dataSizePerCookie = ChunkSize.Value - templateLength - 3; // Budget 3 chars for the chunkid.
+                var cookieChunkCount = (int)Math.Ceiling(value.Length * 1.0 / dataSizePerCookie);
+
+                responseCookies.Append(key, ChunkCountPrefix + cookieChunkCount.ToString(CultureInfo.InvariantCulture), options);
+
+                var offset = 0;
+                for (var chunkId = 1; chunkId <= cookieChunkCount; chunkId++)
+                {
+                    var remainingLength = value.Length - offset;
+                    var length = Math.Min(dataSizePerCookie, remainingLength);
+                    var segment = value.Substring(offset, length);
+                    offset += length;
+
+                    responseCookies.Append(key + ChunkKeySuffix + chunkId.ToString(CultureInfo.InvariantCulture), segment, options);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Deletes the cookie with the given key by setting an expired state. If a matching chunked cookie exists on
+        /// the request, delete each chunk.
+        /// </summary>
+        /// <param name="context"></param>
+        /// <param name="key"></param>
+        /// <param name="options"></param>
+        public void DeleteCookie(HttpContext context, string key, CookieOptions options)
+        {
+            if (context == null)
+            {
+                throw new ArgumentNullException(nameof(context));
+            }
+
+            if (key == null)
+            {
+                throw new ArgumentNullException(nameof(key));
+            }
+
+            if (options == null)
+            {
+                throw new ArgumentNullException(nameof(options));
+            }
+
+            var keys = new List<string>();
+            keys.Add(key + "=");
+
+            var requestCookie = context.Request.Cookies[key];
+            var chunks = ParseChunksCount(requestCookie);
+            if (chunks > 0)
+            {
+                for (int i = 1; i <= chunks + 1; i++)
+                {
+                    var subkey = key + ChunkKeySuffix + i.ToString(CultureInfo.InvariantCulture);
+                    keys.Add(subkey + "=");
+                }
+            }
+
+            var domainHasValue = !string.IsNullOrEmpty(options.Domain);
+            var pathHasValue = !string.IsNullOrEmpty(options.Path);
+
+            Func<string, bool> rejectPredicate;
+            Func<string, bool> predicate = value => keys.Any(k => value.StartsWith(k, StringComparison.OrdinalIgnoreCase));
+            if (domainHasValue)
+            {
+                rejectPredicate = value => predicate(value) && value.IndexOf("domain=" + options.Domain, StringComparison.OrdinalIgnoreCase) != -1;
+            }
+            else if (pathHasValue)
+            {
+                rejectPredicate = value => predicate(value) && value.IndexOf("path=" + options.Path, StringComparison.OrdinalIgnoreCase) != -1;
+            }
+            else
+            {
+                rejectPredicate = value => predicate(value);
+            }
+
+            var responseHeaders = context.Response.Headers;
+            var existingValues = responseHeaders[HeaderNames.SetCookie];
+            if (!StringValues.IsNullOrEmpty(existingValues))
+            {
+                responseHeaders[HeaderNames.SetCookie] = existingValues.Where(value => !rejectPredicate(value)).ToArray();
+            }
+
+            AppendResponseCookie(
+                context,
+                key,
+                string.Empty,
+                new CookieOptions()
+                {
+                    Path = options.Path,
+                    Domain = options.Domain,
+                    SameSite = options.SameSite,
+                    IsEssential = options.IsEssential,
+                    Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
+                });
+
+            for (int i = 1; i <= chunks; i++)
+            {
+                AppendResponseCookie(
+                    context,
+                    key + "C" + i.ToString(CultureInfo.InvariantCulture),
+                    string.Empty,
+                    new CookieOptions()
+                    {
+                        Path = options.Path,
+                        Domain = options.Domain,
+                        SameSite = options.SameSite,
+                        IsEssential = options.IsEssential,
+                        Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
+                    });
+            }
+        }
+    }
+}

+ 7 - 0
src/Security/src/Directory.Build.props

@@ -0,0 +1,7 @@
+<Project>
+  <Import Project="..\Directory.Build.props" />
+
+  <ItemGroup>
+    <PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
+  </ItemGroup>
+</Project>

+ 13 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Constants.cs

@@ -0,0 +1,13 @@
+// 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.
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    internal static class Constants
+    {
+        internal static class Headers
+        {
+            internal const string SetCookie = "Set-Cookie";
+        }
+    }
+}

+ 37 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAppBuilderExtensions.cs

@@ -0,0 +1,37 @@
+// 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 Microsoft.AspNetCore.Authentication.Cookies;
+
+namespace Microsoft.AspNetCore.Builder
+{
+    /// <summary>
+    /// Extension methods to add cookie authentication capabilities to an HTTP application pipeline.
+    /// </summary>
+    public static class CookieAppBuilderExtensions
+    {
+        /// <summary>
+        /// UseCookieAuthentication is obsolete. Configure Cookie authentication with AddAuthentication().AddCookie in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
+        /// </summary>
+        /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
+        /// <returns>A reference to this instance after the operation has completed.</returns>
+        [Obsolete("UseCookieAuthentication is obsolete. Configure Cookie authentication with AddAuthentication().AddCookie in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
+        public static IApplicationBuilder UseCookieAuthentication(this IApplicationBuilder app)
+        {
+            throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
+        }
+
+        /// <summary>
+        /// UseCookieAuthentication is obsolete. Configure Cookie authentication with AddAuthentication().AddCookie in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
+        /// </summary>
+        /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
+        /// <param name="options">A <see cref="CookieAuthenticationOptions"/> that specifies options for the handler.</param>
+        /// <returns>A reference to this instance after the operation has completed.</returns>
+        [Obsolete("UseCookieAuthentication is obsolete. Configure Cookie authentication with AddAuthentication().AddCookie in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
+        public static IApplicationBuilder UseCookieAuthentication(this IApplicationBuilder app, CookieAuthenticationOptions options)
+        {
+            throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
+        }
+    }
+}

+ 46 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationDefaults.cs

@@ -0,0 +1,46 @@
+// 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 Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    /// <summary>
+    /// Default values related to cookie-based authentication handler
+    /// </summary>
+    public static class CookieAuthenticationDefaults
+    {
+        /// <summary>
+        /// The default value used for CookieAuthenticationOptions.AuthenticationScheme
+        /// </summary>
+        public const string AuthenticationScheme = "Cookies";
+
+        /// <summary>
+        /// The prefix used to provide a default CookieAuthenticationOptions.CookieName
+        /// </summary>
+        public static readonly string CookiePrefix = ".AspNetCore.";
+
+        /// <summary>
+        /// The default value used by CookieAuthenticationMiddleware for the
+        /// CookieAuthenticationOptions.LoginPath
+        /// </summary>
+        public static readonly PathString LoginPath = new PathString("/Account/Login");
+
+        /// <summary>
+        /// The default value used by CookieAuthenticationMiddleware for the
+        /// CookieAuthenticationOptions.LogoutPath
+        /// </summary>
+        public static readonly PathString LogoutPath = new PathString("/Account/Logout");
+
+        /// <summary>
+        /// The default value used by CookieAuthenticationMiddleware for the
+        /// CookieAuthenticationOptions.AccessDeniedPath
+        /// </summary>
+        public static readonly PathString AccessDeniedPath = new PathString("/Account/AccessDenied");
+
+        /// <summary>
+        /// The default value of the CookieAuthenticationOptions.ReturnUrlParameter
+        /// </summary>
+        public static readonly string ReturnUrlParameter = "ReturnUrl";
+    }
+}

+ 451 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationHandler.cs

@@ -0,0 +1,451 @@
+// 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 System.Linq;
+using System.Security.Claims;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Microsoft.Net.Http.Headers;
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    public class CookieAuthenticationHandler : SignInAuthenticationHandler<CookieAuthenticationOptions>
+    {
+        private const string HeaderValueNoCache = "no-cache";
+        private const string HeaderValueEpocDate = "Thu, 01 Jan 1970 00:00:00 GMT";
+        private const string SessionIdClaim = "Microsoft.AspNetCore.Authentication.Cookies-SessionId";
+
+        private bool _shouldRefresh;
+        private bool _signInCalled;
+        private bool _signOutCalled;
+
+        private DateTimeOffset? _refreshIssuedUtc;
+        private DateTimeOffset? _refreshExpiresUtc;
+        private string _sessionKey;
+        private Task<AuthenticateResult> _readCookieTask;
+        private AuthenticationTicket _refreshTicket;
+
+        public CookieAuthenticationHandler(IOptionsMonitor<CookieAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
+            : base(options, logger, encoder, clock)
+        { }
+
+        /// <summary>
+        /// The handler calls methods on the events which give the application control at certain points where processing is occurring.
+        /// If it is not provided a default instance is supplied which does nothing when the methods are called.
+        /// </summary>
+        protected new CookieAuthenticationEvents Events
+        {
+            get { return (CookieAuthenticationEvents)base.Events; }
+            set { base.Events = value; }
+        }
+
+        protected override Task InitializeHandlerAsync()
+        {
+            // Cookies needs to finish the response
+            Context.Response.OnStarting(FinishResponseAsync);
+            return Task.CompletedTask;
+        }
+
+        /// <summary>
+        /// Creates a new instance of the events instance.
+        /// </summary>
+        /// <returns>A new instance of the events instance.</returns>
+        protected override Task<object> CreateEventsAsync() => Task.FromResult<object>(new CookieAuthenticationEvents());
+
+        private Task<AuthenticateResult> EnsureCookieTicket()
+        {
+            // We only need to read the ticket once
+            if (_readCookieTask == null)
+            {
+                _readCookieTask = ReadCookieTicket();
+            }
+            return _readCookieTask;
+        }
+
+        private void CheckForRefresh(AuthenticationTicket ticket)
+        {
+            var currentUtc = Clock.UtcNow;
+            var issuedUtc = ticket.Properties.IssuedUtc;
+            var expiresUtc = ticket.Properties.ExpiresUtc;
+            var allowRefresh = ticket.Properties.AllowRefresh ?? true;
+            if (issuedUtc != null && expiresUtc != null && Options.SlidingExpiration && allowRefresh)
+            {
+                var timeElapsed = currentUtc.Subtract(issuedUtc.Value);
+                var timeRemaining = expiresUtc.Value.Subtract(currentUtc);
+
+                if (timeRemaining < timeElapsed)
+                {
+                    RequestRefresh(ticket);
+                }
+            }
+        }
+
+        private void RequestRefresh(AuthenticationTicket ticket, ClaimsPrincipal replacedPrincipal = null)
+        {
+            var issuedUtc = ticket.Properties.IssuedUtc;
+            var expiresUtc = ticket.Properties.ExpiresUtc;
+
+            if (issuedUtc != null && expiresUtc != null)
+            {
+                _shouldRefresh = true;
+                var currentUtc = Clock.UtcNow;
+                _refreshIssuedUtc = currentUtc;
+                var timeSpan = expiresUtc.Value.Subtract(issuedUtc.Value);
+                _refreshExpiresUtc = currentUtc.Add(timeSpan);
+                _refreshTicket = CloneTicket(ticket, replacedPrincipal);
+            }
+        }
+
+        private AuthenticationTicket CloneTicket(AuthenticationTicket ticket, ClaimsPrincipal replacedPrincipal)
+        {
+            var principal = replacedPrincipal ?? ticket.Principal;
+            var newPrincipal = new ClaimsPrincipal();
+            foreach (var identity in principal.Identities)
+            {
+                newPrincipal.AddIdentity(identity.Clone());
+            }
+
+            var newProperties = new AuthenticationProperties();
+            foreach (var item in ticket.Properties.Items)
+            {
+                newProperties.Items[item.Key] = item.Value;
+            }
+
+            return new AuthenticationTicket(newPrincipal, newProperties, ticket.AuthenticationScheme);
+        }
+
+        private async Task<AuthenticateResult> ReadCookieTicket()
+        {
+            var cookie = Options.CookieManager.GetRequestCookie(Context, Options.Cookie.Name);
+            if (string.IsNullOrEmpty(cookie))
+            {
+                return AuthenticateResult.NoResult();
+            }
+
+            var ticket = Options.TicketDataFormat.Unprotect(cookie, GetTlsTokenBinding());
+            if (ticket == null)
+            {
+                return AuthenticateResult.Fail("Unprotect ticket failed");
+            }
+
+            if (Options.SessionStore != null)
+            {
+                var claim = ticket.Principal.Claims.FirstOrDefault(c => c.Type.Equals(SessionIdClaim));
+                if (claim == null)
+                {
+                    return AuthenticateResult.Fail("SessionId missing");
+                }
+                _sessionKey = claim.Value;
+                ticket = await Options.SessionStore.RetrieveAsync(_sessionKey);
+                if (ticket == null)
+                {
+                    return AuthenticateResult.Fail("Identity missing in session store");
+                }
+            }
+
+            var currentUtc = Clock.UtcNow;
+            var expiresUtc = ticket.Properties.ExpiresUtc;
+
+            if (expiresUtc != null && expiresUtc.Value < currentUtc)
+            {
+                if (Options.SessionStore != null)
+                {
+                    await Options.SessionStore.RemoveAsync(_sessionKey);
+                }
+                return AuthenticateResult.Fail("Ticket expired");
+            }
+
+            CheckForRefresh(ticket);
+
+            // Finally we have a valid ticket
+            return AuthenticateResult.Success(ticket);
+        }
+
+        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
+        {
+            var result = await EnsureCookieTicket();
+            if (!result.Succeeded)
+            {
+                return result;
+            }
+
+            var context = new CookieValidatePrincipalContext(Context, Scheme, Options, result.Ticket);
+            await Events.ValidatePrincipal(context);
+
+            if (context.Principal == null)
+            {
+                return AuthenticateResult.Fail("No principal.");
+            }
+
+            if (context.ShouldRenew)
+            {
+                RequestRefresh(result.Ticket, context.Principal);
+            }
+
+            return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name));
+        }
+
+        private CookieOptions BuildCookieOptions()
+        {
+            var cookieOptions = Options.Cookie.Build(Context);
+            // ignore the 'Expires' value as this will be computed elsewhere
+            cookieOptions.Expires = null;
+
+            return cookieOptions;
+        }
+
+        protected virtual async Task FinishResponseAsync()
+        {
+            // Only renew if requested, and neither sign in or sign out was called
+            if (!_shouldRefresh || _signInCalled || _signOutCalled)
+            {
+                return;
+            }
+
+            var ticket = _refreshTicket;
+            if (ticket != null)
+            {
+                var properties = ticket.Properties;
+
+                if (_refreshIssuedUtc.HasValue)
+                {
+                    properties.IssuedUtc = _refreshIssuedUtc;
+                }
+
+                if (_refreshExpiresUtc.HasValue)
+                {
+                    properties.ExpiresUtc = _refreshExpiresUtc;
+                }
+
+                if (Options.SessionStore != null && _sessionKey != null)
+                {
+                    await Options.SessionStore.RenewAsync(_sessionKey, ticket);
+                    var principal = new ClaimsPrincipal(
+                        new ClaimsIdentity(
+                            new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
+                            Scheme.Name));
+                    ticket = new AuthenticationTicket(principal, null, Scheme.Name);
+                }
+
+                var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding());
+
+                var cookieOptions = BuildCookieOptions();
+                if (properties.IsPersistent && _refreshExpiresUtc.HasValue)
+                {
+                    cookieOptions.Expires = _refreshExpiresUtc.Value.ToUniversalTime();
+                }
+
+                Options.CookieManager.AppendResponseCookie(
+                    Context,
+                    Options.Cookie.Name,
+                    cookieValue,
+                    cookieOptions);
+
+                await ApplyHeaders(shouldRedirectToReturnUrl: false, properties: properties);
+            }
+        }
+
+        protected async override Task HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
+        {
+            if (user == null)
+            {
+                throw new ArgumentNullException(nameof(user));
+            }
+
+            properties = properties ?? new AuthenticationProperties();
+
+            _signInCalled = true;
+
+            // Process the request cookie to initialize members like _sessionKey.
+            await EnsureCookieTicket();
+            var cookieOptions = BuildCookieOptions();
+
+            var signInContext = new CookieSigningInContext(
+                Context,
+                Scheme,
+                Options,
+                user,
+                properties,
+                cookieOptions);
+
+            DateTimeOffset issuedUtc;
+            if (signInContext.Properties.IssuedUtc.HasValue)
+            {
+                issuedUtc = signInContext.Properties.IssuedUtc.Value;
+            }
+            else
+            {
+                issuedUtc = Clock.UtcNow;
+                signInContext.Properties.IssuedUtc = issuedUtc;
+            }
+
+            if (!signInContext.Properties.ExpiresUtc.HasValue)
+            {
+                signInContext.Properties.ExpiresUtc = issuedUtc.Add(Options.ExpireTimeSpan);
+            }
+
+            await Events.SigningIn(signInContext);
+
+            if (signInContext.Properties.IsPersistent)
+            {
+                var expiresUtc = signInContext.Properties.ExpiresUtc ?? issuedUtc.Add(Options.ExpireTimeSpan);
+                signInContext.CookieOptions.Expires = expiresUtc.ToUniversalTime();
+            }
+
+            var ticket = new AuthenticationTicket(signInContext.Principal, signInContext.Properties, signInContext.Scheme.Name);
+
+            if (Options.SessionStore != null)
+            {
+                if (_sessionKey != null)
+                {
+                    await Options.SessionStore.RemoveAsync(_sessionKey);
+                }
+                _sessionKey = await Options.SessionStore.StoreAsync(ticket);
+                var principal = new ClaimsPrincipal(
+                    new ClaimsIdentity(
+                        new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
+                        Options.ClaimsIssuer));
+                ticket = new AuthenticationTicket(principal, null, Scheme.Name);
+            }
+
+            var cookieValue = Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding());
+
+            Options.CookieManager.AppendResponseCookie(
+                Context,
+                Options.Cookie.Name,
+                cookieValue,
+                signInContext.CookieOptions);
+
+            var signedInContext = new CookieSignedInContext(
+                Context,
+                Scheme,
+                signInContext.Principal,
+                signInContext.Properties,
+                Options);
+
+            await Events.SignedIn(signedInContext);
+
+            // Only redirect on the login path
+            var shouldRedirect = Options.LoginPath.HasValue && OriginalPath == Options.LoginPath;
+            await ApplyHeaders(shouldRedirect, signedInContext.Properties);
+
+            Logger.SignedIn(Scheme.Name);
+        }
+
+        protected async override Task HandleSignOutAsync(AuthenticationProperties properties)
+        {
+            properties = properties ?? new AuthenticationProperties();
+
+            _signOutCalled = true;
+
+            // Process the request cookie to initialize members like _sessionKey.
+            await EnsureCookieTicket();
+            var cookieOptions = BuildCookieOptions();
+            if (Options.SessionStore != null && _sessionKey != null)
+            {
+                await Options.SessionStore.RemoveAsync(_sessionKey);
+            }
+
+            var context = new CookieSigningOutContext(
+                Context,
+                Scheme,
+                Options,
+                properties,
+                cookieOptions);
+
+            await Events.SigningOut(context);
+
+            Options.CookieManager.DeleteCookie(
+                Context,
+                Options.Cookie.Name,
+                context.CookieOptions);
+
+            // Only redirect on the logout path
+            var shouldRedirect = Options.LogoutPath.HasValue && OriginalPath == Options.LogoutPath;
+            await ApplyHeaders(shouldRedirect, context.Properties);
+
+            Logger.SignedOut(Scheme.Name);
+        }
+
+        private async Task ApplyHeaders(bool shouldRedirectToReturnUrl, AuthenticationProperties properties)
+        {
+            Response.Headers[HeaderNames.CacheControl] = HeaderValueNoCache;
+            Response.Headers[HeaderNames.Pragma] = HeaderValueNoCache;
+            Response.Headers[HeaderNames.Expires] = HeaderValueEpocDate;
+
+            if (shouldRedirectToReturnUrl && Response.StatusCode == 200)
+            {
+                // set redirect uri in order:
+                // 1. properties.RedirectUri
+                // 2. query parameter ReturnUrlParameter
+                //
+                // Absolute uri is not allowed if it is from query string as query string is not
+                // a trusted source.
+                var redirectUri = properties.RedirectUri;
+                if (string.IsNullOrEmpty(redirectUri))
+                {
+                    redirectUri = Request.Query[Options.ReturnUrlParameter];
+                    if (string.IsNullOrEmpty(redirectUri) || !IsHostRelative(redirectUri))
+                    {
+                        redirectUri = null;
+                    }
+                }
+
+                if (redirectUri != null)
+                {
+                    await Events.RedirectToReturnUrl(
+                        new RedirectContext<CookieAuthenticationOptions>(Context, Scheme, Options, properties, redirectUri));
+                }
+            }
+        }
+
+        private static bool IsHostRelative(string path)
+        {
+            if (string.IsNullOrEmpty(path))
+            {
+                return false;
+            }
+            if (path.Length == 1)
+            {
+                return path[0] == '/';
+            }
+            return path[0] == '/' && path[1] != '/' && path[1] != '\\';
+        }
+
+        protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
+        {
+            var returnUrl = properties.RedirectUri;
+            if (string.IsNullOrEmpty(returnUrl))
+            {
+                returnUrl = OriginalPathBase + Request.Path + Request.QueryString;
+            }
+            var accessDeniedUri = Options.AccessDeniedPath + QueryString.Create(Options.ReturnUrlParameter, returnUrl);
+            var redirectContext = new RedirectContext<CookieAuthenticationOptions>(Context, Scheme, Options, properties, BuildRedirectUri(accessDeniedUri));
+            await Events.RedirectToAccessDenied(redirectContext);
+        }
+
+        protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
+        {
+            var redirectUri = properties.RedirectUri;
+            if (string.IsNullOrEmpty(redirectUri))
+            {
+                redirectUri = OriginalPathBase + Request.Path + Request.QueryString;
+            }
+
+            var loginUri = Options.LoginPath + QueryString.Create(Options.ReturnUrlParameter, redirectUri);
+            var redirectContext = new RedirectContext<CookieAuthenticationOptions>(Context, Scheme, Options, properties, BuildRedirectUri(loginUri));
+            await Events.RedirectToLogin(redirectContext);
+        }
+
+        private string GetTlsTokenBinding()
+        {
+            var binding = Context.Features.Get<ITlsTokenBindingFeature>()?.GetProvidedTokenBindingId();
+            return binding == null ? null : Convert.ToBase64String(binding);
+        }
+    }
+}

+ 214 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationOptions.cs

@@ -0,0 +1,214 @@
+// 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 Microsoft.AspNetCore.Authentication.Internal;
+using Microsoft.AspNetCore.DataProtection;
+using Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    /// <summary>
+    /// Configuration options for <see cref="CookieAuthenticationOptions"/>.
+    /// </summary>
+    public class CookieAuthenticationOptions : AuthenticationSchemeOptions
+    {
+        private CookieBuilder _cookieBuilder = new RequestPathBaseCookieBuilder
+        {
+            // the default name is configured in PostConfigureCookieAuthenticationOptions
+
+            // To support OAuth authentication, a lax mode is required, see https://github.com/aspnet/Security/issues/1231.
+            SameSite = SameSiteMode.Lax,
+            HttpOnly = true,
+            SecurePolicy = CookieSecurePolicy.SameAsRequest,
+            IsEssential = true,
+        };
+
+        /// <summary>
+        /// Create an instance of the options initialized with the default values
+        /// </summary>
+        public CookieAuthenticationOptions()
+        {
+            ExpireTimeSpan = TimeSpan.FromDays(14);
+            ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
+            SlidingExpiration = true;
+            Events = new CookieAuthenticationEvents();
+        }
+
+        /// <summary>
+        /// <para>
+        /// Determines the settings used to create the cookie.
+        /// </para>
+        /// <para>
+        /// <seealso cref="CookieBuilder.SameSite"/> defaults to <see cref="SameSiteMode.Lax"/>.
+        /// <seealso cref="CookieBuilder.HttpOnly"/> defaults to <c>true</c>.
+        /// <seealso cref="CookieBuilder.SecurePolicy"/> defaults to <see cref="CookieSecurePolicy.SameAsRequest"/>.
+        /// </para>
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// The default value for cookie name is ".AspNetCore.Cookies".
+        /// This value should be changed if you change the name of the AuthenticationScheme, especially if your
+        /// system uses the cookie authentication handler multiple times.
+        /// </para>
+        /// <para>
+        /// <seealso cref="CookieBuilder.SameSite"/> determines if the browser should allow the cookie to be attached to same-site or cross-site requests.
+        /// The default is Lax, which means the cookie is only allowed to be attached to cross-site requests using safe HTTP methods and same-site requests.
+        /// </para>
+        /// <para>
+        /// <seealso cref="CookieBuilder.HttpOnly"/> determines if the browser should allow the cookie to be accessed by client-side javascript.
+        /// The default is true, which means the cookie will only be passed to http requests and is not made available to script on the page.
+        /// </para>
+        /// <para>
+        /// <seealso cref="CookieBuilder.Expiration"/> is currently ignored. Use <see cref="ExpireTimeSpan"/> to control lifetime of cookie authentication.
+        /// </para>
+        /// </remarks>
+        public CookieBuilder Cookie
+        {
+            get => _cookieBuilder;
+            set => _cookieBuilder = value ?? throw new ArgumentNullException(nameof(value));
+        }
+
+        /// <summary>
+        /// If set this will be used by the CookieAuthenticationHandler for data protection.
+        /// </summary>
+        public IDataProtectionProvider DataProtectionProvider { get; set; }
+
+        /// <summary>
+        /// The SlidingExpiration is set to true to instruct the handler to re-issue a new cookie with a new
+        /// expiration time any time it processes a request which is more than halfway through the expiration window.
+        /// </summary>
+        public bool SlidingExpiration { get; set; }
+
+        /// <summary>
+        /// The LoginPath property is used by the handler for the redirection target when handling ChallengeAsync.
+        /// The current url which is added to the LoginPath as a query string parameter named by the ReturnUrlParameter. 
+        /// Once a request to the LoginPath grants a new SignIn identity, the ReturnUrlParameter value is used to redirect 
+        /// the browser back to the original url.
+        /// </summary>
+        public PathString LoginPath { get; set; }
+
+        /// <summary>
+        /// If the LogoutPath is provided the handler then a request to that path will redirect based on the ReturnUrlParameter.
+        /// </summary>
+        public PathString LogoutPath { get; set; }
+
+        /// <summary>
+        /// The AccessDeniedPath property is used by the handler for the redirection target when handling ForbidAsync.
+        /// </summary>
+        public PathString AccessDeniedPath { get; set; }
+
+        /// <summary>
+        /// The ReturnUrlParameter determines the name of the query string parameter which is appended by the handler
+        /// when during a Challenge. This is also the query string parameter looked for when a request arrives on the 
+        /// login path or logout path, in order to return to the original url after the action is performed.
+        /// </summary>
+        public string ReturnUrlParameter { get; set; }
+
+        /// <summary>
+        /// The Provider may be assigned to an instance of an object created by the application at startup time. The handler
+        /// calls methods on the provider which give the application control at certain points where processing is occurring.
+        /// If it is not provided a default instance is supplied which does nothing when the methods are called.
+        /// </summary>
+        public new CookieAuthenticationEvents Events
+        {
+            get => (CookieAuthenticationEvents)base.Events;
+            set => base.Events = value;
+        }
+
+        /// <summary>
+        /// The TicketDataFormat is used to protect and unprotect the identity and other properties which are stored in the
+        /// cookie value. If not provided one will be created using <see cref="DataProtectionProvider"/>.
+        /// </summary>
+        public ISecureDataFormat<AuthenticationTicket> TicketDataFormat { get; set; }
+
+        /// <summary>
+        /// The component used to get cookies from the request or set them on the response.
+        ///
+        /// ChunkingCookieManager will be used by default.
+        /// </summary>
+        public ICookieManager CookieManager { get; set; }
+
+        /// <summary>
+        /// An optional container in which to store the identity across requests. When used, only a session identifier is sent
+        /// to the client. This can be used to mitigate potential problems with very large identities.
+        /// </summary>
+        public ITicketStore SessionStore { get; set; }
+
+        /// <summary>
+        /// <para>
+        /// Controls how much time the authentication ticket stored in the cookie will remain valid from the point it is created
+        /// The expiration information is stored in the protected cookie ticket. Because of that an expired cookie will be ignored
+        /// even if it is passed to the server after the browser should have purged it.
+        /// </para>
+        /// <para>
+        /// This is separate from the value of <seealso cref="CookieOptions.Expires"/>, which specifies
+        /// how long the browser will keep the cookie.
+        /// </para>
+        /// </summary>
+        public TimeSpan ExpireTimeSpan { get; set; }
+
+        #region Obsolete API
+        /// <summary>
+        /// <para>
+        /// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Name"/> on <see cref="Cookie"/>.
+        /// </para>
+        /// <para>
+        /// Determines the cookie name used to persist the identity. The default value is ".AspNetCore.Cookies".
+        /// This value should be changed if you change the name of the AuthenticationScheme, especially if your
+        /// system uses the cookie authentication handler multiple times.
+        /// </para>
+        /// </summary>
+        [Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Name) + ".")]
+        public string CookieName { get => Cookie.Name; set => Cookie.Name = value; }
+
+        /// <summary>
+        /// <para>
+        /// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Domain"/> on <see cref="Cookie"/>.
+        /// </para>
+        /// <para>
+        /// Determines the domain used to create the cookie. Is not provided by default.
+        /// </para>
+        /// </summary>
+        [Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Domain) + ".")]
+        public string CookieDomain { get => Cookie.Domain; set => Cookie.Domain = value; }
+
+        /// <summary>
+        /// <para>
+        /// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.Path"/> on <see cref="Cookie"/>.
+        /// </para>
+        /// <para>
+        /// Determines the path used to create the cookie. The default value is "/" for highest browser compatibility.
+        /// </para>
+        /// </summary>
+        [Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Path) + ".")]
+        public string CookiePath { get => Cookie.Path; set => Cookie.Path = value; }
+
+        /// <summary>
+        /// <para>
+        /// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.HttpOnly"/> on <see cref="Cookie"/>.
+        /// </para>
+        /// <para>
+        /// Determines if the browser should allow the cookie to be accessed by client-side javascript. The
+        /// default is true, which means the cookie will only be passed to http requests and is not made available
+        /// to script on the page.
+        /// </para>
+        /// </summary>
+        [Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.HttpOnly) + ".")]
+        public bool CookieHttpOnly { get => Cookie.HttpOnly; set => Cookie.HttpOnly = value; }
+
+        /// <summary>
+        /// <para>
+        /// This property is obsolete and will be removed in a future version. The recommended alternative is <seealso cref="CookieBuilder.SecurePolicy"/> on <see cref="Cookie"/>.
+        /// </para>
+        /// <para>
+        /// Determines if the cookie should only be transmitted on HTTPS request. The default is to limit the cookie
+        /// to HTTPS requests if the page which is doing the SignIn is also HTTPS. If you have an HTTPS sign in page
+        /// and portions of your site are HTTP you may need to change this value.
+        /// </para>
+        /// </summary>
+        [Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.SecurePolicy) + ".")]
+        public CookieSecurePolicy CookieSecure { get => Cookie.SecurePolicy; set => Cookie.SecurePolicy = value; }
+        #endregion
+    }
+}

+ 32 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/CookieExtensions.cs

@@ -0,0 +1,32 @@
+// 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 Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Options;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+    public static class CookieExtensions
+    {
+        public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder)
+            => builder.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
+
+        public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme)
+            => builder.AddCookie(authenticationScheme, configureOptions: null);
+
+        public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, Action<CookieAuthenticationOptions> configureOptions) 
+            => builder.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, configureOptions);
+
+        public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme, Action<CookieAuthenticationOptions> configureOptions)
+            => builder.AddCookie(authenticationScheme, displayName: null, configureOptions: configureOptions);
+
+        public static AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<CookieAuthenticationOptions> configureOptions)
+        {
+            builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureCookieAuthenticationOptions>());
+            return builder.AddScheme<CookieAuthenticationOptions, CookieAuthenticationHandler>(authenticationScheme, displayName, configureOptions);
+        }
+    }
+}

+ 158 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieAuthenticationEvents.cs

@@ -0,0 +1,158 @@
+// 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 System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    /// <summary>
+    /// This default implementation of the ICookieAuthenticationEvents may be used if the 
+    /// application only needs to override a few of the interface methods. This may be used as a base class
+    /// or may be instantiated directly.
+    /// </summary>
+    public class CookieAuthenticationEvents
+    {
+        /// <summary>
+        /// A delegate assigned to this property will be invoked when the related method is called.
+        /// </summary>
+        public Func<CookieValidatePrincipalContext, Task> OnValidatePrincipal { get; set; } = context => Task.CompletedTask;
+
+        /// <summary>
+        /// A delegate assigned to this property will be invoked when the related method is called.
+        /// </summary>
+        public Func<CookieSigningInContext, Task> OnSigningIn { get; set; } = context => Task.CompletedTask;
+
+        /// <summary>
+        /// A delegate assigned to this property will be invoked when the related method is called.
+        /// </summary>
+        public Func<CookieSignedInContext, Task> OnSignedIn { get; set; } = context => Task.CompletedTask;
+
+        /// <summary>
+        /// A delegate assigned to this property will be invoked when the related method is called.
+        /// </summary>
+        public Func<CookieSigningOutContext, Task> OnSigningOut { get; set; } = context => Task.CompletedTask;
+
+        /// <summary>
+        /// A delegate assigned to this property will be invoked when the related method is called.
+        /// </summary>
+        public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToLogin { get; set; } = context =>
+        {
+            if (IsAjaxRequest(context.Request))
+            {
+                context.Response.Headers["Location"] = context.RedirectUri;
+                context.Response.StatusCode = 401;
+            }
+            else
+            {
+                context.Response.Redirect(context.RedirectUri);
+            }
+            return Task.CompletedTask;
+        };
+
+        /// <summary>
+        /// A delegate assigned to this property will be invoked when the related method is called.
+        /// </summary>
+        public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToAccessDenied { get; set; } = context =>
+        {
+            if (IsAjaxRequest(context.Request))
+            {
+                context.Response.Headers["Location"] = context.RedirectUri;
+                context.Response.StatusCode = 403;
+            }
+            else
+            {
+                context.Response.Redirect(context.RedirectUri);
+            }
+            return Task.CompletedTask;
+        };
+
+        /// <summary>
+        /// A delegate assigned to this property will be invoked when the related method is called.
+        /// </summary>
+        public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToLogout { get; set; } = context =>
+        {
+            if (IsAjaxRequest(context.Request))
+            {
+                context.Response.Headers["Location"] = context.RedirectUri;
+            }
+            else
+            {
+                context.Response.Redirect(context.RedirectUri);
+            }
+            return Task.CompletedTask;
+        };
+
+        /// <summary>
+        /// A delegate assigned to this property will be invoked when the related method is called.
+        /// </summary>
+        public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToReturnUrl { get; set; } = context =>
+        {
+            if (IsAjaxRequest(context.Request))
+            {
+                context.Response.Headers["Location"] = context.RedirectUri;
+            }
+            else
+            {
+                context.Response.Redirect(context.RedirectUri);
+            }
+            return Task.CompletedTask;
+        };
+
+        private static bool IsAjaxRequest(HttpRequest request)
+        {
+            return string.Equals(request.Query["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal) ||
+                string.Equals(request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal);
+        }		
+
+        /// <summary>
+        /// Implements the interface method by invoking the related delegate method.
+        /// </summary>
+        /// <param name="context"></param>
+        /// <returns></returns>
+        public virtual Task ValidatePrincipal(CookieValidatePrincipalContext context) => OnValidatePrincipal(context);
+
+        /// <summary>
+        /// Implements the interface method by invoking the related delegate method.
+        /// </summary>
+        /// <param name="context"></param>
+        public virtual Task SigningIn(CookieSigningInContext context) => OnSigningIn(context);
+
+        /// <summary>
+        /// Implements the interface method by invoking the related delegate method.
+        /// </summary>
+        /// <param name="context"></param>
+        public virtual Task SignedIn(CookieSignedInContext context) => OnSignedIn(context);
+
+        /// <summary>
+        /// Implements the interface method by invoking the related delegate method.
+        /// </summary>
+        /// <param name="context"></param>
+        public virtual Task SigningOut(CookieSigningOutContext context) => OnSigningOut(context);
+
+        /// <summary>
+        /// Implements the interface method by invoking the related delegate method.
+        /// </summary>
+        /// <param name="context">Contains information about the event</param>
+        public virtual Task RedirectToLogout(RedirectContext<CookieAuthenticationOptions> context) => OnRedirectToLogout(context);
+
+        /// <summary>
+        /// Implements the interface method by invoking the related delegate method.
+        /// </summary>
+        /// <param name="context">Contains information about the event</param>
+        public virtual Task RedirectToLogin(RedirectContext<CookieAuthenticationOptions> context) => OnRedirectToLogin(context);
+
+        /// <summary>
+        /// Implements the interface method by invoking the related delegate method.
+        /// </summary>
+        /// <param name="context">Contains information about the event</param>
+        public virtual Task RedirectToReturnUrl(RedirectContext<CookieAuthenticationOptions> context) => OnRedirectToReturnUrl(context);
+
+        /// <summary>
+        /// Implements the interface method by invoking the related delegate method.
+        /// </summary>
+        /// <param name="context">Contains information about the event</param>
+        public virtual Task RedirectToAccessDenied(RedirectContext<CookieAuthenticationOptions> context) => OnRedirectToAccessDenied(context);
+    }
+}

+ 33 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSignedInContext.cs

@@ -0,0 +1,33 @@
+// 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.Security.Claims;
+using Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    /// <summary>
+    /// Context object passed to the ICookieAuthenticationEvents method SignedIn.
+    /// </summary>    
+    public class CookieSignedInContext : PrincipalContext<CookieAuthenticationOptions>
+    {
+        /// <summary>
+        /// Creates a new instance of the context object.
+        /// </summary>
+        /// <param name="context">The HTTP request context</param>
+        /// <param name="scheme">The scheme data</param>
+        /// <param name="principal">Initializes Principal property</param>
+        /// <param name="properties">Initializes Properties property</param>
+        /// <param name="options">The handler options</param>
+        public CookieSignedInContext(
+            HttpContext context,
+            AuthenticationScheme scheme,
+            ClaimsPrincipal principal,
+            AuthenticationProperties properties,
+            CookieAuthenticationOptions options)
+            : base(context, scheme, options, properties)
+        {
+            Principal = principal;
+        }
+    }
+}

+ 42 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningInContext.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.Security.Claims;
+using Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    /// <summary>
+    /// Context object passed to the <see cref="CookieAuthenticationEvents.SigningIn(CookieSigningInContext)"/>.
+    /// </summary>    
+    public class CookieSigningInContext : PrincipalContext<CookieAuthenticationOptions>
+    {
+        /// <summary>
+        /// Creates a new instance of the context object.
+        /// </summary>
+        /// <param name="context">The HTTP request context</param>
+        /// <param name="scheme">The scheme data</param>
+        /// <param name="options">The handler options</param>
+        /// <param name="principal">Initializes Principal property</param>
+        /// <param name="properties">The authentication properties.</param>
+        /// <param name="cookieOptions">Initializes options for the authentication cookie.</param>
+        public CookieSigningInContext(
+            HttpContext context,
+            AuthenticationScheme scheme,
+            CookieAuthenticationOptions options,
+            ClaimsPrincipal principal,
+            AuthenticationProperties properties,
+            CookieOptions cookieOptions)
+            : base(context, scheme, options, properties)
+        {
+            CookieOptions = cookieOptions;
+            Principal = principal;
+        }
+
+        /// <summary>
+        /// The options for creating the outgoing cookie.
+        /// May be replace or altered during the SigningIn call.
+        /// </summary>
+        public CookieOptions CookieOptions { get; set; }
+    }
+}

+ 36 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieSigningOutContext.cs

@@ -0,0 +1,36 @@
+// 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 Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    /// <summary>
+    /// Context object passed to the <see cref="CookieAuthenticationEvents.SigningOut(CookieSigningOutContext)"/>
+    /// </summary>
+    public class CookieSigningOutContext : PropertiesContext<CookieAuthenticationOptions>
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="context"></param>
+        /// <param name="scheme"></param>
+        /// <param name="options"></param>
+        /// <param name="properties"></param>
+        /// <param name="cookieOptions"></param>
+        public CookieSigningOutContext(
+            HttpContext context,
+            AuthenticationScheme scheme,
+            CookieAuthenticationOptions options, 
+            AuthenticationProperties properties, 
+            CookieOptions cookieOptions)
+            : base(context, scheme, options, properties)
+            => CookieOptions = cookieOptions;
+
+        /// <summary>
+        /// The options for creating the outgoing cookie.
+        /// May be replace or altered during the SigningOut call.
+        /// </summary>
+        public CookieOptions CookieOptions { get; set; }
+    }
+}

+ 51 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieValidatePrincipalContext.cs

@@ -0,0 +1,51 @@
+// 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 System.Security.Claims;
+using Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    /// <summary>
+    /// Context object passed to the CookieAuthenticationEvents ValidatePrincipal method.
+    /// </summary>
+    public class CookieValidatePrincipalContext : PrincipalContext<CookieAuthenticationOptions>
+    {
+        /// <summary>
+        /// Creates a new instance of the context object.
+        /// </summary>
+        /// <param name="context"></param>
+        /// <param name="scheme"></param>
+        /// <param name="ticket">Contains the initial values for identity and extra data</param>
+        /// <param name="options"></param>
+        public CookieValidatePrincipalContext(HttpContext context, AuthenticationScheme scheme, CookieAuthenticationOptions options, AuthenticationTicket ticket)
+            : base(context, scheme, options, ticket?.Properties)
+        {
+            if (ticket == null)
+            {
+                throw new ArgumentNullException(nameof(ticket));
+            }
+
+            Principal = ticket.Principal;
+        }
+
+        /// <summary>
+        /// If true, the cookie will be renewed
+        /// </summary>
+        public bool ShouldRenew { get; set; }
+
+        /// <summary>
+        /// Called to replace the claims principal. The supplied principal will replace the value of the 
+        /// Principal property, which determines the identity of the authenticated request.
+        /// </summary>
+        /// <param name="principal">The <see cref="ClaimsPrincipal"/> used as the replacement</param>
+        public void ReplacePrincipal(ClaimsPrincipal principal) => Principal = principal;
+
+        /// <summary>
+        /// Called to reject the incoming principal. This may be done if the application has determined the
+        /// account is no longer active, and the request should be treated as if it was anonymous.
+        /// </summary>
+        public void RejectPrincipal() => Principal = null;
+    }
+}

+ 39 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/ICookieManager.cs

@@ -0,0 +1,39 @@
+// 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 Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    /// <summary>
+    /// This is used by the CookieAuthenticationMiddleware to process request and response cookies.
+    /// It is abstracted from the normal cookie APIs to allow for complex operations like chunking.
+    /// </summary>
+    public interface ICookieManager
+    {
+        /// <summary>
+        /// Retrieve a cookie of the given name from the request.
+        /// </summary>
+        /// <param name="context"></param>
+        /// <param name="key"></param>
+        /// <returns></returns>
+        string GetRequestCookie(HttpContext context, string key);
+
+        /// <summary>
+        /// Append the given cookie to the response.
+        /// </summary>
+        /// <param name="context"></param>
+        /// <param name="key"></param>
+        /// <param name="value"></param>
+        /// <param name="options"></param>
+        void AppendResponseCookie(HttpContext context, string key, string value, CookieOptions options);
+
+        /// <summary>
+        /// Append a delete cookie to the response.
+        /// </summary>
+        /// <param name="context"></param>
+        /// <param name="key"></param>
+        /// <param name="options"></param>
+        void DeleteCookie(HttpContext context, string key, CookieOptions options);
+    }
+}

+ 43 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/ITicketStore.cs

@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    /// <summary>
+    /// This provides an abstract storage mechanic to preserve identity information on the server
+    /// while only sending a simple identifier key to the client. This is most commonly used to mitigate
+    /// issues with serializing large identities into cookies.
+    /// </summary>
+    public interface ITicketStore
+    {
+        /// <summary>
+        /// Store the identity ticket and return the associated key.
+        /// </summary>
+        /// <param name="ticket">The identity information to store.</param>
+        /// <returns>The key that can be used to retrieve the identity later.</returns>
+        Task<string> StoreAsync(AuthenticationTicket ticket);
+
+        /// <summary>
+        /// Tells the store that the given identity should be updated.
+        /// </summary>
+        /// <param name="key"></param>
+        /// <param name="ticket"></param>
+        /// <returns></returns>
+        Task RenewAsync(string key, AuthenticationTicket ticket);
+
+        /// <summary>
+        /// Retrieves an identity from the store for the given key.
+        /// </summary>
+        /// <param name="key">The key associated with the identity.</param>
+        /// <returns>The identity associated with the given key, or if not found.</returns>
+        Task<AuthenticationTicket> RetrieveAsync(string key);
+
+        /// <summary>
+        /// Remove the identity associated with the given key.
+        /// </summary>
+        /// <param name="key">The key associated with the identity.</param>
+        /// <returns></returns>
+        Task RemoveAsync(string key);
+    }
+}

+ 35 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/LoggingExtensions.cs

@@ -0,0 +1,35 @@
+// 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.Extensions.Logging
+{
+    internal static class LoggingExtensions
+    {
+        private static Action<ILogger, string, Exception> _authSchemeSignedIn;
+        private static Action<ILogger, string, Exception> _authSchemeSignedOut;
+
+        static LoggingExtensions()
+        {
+            _authSchemeSignedIn = LoggerMessage.Define<string>(
+                eventId: 10,
+                logLevel: LogLevel.Information,
+                formatString: "AuthenticationScheme: {AuthenticationScheme} signed in.");
+            _authSchemeSignedOut = LoggerMessage.Define<string>(
+                eventId: 11,
+                logLevel: LogLevel.Information,
+                formatString: "AuthenticationScheme: {AuthenticationScheme} signed out.");
+        }
+
+        public static void SignedIn(this ILogger logger, string authenticationScheme)
+        {
+            _authSchemeSignedIn(logger, authenticationScheme, null);
+        }
+
+        public static void SignedOut(this ILogger logger, string authenticationScheme)
+        {
+            _authSchemeSignedOut(logger, authenticationScheme, null);
+        }
+    }
+}

+ 20 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/Microsoft.AspNetCore.Authentication.Cookies.csproj

@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <Description>ASP.NET Core middleware that enables an application to use cookie based authentication.</Description>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <DefineConstants>$(DefineConstants);SECURITY</DefineConstants>
+    <NoWarn>$(NoWarn);CS1591</NoWarn>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+    <PackageTags>aspnetcore;authentication;security</PackageTags>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Compile Include="..\..\shared\Microsoft.AspNetCore.ChunkingCookieManager.Sources\**\*.cs" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj" />
+  </ItemGroup>
+
+</Project>

+ 59 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/PostConfigureCookieAuthenticationOptions.cs

@@ -0,0 +1,59 @@
+// 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 Microsoft.AspNetCore.DataProtection;
+using Microsoft.Extensions.Options;
+
+namespace Microsoft.AspNetCore.Authentication.Cookies
+{
+    /// <summary>
+    /// Used to setup defaults for all <see cref="CookieAuthenticationOptions"/>.
+    /// </summary>
+    public class PostConfigureCookieAuthenticationOptions : IPostConfigureOptions<CookieAuthenticationOptions>
+    {
+        private readonly IDataProtectionProvider _dp;
+
+        public PostConfigureCookieAuthenticationOptions(IDataProtectionProvider dataProtection)
+        {
+            _dp = dataProtection;
+        }
+
+        /// <summary>
+        /// Invoked to post configure a TOptions instance.
+        /// </summary>
+        /// <param name="name">The name of the options instance being configured.</param>
+        /// <param name="options">The options instance to configure.</param>
+        public void PostConfigure(string name, CookieAuthenticationOptions options)
+        {
+            options.DataProtectionProvider = options.DataProtectionProvider ?? _dp;
+
+            if (string.IsNullOrEmpty(options.Cookie.Name))
+            {
+                options.Cookie.Name = CookieAuthenticationDefaults.CookiePrefix + name;
+            }
+            if (options.TicketDataFormat == null)
+            {
+                // Note: the purpose for the data protector must remain fixed for interop to work.
+                var dataProtector = options.DataProtectionProvider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", name, "v2");
+                options.TicketDataFormat = new TicketDataFormat(dataProtector);
+            }
+            if (options.CookieManager == null)
+            {
+                options.CookieManager = new ChunkingCookieManager();
+            }
+            if (!options.LoginPath.HasValue)
+            {
+                options.LoginPath = CookieAuthenticationDefaults.LoginPath;
+            }
+            if (!options.LogoutPath.HasValue)
+            {
+                options.LogoutPath = CookieAuthenticationDefaults.LogoutPath;
+            }
+            if (!options.AccessDeniedPath.HasValue)
+            {
+                options.AccessDeniedPath = CookieAuthenticationDefaults.AccessDeniedPath;
+            }
+        }
+    }
+}

+ 1621 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Cookies/baseline.netcore.json

@@ -0,0 +1,1621 @@
+{
+  "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Cookies, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
+  "Types": [
+    {
+      "Name": "Microsoft.Extensions.DependencyInjection.CookieExtensions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "AddCookie",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AddCookie",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            },
+            {
+              "Name": "authenticationScheme",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AddCookie",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            },
+            {
+              "Name": "configureOptions",
+              "Type": "System.Action<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AddCookie",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            },
+            {
+              "Name": "authenticationScheme",
+              "Type": "System.String"
+            },
+            {
+              "Name": "configureOptions",
+              "Type": "System.Action<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AddCookie",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            },
+            {
+              "Name": "authenticationScheme",
+              "Type": "System.String"
+            },
+            {
+              "Name": "displayName",
+              "Type": "System.String"
+            },
+            {
+              "Name": "configureOptions",
+              "Type": "System.Action<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Builder.CookieAppBuilderExtensions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "UseCookieAuthentication",
+          "Parameters": [
+            {
+              "Name": "app",
+              "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "UseCookieAuthentication",
+          "Parameters": [
+            {
+              "Name": "app",
+              "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Field",
+          "Name": "CookiePrefix",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "LoginPath",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.PathString",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "LogoutPath",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.PathString",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "AccessDeniedPath",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.PathString",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "ReturnUrlParameter",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "AuthenticationScheme",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "Visibility": "Public",
+          "GenericParameter": [],
+          "Constant": true,
+          "Literal": "\"Cookies\""
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Authentication.SignInAuthenticationHandler<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_Events",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents",
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_Events",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "InitializeHandlerAsync",
+          "Parameters": [],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "CreateEventsAsync",
+          "Parameters": [],
+          "ReturnType": "System.Threading.Tasks.Task<System.Object>",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "HandleAuthenticateAsync",
+          "Parameters": [],
+          "ReturnType": "System.Threading.Tasks.Task<Microsoft.AspNetCore.Authentication.AuthenticateResult>",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "FinishResponseAsync",
+          "Parameters": [],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "HandleSignInAsync",
+          "Parameters": [
+            {
+              "Name": "user",
+              "Type": "System.Security.Claims.ClaimsPrincipal"
+            },
+            {
+              "Name": "properties",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "HandleSignOutAsync",
+          "Parameters": [
+            {
+              "Name": "properties",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "HandleForbiddenAsync",
+          "Parameters": [
+            {
+              "Name": "properties",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "HandleChallengeAsync",
+          "Parameters": [
+            {
+              "Name": "properties",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "options",
+              "Type": "Microsoft.Extensions.Options.IOptionsMonitor<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>"
+            },
+            {
+              "Name": "logger",
+              "Type": "Microsoft.Extensions.Logging.ILoggerFactory"
+            },
+            {
+              "Name": "encoder",
+              "Type": "System.Text.Encodings.Web.UrlEncoder"
+            },
+            {
+              "Name": "clock",
+              "Type": "Microsoft.AspNetCore.Authentication.ISystemClock"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Authentication.AuthenticationSchemeOptions",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_Cookie",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.CookieBuilder",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_Cookie",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Http.CookieBuilder"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_DataProtectionProvider",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_DataProtectionProvider",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_SlidingExpiration",
+          "Parameters": [],
+          "ReturnType": "System.Boolean",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_SlidingExpiration",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Boolean"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_LoginPath",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.PathString",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_LoginPath",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Http.PathString"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_LogoutPath",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.PathString",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_LogoutPath",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Http.PathString"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_AccessDeniedPath",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.PathString",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_AccessDeniedPath",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Http.PathString"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_ReturnUrlParameter",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ReturnUrlParameter",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_Events",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_Events",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_TicketDataFormat",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.ISecureDataFormat<Microsoft.AspNetCore.Authentication.AuthenticationTicket>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_TicketDataFormat",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Authentication.ISecureDataFormat<Microsoft.AspNetCore.Authentication.AuthenticationTicket>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_CookieManager",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_CookieManager",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_SessionStore",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_SessionStore",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_ExpireTimeSpan",
+          "Parameters": [],
+          "ReturnType": "System.TimeSpan",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ExpireTimeSpan",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.TimeSpan"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_CookieName",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_CookieName",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_CookieDomain",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_CookieDomain",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_CookiePath",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_CookiePath",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_CookieHttpOnly",
+          "Parameters": [],
+          "ReturnType": "System.Boolean",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_CookieHttpOnly",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Boolean"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_CookieSecure",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.CookieSecurePolicy",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_CookieSecure",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Http.CookieSecurePolicy"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_OnValidatePrincipal",
+          "Parameters": [],
+          "ReturnType": "System.Func<Microsoft.AspNetCore.Authentication.Cookies.CookieValidatePrincipalContext, System.Threading.Tasks.Task>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_OnValidatePrincipal",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Func<Microsoft.AspNetCore.Authentication.Cookies.CookieValidatePrincipalContext, System.Threading.Tasks.Task>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_OnSigningIn",
+          "Parameters": [],
+          "ReturnType": "System.Func<Microsoft.AspNetCore.Authentication.Cookies.CookieSigningInContext, System.Threading.Tasks.Task>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_OnSigningIn",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Func<Microsoft.AspNetCore.Authentication.Cookies.CookieSigningInContext, System.Threading.Tasks.Task>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_OnSignedIn",
+          "Parameters": [],
+          "ReturnType": "System.Func<Microsoft.AspNetCore.Authentication.Cookies.CookieSignedInContext, System.Threading.Tasks.Task>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_OnSignedIn",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Func<Microsoft.AspNetCore.Authentication.Cookies.CookieSignedInContext, System.Threading.Tasks.Task>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_OnSigningOut",
+          "Parameters": [],
+          "ReturnType": "System.Func<Microsoft.AspNetCore.Authentication.Cookies.CookieSigningOutContext, System.Threading.Tasks.Task>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_OnSigningOut",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Func<Microsoft.AspNetCore.Authentication.Cookies.CookieSigningOutContext, System.Threading.Tasks.Task>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_OnRedirectToLogin",
+          "Parameters": [],
+          "ReturnType": "System.Func<Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>, System.Threading.Tasks.Task>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_OnRedirectToLogin",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Func<Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>, System.Threading.Tasks.Task>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_OnRedirectToAccessDenied",
+          "Parameters": [],
+          "ReturnType": "System.Func<Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>, System.Threading.Tasks.Task>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_OnRedirectToAccessDenied",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Func<Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>, System.Threading.Tasks.Task>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_OnRedirectToLogout",
+          "Parameters": [],
+          "ReturnType": "System.Func<Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>, System.Threading.Tasks.Task>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_OnRedirectToLogout",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Func<Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>, System.Threading.Tasks.Task>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_OnRedirectToReturnUrl",
+          "Parameters": [],
+          "ReturnType": "System.Func<Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>, System.Threading.Tasks.Task>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_OnRedirectToReturnUrl",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Func<Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>, System.Threading.Tasks.Task>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "ValidatePrincipal",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieValidatePrincipalContext"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "SigningIn",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningInContext"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "SignedIn",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSignedInContext"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "SigningOut",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningOutContext"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "RedirectToLogout",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "RedirectToLogin",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "RedirectToReturnUrl",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "RedirectToAccessDenied",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Authentication.RedirectContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieSignedInContext",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Authentication.PrincipalContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Http.HttpContext"
+            },
+            {
+              "Name": "scheme",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme"
+            },
+            {
+              "Name": "principal",
+              "Type": "System.Security.Claims.ClaimsPrincipal"
+            },
+            {
+              "Name": "properties",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningInContext",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Authentication.PrincipalContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_CookieOptions",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.CookieOptions",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_CookieOptions",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Http.CookieOptions"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Http.HttpContext"
+            },
+            {
+              "Name": "scheme",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions"
+            },
+            {
+              "Name": "principal",
+              "Type": "System.Security.Claims.ClaimsPrincipal"
+            },
+            {
+              "Name": "properties",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
+            },
+            {
+              "Name": "cookieOptions",
+              "Type": "Microsoft.AspNetCore.Http.CookieOptions"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieSigningOutContext",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Authentication.PropertiesContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_CookieOptions",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.CookieOptions",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_CookieOptions",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Http.CookieOptions"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Http.HttpContext"
+            },
+            {
+              "Name": "scheme",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions"
+            },
+            {
+              "Name": "properties",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
+            },
+            {
+              "Name": "cookieOptions",
+              "Type": "Microsoft.AspNetCore.Http.CookieOptions"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.CookieValidatePrincipalContext",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Authentication.PrincipalContext<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_ShouldRenew",
+          "Parameters": [],
+          "ReturnType": "System.Boolean",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ShouldRenew",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Boolean"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "ReplacePrincipal",
+          "Parameters": [
+            {
+              "Name": "principal",
+              "Type": "System.Security.Claims.ClaimsPrincipal"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "RejectPrincipal",
+          "Parameters": [],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Http.HttpContext"
+            },
+            {
+              "Name": "scheme",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationScheme"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions"
+            },
+            {
+              "Name": "ticket",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "GetRequestCookie",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Http.HttpContext"
+            },
+            {
+              "Name": "key",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.String",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AppendResponseCookie",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Http.HttpContext"
+            },
+            {
+              "Name": "key",
+              "Type": "System.String"
+            },
+            {
+              "Name": "value",
+              "Type": "System.String"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Http.CookieOptions"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "DeleteCookie",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Http.HttpContext"
+            },
+            {
+              "Name": "key",
+              "Type": "System.String"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Http.CookieOptions"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.ITicketStore",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "StoreAsync",
+          "Parameters": [
+            {
+              "Name": "ticket",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task<System.String>",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "RenewAsync",
+          "Parameters": [
+            {
+              "Name": "key",
+              "Type": "System.String"
+            },
+            {
+              "Name": "ticket",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationTicket"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "RetrieveAsync",
+          "Parameters": [
+            {
+              "Name": "key",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task<Microsoft.AspNetCore.Authentication.AuthenticationTicket>",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "RemoveAsync",
+          "Parameters": [
+            {
+              "Name": "key",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.PostConfigureCookieAuthenticationOptions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "ImplementedInterfaces": [
+        "Microsoft.Extensions.Options.IPostConfigureOptions<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>"
+      ],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "PostConfigure",
+          "Parameters": [
+            {
+              "Name": "name",
+              "Type": "System.String"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.Extensions.Options.IPostConfigureOptions<Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "dataProtection",
+              "Type": "Microsoft.AspNetCore.DataProtection.IDataProtectionProvider"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Cookies.ChunkingCookieManager",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "ImplementedInterfaces": [
+        "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager"
+      ],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_ChunkSize",
+          "Parameters": [],
+          "ReturnType": "System.Nullable<System.Int32>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ChunkSize",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Nullable<System.Int32>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_ThrowForPartialCookies",
+          "Parameters": [],
+          "ReturnType": "System.Boolean",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ThrowForPartialCookies",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Boolean"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "GetRequestCookie",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Http.HttpContext"
+            },
+            {
+              "Name": "key",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.String",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AppendResponseCookie",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Http.HttpContext"
+            },
+            {
+              "Name": "key",
+              "Type": "System.String"
+            },
+            {
+              "Name": "value",
+              "Type": "System.String"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Http.CookieOptions"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "DeleteCookie",
+          "Parameters": [
+            {
+              "Name": "context",
+              "Type": "Microsoft.AspNetCore.Http.HttpContext"
+            },
+            {
+              "Name": "key",
+              "Type": "System.String"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Http.CookieOptions"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Authentication.Cookies.ICookieManager",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "DefaultChunkSize",
+          "Parameters": [],
+          "ReturnType": "System.Int32",
+          "Static": true,
+          "Visibility": "Public",
+          "GenericParameter": [],
+          "Constant": true,
+          "Literal": "4050"
+        }
+      ],
+      "GenericParameters": []
+    }
+  ]
+}

+ 37 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookAppBuilderExtensions.cs

@@ -0,0 +1,37 @@
+// 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 Microsoft.AspNetCore.Authentication.Facebook;
+
+namespace Microsoft.AspNetCore.Builder
+{
+    /// <summary>
+    /// Extension methods to add Facebook authentication capabilities to an HTTP application pipeline.
+    /// </summary>
+    public static class FacebookAppBuilderExtensions
+    {
+        /// <summary>
+        /// UseFacebookAuthentication is obsolete. Configure Facebook authentication with AddAuthentication().AddFacebook in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
+        /// </summary>
+        /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
+        /// <returns>A reference to this instance after the operation has completed.</returns>
+        [Obsolete("UseFacebookAuthentication is obsolete. Configure Facebook authentication with AddAuthentication().AddFacebook in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
+        public static IApplicationBuilder UseFacebookAuthentication(this IApplicationBuilder app)
+        {
+            throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
+        }
+
+        /// <summary>
+        /// UseFacebookAuthentication is obsolete. Configure Facebook authentication with AddAuthentication().AddFacebook in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
+        /// </summary>
+        /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
+        /// <param name="options">A <see cref="FacebookOptions"/> that specifies options for the handler.</param>
+        /// <returns>A reference to this instance after the operation has completed.</returns>
+        [Obsolete("UseFacebookAuthentication is obsolete. Configure Facebook authentication with AddAuthentication().AddFacebook in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
+        public static IApplicationBuilder UseFacebookAuthentication(this IApplicationBuilder app, FacebookOptions options)
+        {
+            throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
+        }
+    }
+}

+ 18 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookDefaults.cs

@@ -0,0 +1,18 @@
+// 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.
+
+namespace Microsoft.AspNetCore.Authentication.Facebook
+{
+    public static class FacebookDefaults
+    {
+        public const string AuthenticationScheme = "Facebook";
+
+        public static readonly string DisplayName = "Facebook";
+
+        public static readonly string AuthorizationEndpoint = "https://www.facebook.com/v2.12/dialog/oauth";
+
+        public static readonly string TokenEndpoint = "https://graph.facebook.com/v2.12/oauth/access_token";
+
+        public static readonly string UserInformationEndpoint = "https://graph.facebook.com/v2.12/me";
+    }
+}

+ 24 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookExtensions.cs

@@ -0,0 +1,24 @@
+// 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 Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Facebook;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+    public static class FacebookAuthenticationOptionsExtensions
+    {
+        public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder)
+            => builder.AddFacebook(FacebookDefaults.AuthenticationScheme, _ => { });
+
+        public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, Action<FacebookOptions> configureOptions)
+            => builder.AddFacebook(FacebookDefaults.AuthenticationScheme, configureOptions);
+
+        public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, string authenticationScheme, Action<FacebookOptions> configureOptions)
+            => builder.AddFacebook(authenticationScheme, FacebookDefaults.DisplayName, configureOptions);
+
+        public static AuthenticationBuilder AddFacebook(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<FacebookOptions> configureOptions)
+            => builder.AddOAuth<FacebookOptions, FacebookHandler>(authenticationScheme, displayName, configureOptions);
+    }
+}

+ 80 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookHandler.cs

@@ -0,0 +1,80 @@
+// 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.Collections.Generic;
+using System.Globalization;
+using System.Net.Http;
+using System.Security.Claims;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication.OAuth;
+using Microsoft.AspNetCore.WebUtilities;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json.Linq;
+
+namespace Microsoft.AspNetCore.Authentication.Facebook
+{
+    public class FacebookHandler : OAuthHandler<FacebookOptions>
+    {
+        public FacebookHandler(IOptionsMonitor<FacebookOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
+            : base(options, logger, encoder, clock)
+        { }
+
+        protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
+        {
+            var endpoint = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, "access_token", tokens.AccessToken);
+            if (Options.SendAppSecretProof)
+            {
+                endpoint = QueryHelpers.AddQueryString(endpoint, "appsecret_proof", GenerateAppSecretProof(tokens.AccessToken));
+            }
+            if (Options.Fields.Count > 0)
+            {
+                endpoint = QueryHelpers.AddQueryString(endpoint, "fields", string.Join(",", Options.Fields));
+            }
+
+            var response = await Backchannel.GetAsync(endpoint, Context.RequestAborted);
+            if (!response.IsSuccessStatusCode)
+            {
+                throw new HttpRequestException($"An error occurred when retrieving Facebook user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Facebook Graph API is enabled.");
+            }
+
+            var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
+
+            var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload);
+            context.RunClaimActions();
+
+            await Events.CreatingTicket(context);
+
+            return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
+
+        }
+
+        private string GenerateAppSecretProof(string accessToken)
+        {
+            using (var algorithm = new HMACSHA256(Encoding.ASCII.GetBytes(Options.AppSecret)))
+            {
+                var hash = algorithm.ComputeHash(Encoding.ASCII.GetBytes(accessToken));
+                var builder = new StringBuilder();
+                for (int i = 0; i < hash.Length; i++)
+                {
+                    builder.Append(hash[i].ToString("x2", CultureInfo.InvariantCulture));
+                }
+                return builder.ToString();
+            }
+        }
+
+        protected override string FormatScope(IEnumerable<string> scopes)
+        {
+            // Facebook deviates from the OAuth spec here. They require comma separated instead of space separated.
+            // https://developers.facebook.com/docs/reference/dialogs/oauth
+            // http://tools.ietf.org/html/rfc6749#section-3.3
+            return string.Join(",", scopes);
+        }
+
+        protected override string FormatScope()
+            => base.FormatScope();
+    }
+}

+ 102 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/FacebookOptions.cs

@@ -0,0 +1,102 @@
+// 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 System.Collections.Generic;
+using System.Security.Claims;
+using Microsoft.AspNetCore.Authentication;
+using System.Globalization;
+using Microsoft.AspNetCore.Authentication.OAuth;
+using Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Authentication.Facebook
+{
+    /// <summary>
+    /// Configuration options for <see cref="FacebookHandler"/>.
+    /// </summary>
+    public class FacebookOptions : OAuthOptions
+    {
+        /// <summary>
+        /// Initializes a new <see cref="FacebookOptions"/>.
+        /// </summary>
+        public FacebookOptions()
+        {
+            CallbackPath = new PathString("/signin-facebook");
+            SendAppSecretProof = true;
+            AuthorizationEndpoint = FacebookDefaults.AuthorizationEndpoint;
+            TokenEndpoint = FacebookDefaults.TokenEndpoint;
+            UserInformationEndpoint = FacebookDefaults.UserInformationEndpoint;
+            Scope.Add("public_profile");
+            Scope.Add("email");
+            Fields.Add("name");
+            Fields.Add("email");
+            Fields.Add("first_name");
+            Fields.Add("last_name");
+
+            ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
+            ClaimActions.MapJsonSubKey("urn:facebook:age_range_min", "age_range", "min");
+            ClaimActions.MapJsonSubKey("urn:facebook:age_range_max", "age_range", "max");
+            ClaimActions.MapJsonKey(ClaimTypes.DateOfBirth, "birthday");
+            ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
+            ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
+            ClaimActions.MapJsonKey(ClaimTypes.GivenName, "first_name");
+            ClaimActions.MapJsonKey("urn:facebook:middle_name", "middle_name");
+            ClaimActions.MapJsonKey(ClaimTypes.Surname, "last_name");
+            ClaimActions.MapJsonKey(ClaimTypes.Gender, "gender");
+            ClaimActions.MapJsonKey("urn:facebook:link", "link");
+            ClaimActions.MapJsonSubKey("urn:facebook:location", "location", "name");
+            ClaimActions.MapJsonKey(ClaimTypes.Locality, "locale");
+            ClaimActions.MapJsonKey("urn:facebook:timezone", "timezone");
+        }
+
+        /// <summary>
+        /// Check that the options are valid.  Should throw an exception if things are not ok.
+        /// </summary>
+        public override void Validate()
+        {
+            if (string.IsNullOrEmpty(AppId))
+            {
+                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(AppId)), nameof(AppId));
+            }
+
+            if (string.IsNullOrEmpty(AppSecret))
+            {
+                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.Exception_OptionMustBeProvided, nameof(AppSecret)), nameof(AppSecret));
+            }
+
+            base.Validate();
+        }
+
+        // Facebook uses a non-standard term for this field.
+        /// <summary>
+        /// Gets or sets the Facebook-assigned appId.
+        /// </summary>
+        public string AppId
+        {
+            get { return ClientId; }
+            set { ClientId = value; }
+        }
+
+        // Facebook uses a non-standard term for this field.
+        /// <summary>
+        /// Gets or sets the Facebook-assigned app secret.
+        /// </summary>
+        public string AppSecret
+        {
+            get { return ClientSecret; }
+            set { ClientSecret = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets if the appsecret_proof should be generated and sent with Facebook API calls.
+        /// This is enabled by default.
+        /// </summary>
+        public bool SendAppSecretProof { get; set; }
+
+        /// <summary>
+        /// The list of fields to retrieve from the UserInformationEndpoint.
+        /// https://developers.facebook.com/docs/graph-api/reference/user
+        /// </summary>
+        public ICollection<string> Fields { get; } = new HashSet<string>();
+    }
+}

+ 15 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/Microsoft.AspNetCore.Authentication.Facebook.csproj

@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <Description>ASP.NET Core middleware that enables an application to support Facebook's OAuth 2.0 authentication workflow.</Description>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <NoWarn>$(NoWarn);CS1591</NoWarn>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+    <PackageTags>aspnetcore;authentication;security</PackageTags>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
+  </ItemGroup>
+
+</Project>

+ 44 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/Properties/Resources.Designer.cs

@@ -0,0 +1,44 @@
+// <auto-generated />
+namespace Microsoft.AspNetCore.Authentication.Facebook
+{
+    using System.Globalization;
+    using System.Reflection;
+    using System.Resources;
+
+    internal static class Resources
+    {
+        private static readonly ResourceManager _resourceManager
+            = new ResourceManager("Microsoft.AspNetCore.Authentication.Facebook.Resources", typeof(Resources).GetTypeInfo().Assembly);
+
+        /// <summary>
+        /// The '{0}' option must be provided.
+        /// </summary>
+        internal static string Exception_OptionMustBeProvided
+        {
+            get => GetString("Exception_OptionMustBeProvided");
+        }
+
+        /// <summary>
+        /// The '{0}' option must be provided.
+        /// </summary>
+        internal static string FormatException_OptionMustBeProvided(object p0)
+            => string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0);
+
+        private static string GetString(string name, params string[] formatterNames)
+        {
+            var value = _resourceManager.GetString(name);
+
+            System.Diagnostics.Debug.Assert(value != null);
+
+            if (formatterNames != null)
+            {
+                for (var i = 0; i < formatterNames.Length; i++)
+                {
+                    value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
+                }
+            }
+
+            return value;
+        }
+    }
+}

+ 123 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/Resources.resx

@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="Exception_OptionMustBeProvided" xml:space="preserve">
+    <value>The '{0}' option must be provided.</value>
+  </data>
+</root>

+ 390 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Facebook/baseline.netcore.json

@@ -0,0 +1,390 @@
+{
+  "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Facebook, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
+  "Types": [
+    {
+      "Name": "Microsoft.Extensions.DependencyInjection.FacebookAuthenticationOptionsExtensions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "AddFacebook",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AddFacebook",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            },
+            {
+              "Name": "configureOptions",
+              "Type": "System.Action<Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AddFacebook",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            },
+            {
+              "Name": "authenticationScheme",
+              "Type": "System.String"
+            },
+            {
+              "Name": "configureOptions",
+              "Type": "System.Action<Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AddFacebook",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            },
+            {
+              "Name": "authenticationScheme",
+              "Type": "System.String"
+            },
+            {
+              "Name": "displayName",
+              "Type": "System.String"
+            },
+            {
+              "Name": "configureOptions",
+              "Type": "System.Action<Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookDefaults",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Field",
+          "Name": "DisplayName",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "AuthorizationEndpoint",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "TokenEndpoint",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "UserInformationEndpoint",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "AuthenticationScheme",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "Visibility": "Public",
+          "GenericParameter": [],
+          "Constant": true,
+          "Literal": "\"Facebook\""
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookHandler",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler<Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions>",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "CreateTicketAsync",
+          "Parameters": [
+            {
+              "Name": "identity",
+              "Type": "System.Security.Claims.ClaimsIdentity"
+            },
+            {
+              "Name": "properties",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
+            },
+            {
+              "Name": "tokens",
+              "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task<Microsoft.AspNetCore.Authentication.AuthenticationTicket>",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "FormatScope",
+          "Parameters": [
+            {
+              "Name": "scopes",
+              "Type": "System.Collections.Generic.IEnumerable<System.String>"
+            }
+          ],
+          "ReturnType": "System.String",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "FormatScope",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "options",
+              "Type": "Microsoft.Extensions.Options.IOptionsMonitor<Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions>"
+            },
+            {
+              "Name": "logger",
+              "Type": "Microsoft.Extensions.Logging.ILoggerFactory"
+            },
+            {
+              "Name": "encoder",
+              "Type": "System.Text.Encodings.Web.UrlEncoder"
+            },
+            {
+              "Name": "clock",
+              "Type": "Microsoft.AspNetCore.Authentication.ISystemClock"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "Validate",
+          "Parameters": [],
+          "ReturnType": "System.Void",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_AppId",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_AppId",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_AppSecret",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_AppSecret",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_SendAppSecretProof",
+          "Parameters": [],
+          "ReturnType": "System.Boolean",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_SendAppSecretProof",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Boolean"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_Fields",
+          "Parameters": [],
+          "ReturnType": "System.Collections.Generic.ICollection<System.String>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Builder.FacebookAppBuilderExtensions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "UseFacebookAuthentication",
+          "Parameters": [
+            {
+              "Name": "app",
+              "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "UseFacebookAuthentication",
+          "Parameters": [
+            {
+              "Name": "app",
+              "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Authentication.Facebook.FacebookOptions"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    }
+  ]
+}

+ 37 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleAppBuilderExtensions.cs

@@ -0,0 +1,37 @@
+// 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 Microsoft.AspNetCore.Authentication.Google;
+
+namespace Microsoft.AspNetCore.Builder
+{
+    /// <summary>
+    /// Extension methods to add Google authentication capabilities to an HTTP application pipeline.
+    /// </summary>
+    public static class GoogleAppBuilderExtensions
+    {
+        /// <summary>
+        /// UseGoogleAuthentication is obsolete. Configure Google authentication with AddAuthentication().AddGoogle in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
+        /// </summary>
+        /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
+        /// <returns>A reference to this instance after the operation has completed.</returns>
+        [Obsolete("UseGoogleAuthentication is obsolete. Configure Google authentication with AddAuthentication().AddGoogle in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
+        public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder app)
+        {
+            throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
+        }
+
+        /// <summary>
+        /// UseGoogleAuthentication is obsolete. Configure Google authentication with AddAuthentication().AddGoogle in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.
+        /// </summary>
+        /// <param name="app">The <see cref="IApplicationBuilder"/> to add the handler to.</param>
+        /// <param name="options">A <see cref="GoogleOptions"/> that specifies options for the handler.</param>
+        /// <returns>A reference to this instance after the operation has completed.</returns>
+        [Obsolete("UseGoogleAuthentication is obsolete. Configure Google authentication with AddAuthentication().AddGoogle in ConfigureServices. See https://go.microsoft.com/fwlink/?linkid=845470 for more details.", error: true)]
+        public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder app, GoogleOptions options)
+        {
+            throw new NotSupportedException("This method is no longer supported, see https://go.microsoft.com/fwlink/?linkid=845470");
+        }
+    }
+}

+ 89 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleChallengeProperties.cs

@@ -0,0 +1,89 @@
+using System.Collections.Generic;
+using Microsoft.AspNetCore.Authentication.OAuth;
+
+namespace Microsoft.AspNetCore.Authentication.Google
+{
+    public class GoogleChallengeProperties : OAuthChallengeProperties
+    {
+        /// <summary>
+        /// The parameter key for the "access_type" argument being used for a challenge request.
+        /// </summary>
+        public static readonly string AccessTypeKey = "access_type";
+
+        /// <summary>
+        /// The parameter key for the "approval_prompt" argument being used for a challenge request.
+        /// </summary>
+        public static readonly string ApprovalPromptKey = "approval_prompt";
+
+        /// <summary>
+        /// The parameter key for the "include_granted_scopes" argument being used for a challenge request.
+        /// </summary>
+        public static readonly string IncludeGrantedScopesKey = "include_granted_scopes";
+
+        /// <summary>
+        /// The parameter key for the "login_hint" argument being used for a challenge request.
+        /// </summary>
+        public static readonly string LoginHintKey = "login_hint";
+
+        /// <summary>
+        /// The parameter key for the "prompt" argument being used for a challenge request.
+        /// </summary>
+        public static readonly string PromptParameterKey = "prompt";
+
+        public GoogleChallengeProperties()
+        { }
+
+        public GoogleChallengeProperties(IDictionary<string, string> items)
+            : base(items)
+        { }
+
+        public GoogleChallengeProperties(IDictionary<string, string> items, IDictionary<string, object> parameters)
+            : base(items, parameters)
+        { }
+
+        /// <summary>
+        /// The "access_type" parameter value being used for a challenge request.
+        /// </summary>
+        public string AccessType
+        {
+            get => GetParameter<string>(AccessTypeKey);
+            set => SetParameter(AccessTypeKey, value);
+        }
+
+        /// <summary>
+        /// The "approval_prompt" parameter value being used for a challenge request.
+        /// </summary>
+        public string ApprovalPrompt
+        {
+            get => GetParameter<string>(ApprovalPromptKey);
+            set => SetParameter(ApprovalPromptKey, value);
+        }
+
+        /// <summary>
+        /// The "include_granted_scopes" parameter value being used for a challenge request.
+        /// </summary>
+        public bool? IncludeGrantedScopes
+        {
+            get => GetParameter<bool?>(IncludeGrantedScopesKey);
+            set => SetParameter(IncludeGrantedScopesKey, value);
+        }
+
+        /// <summary>
+        /// The "login_hint" parameter value being used for a challenge request.
+        /// </summary>
+        public string LoginHint
+        {
+            get => GetParameter<string>(LoginHintKey);
+            set => SetParameter(LoginHintKey, value);
+        }
+
+        /// <summary>
+        /// The "prompt" parameter value being used for a challenge request.
+        /// </summary>
+        public string Prompt
+        {
+            get => GetParameter<string>(PromptParameterKey);
+            set => SetParameter(PromptParameterKey, value);
+        }
+    }
+}

+ 21 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleDefaults.cs

@@ -0,0 +1,21 @@
+// 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.
+
+namespace Microsoft.AspNetCore.Authentication.Google
+{
+    /// <summary>
+    /// Default values for Google authentication
+    /// </summary>
+    public static class GoogleDefaults
+    {
+        public const string AuthenticationScheme = "Google";
+
+        public static readonly string DisplayName = "Google";
+
+        public static readonly string AuthorizationEndpoint = "https://accounts.google.com/o/oauth2/v2/auth";
+
+        public static readonly string TokenEndpoint = "https://www.googleapis.com/oauth2/v4/token";
+
+        public static readonly string UserInformationEndpoint = "https://www.googleapis.com/plus/v1/people/me";
+    }
+}

+ 24 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleExtensions.cs

@@ -0,0 +1,24 @@
+// 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 Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Google;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+    public static class GoogleExtensions
+    {
+        public static AuthenticationBuilder AddGoogle(this AuthenticationBuilder builder)
+            => builder.AddGoogle(GoogleDefaults.AuthenticationScheme, _ => { });
+
+        public static AuthenticationBuilder AddGoogle(this AuthenticationBuilder builder, Action<GoogleOptions> configureOptions)
+            => builder.AddGoogle(GoogleDefaults.AuthenticationScheme, configureOptions);
+
+        public static AuthenticationBuilder AddGoogle(this AuthenticationBuilder builder, string authenticationScheme, Action<GoogleOptions> configureOptions)
+            => builder.AddGoogle(authenticationScheme, GoogleDefaults.DisplayName, configureOptions);
+
+        public static AuthenticationBuilder AddGoogle(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action<GoogleOptions> configureOptions)
+            => builder.AddOAuth<GoogleOptions, GoogleHandler>(authenticationScheme, displayName, configureOptions);
+    }
+}

+ 108 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleHandler.cs

@@ -0,0 +1,108 @@
+// 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 System.Collections.Generic;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Security.Claims;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication.OAuth;
+using Microsoft.AspNetCore.WebUtilities;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json.Linq;
+
+namespace Microsoft.AspNetCore.Authentication.Google
+{
+    public class GoogleHandler : OAuthHandler<GoogleOptions>
+    {
+        public GoogleHandler(IOptionsMonitor<GoogleOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
+            : base(options, logger, encoder, clock)
+        { }
+
+        protected override async Task<AuthenticationTicket> CreateTicketAsync(
+            ClaimsIdentity identity,
+            AuthenticationProperties properties,
+            OAuthTokenResponse tokens)
+        {
+            // Get the Google user
+            var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint);
+            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
+
+            var response = await Backchannel.SendAsync(request, Context.RequestAborted);
+            if (!response.IsSuccessStatusCode)
+            {
+                throw new HttpRequestException($"An error occurred when retrieving Google user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Google+ API is enabled.");
+            }
+
+            var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
+
+            var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload);
+            context.RunClaimActions();
+
+            await Events.CreatingTicket(context);
+            return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
+        }
+
+        // TODO: Abstract this properties override pattern into the base class?
+        protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
+        {
+            // Google Identity Platform Manual:
+            // https://developers.google.com/identity/protocols/OAuth2WebServer
+
+            var queryStrings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+            queryStrings.Add("response_type", "code");
+            queryStrings.Add("client_id", Options.ClientId);
+            queryStrings.Add("redirect_uri", redirectUri);
+
+            AddQueryString(queryStrings, properties, GoogleChallengeProperties.ScopeKey, FormatScope, Options.Scope);
+            AddQueryString(queryStrings, properties, GoogleChallengeProperties.AccessTypeKey, Options.AccessType);
+            AddQueryString(queryStrings, properties, GoogleChallengeProperties.ApprovalPromptKey);
+            AddQueryString(queryStrings, properties, GoogleChallengeProperties.PromptParameterKey);
+            AddQueryString(queryStrings, properties, GoogleChallengeProperties.LoginHintKey);
+            AddQueryString(queryStrings, properties, GoogleChallengeProperties.IncludeGrantedScopesKey, v => v?.ToString().ToLower(), (bool?)null);
+
+            var state = Options.StateDataFormat.Protect(properties);
+            queryStrings.Add("state", state);
+
+            var authorizationEndpoint = QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, queryStrings);
+            return authorizationEndpoint;
+        }
+
+        private void AddQueryString<T>(
+            IDictionary<string, string> queryStrings,
+            AuthenticationProperties properties,
+            string name,
+            Func<T, string> formatter,
+            T defaultValue)
+        {
+            string value = null;
+            var parameterValue = properties.GetParameter<T>(name);
+            if (parameterValue != null)
+            {
+                value = formatter(parameterValue);
+            }
+            else if (!properties.Items.TryGetValue(name, out value))
+            {
+                value = formatter(defaultValue);
+            }
+
+            // Remove the parameter from AuthenticationProperties so it won't be serialized into the state
+            properties.Items.Remove(name);
+
+            if (value != null)
+            {
+                queryStrings[name] = value;
+            }
+        }
+
+        private void AddQueryString(
+            IDictionary<string, string> queryStrings,
+            AuthenticationProperties properties,
+            string name,
+            string defaultValue = null)
+            => AddQueryString(queryStrings, properties, name, x => x, defaultValue);
+    }
+}

+ 50 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleHelper.cs

@@ -0,0 +1,50 @@
+// 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 Newtonsoft.Json.Linq;
+
+namespace Microsoft.AspNetCore.Authentication.Google
+{
+    /// <summary>
+    /// Contains static methods that allow to extract user's information from a <see cref="JObject"/>
+    /// instance retrieved from Google after a successful authentication process.
+    /// </summary>
+    public static class GoogleHelper
+    {
+        /// <summary>
+        /// Gets the user's email.
+        /// </summary>
+        public static string GetEmail(JObject user)
+        {
+            if (user == null)
+            {
+                throw new ArgumentNullException(nameof(user));
+            }
+
+            return TryGetFirstValue(user, "emails", "value");
+        }
+
+        // Get the given subProperty from a list property.
+        private static string TryGetFirstValue(JObject user, string propertyName, string subProperty)
+        {
+            JToken value;
+            if (user.TryGetValue(propertyName, out value))
+            {
+                var array = JArray.Parse(value.ToString());
+                if (array != null && array.Count > 0)
+                {
+                    var subObject = JObject.Parse(array.First.ToString());
+                    if (subObject != null)
+                    {
+                        if (subObject.TryGetValue(subProperty, out value))
+                        {
+                            return value.ToString();
+                        }
+                    }
+                }
+            }
+            return null;
+        }
+    }
+}

+ 42 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Google/GoogleOptions.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.Security.Claims;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.OAuth;
+using Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Authentication.Google
+{
+    /// <summary>
+    /// Configuration options for <see cref="GoogleHandler"/>.
+    /// </summary>
+    public class GoogleOptions : OAuthOptions
+    {
+        /// <summary>
+        /// Initializes a new <see cref="GoogleOptions"/>.
+        /// </summary>
+        public GoogleOptions()
+        {
+            CallbackPath = new PathString("/signin-google");
+            AuthorizationEndpoint = GoogleDefaults.AuthorizationEndpoint;
+            TokenEndpoint = GoogleDefaults.TokenEndpoint;
+            UserInformationEndpoint = GoogleDefaults.UserInformationEndpoint;
+            Scope.Add("openid");
+            Scope.Add("profile");
+            Scope.Add("email");
+
+            ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
+            ClaimActions.MapJsonKey(ClaimTypes.Name, "displayName");
+            ClaimActions.MapJsonSubKey(ClaimTypes.GivenName, "name", "givenName");
+            ClaimActions.MapJsonSubKey(ClaimTypes.Surname, "name", "familyName");
+            ClaimActions.MapJsonKey("urn:google:profile", "url");
+            ClaimActions.MapCustomJson(ClaimTypes.Email, GoogleHelper.GetEmail);
+        }
+
+        /// <summary>
+        /// access_type. Set to 'offline' to request a refresh token.
+        /// </summary>
+        public string AccessType { get; set; }
+    }
+}

+ 15 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Google/Microsoft.AspNetCore.Authentication.Google.csproj

@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <Description>ASP.NET Core contains middleware to support Google's OpenId and OAuth 2.0 authentication workflows.</Description>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <NoWarn>$(NoWarn);CS1591</NoWarn>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+    <PackageTags>aspnetcore;authentication;security</PackageTags>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
+  </ItemGroup>
+
+</Project>

+ 58 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Google/Properties/Resources.Designer.cs

@@ -0,0 +1,58 @@
+// <auto-generated />
+namespace Microsoft.AspNetCore.Authentication.Google
+{
+    using System.Globalization;
+    using System.Reflection;
+    using System.Resources;
+
+    internal static class Resources
+    {
+        private static readonly ResourceManager _resourceManager
+            = new ResourceManager("Microsoft.AspNetCore.Authentication.Google.Resources", typeof(Resources).GetTypeInfo().Assembly);
+
+        /// <summary>
+        /// The '{0}' option must be provided.
+        /// </summary>
+        internal static string Exception_OptionMustBeProvided
+        {
+            get => GetString("Exception_OptionMustBeProvided");
+        }
+
+        /// <summary>
+        /// The '{0}' option must be provided.
+        /// </summary>
+        internal static string FormatException_OptionMustBeProvided(object p0)
+            => string.Format(CultureInfo.CurrentCulture, GetString("Exception_OptionMustBeProvided"), p0);
+
+        /// <summary>
+        /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler.
+        /// </summary>
+        internal static string Exception_ValidatorHandlerMismatch
+        {
+            get => GetString("Exception_ValidatorHandlerMismatch");
+        }
+
+        /// <summary>
+        /// An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler.
+        /// </summary>
+        internal static string FormatException_ValidatorHandlerMismatch()
+            => GetString("Exception_ValidatorHandlerMismatch");
+
+        private static string GetString(string name, params string[] formatterNames)
+        {
+            var value = _resourceManager.GetString(name);
+
+            System.Diagnostics.Debug.Assert(value != null);
+
+            if (formatterNames != null)
+            {
+                for (var i = 0; i < formatterNames.Length; i++)
+                {
+                    value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
+                }
+            }
+
+            return value;
+        }
+    }
+}

+ 126 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Google/Resources.resx

@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="Exception_OptionMustBeProvided" xml:space="preserve">
+    <value>The '{0}' option must be provided.</value>
+  </data>
+  <data name="Exception_ValidatorHandlerMismatch" xml:space="preserve">
+    <value>An ICertificateValidator cannot be specified at the same time as an HttpMessageHandler unless it is a WebRequestHandler.</value>
+  </data>
+</root>

+ 550 - 0
src/Security/src/Microsoft.AspNetCore.Authentication.Google/baseline.netcore.json

@@ -0,0 +1,550 @@
+{
+  "AssemblyIdentity": "Microsoft.AspNetCore.Authentication.Google, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
+  "Types": [
+    {
+      "Name": "Microsoft.Extensions.DependencyInjection.GoogleExtensions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "AddGoogle",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AddGoogle",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            },
+            {
+              "Name": "configureOptions",
+              "Type": "System.Action<Microsoft.AspNetCore.Authentication.Google.GoogleOptions>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AddGoogle",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            },
+            {
+              "Name": "authenticationScheme",
+              "Type": "System.String"
+            },
+            {
+              "Name": "configureOptions",
+              "Type": "System.Action<Microsoft.AspNetCore.Authentication.Google.GoogleOptions>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "AddGoogle",
+          "Parameters": [
+            {
+              "Name": "builder",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder"
+            },
+            {
+              "Name": "authenticationScheme",
+              "Type": "System.String"
+            },
+            {
+              "Name": "displayName",
+              "Type": "System.String"
+            },
+            {
+              "Name": "configureOptions",
+              "Type": "System.Action<Microsoft.AspNetCore.Authentication.Google.GoogleOptions>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Authentication.AuthenticationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleChallengeProperties",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthChallengeProperties",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_AccessType",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_AccessType",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_ApprovalPrompt",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ApprovalPrompt",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_IncludeGrantedScopes",
+          "Parameters": [],
+          "ReturnType": "System.Nullable<System.Boolean>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_IncludeGrantedScopes",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Nullable<System.Boolean>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_LoginHint",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_LoginHint",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_Prompt",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_Prompt",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "items",
+              "Type": "System.Collections.Generic.IDictionary<System.String, System.String>"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "items",
+              "Type": "System.Collections.Generic.IDictionary<System.String, System.String>"
+            },
+            {
+              "Name": "parameters",
+              "Type": "System.Collections.Generic.IDictionary<System.String, System.Object>"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "AccessTypeKey",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "ApprovalPromptKey",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "IncludeGrantedScopesKey",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "LoginHintKey",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "PromptParameterKey",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleDefaults",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Field",
+          "Name": "DisplayName",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "AuthorizationEndpoint",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "TokenEndpoint",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "UserInformationEndpoint",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "ReadOnly": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Field",
+          "Name": "AuthenticationScheme",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Static": true,
+          "Visibility": "Public",
+          "GenericParameter": [],
+          "Constant": true,
+          "Literal": "\"Google\""
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleHandler",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler<Microsoft.AspNetCore.Authentication.Google.GoogleOptions>",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "CreateTicketAsync",
+          "Parameters": [
+            {
+              "Name": "identity",
+              "Type": "System.Security.Claims.ClaimsIdentity"
+            },
+            {
+              "Name": "properties",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
+            },
+            {
+              "Name": "tokens",
+              "Type": "Microsoft.AspNetCore.Authentication.OAuth.OAuthTokenResponse"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task<Microsoft.AspNetCore.Authentication.AuthenticationTicket>",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "BuildChallengeUrl",
+          "Parameters": [
+            {
+              "Name": "properties",
+              "Type": "Microsoft.AspNetCore.Authentication.AuthenticationProperties"
+            },
+            {
+              "Name": "redirectUri",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.String",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Protected",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "options",
+              "Type": "Microsoft.Extensions.Options.IOptionsMonitor<Microsoft.AspNetCore.Authentication.Google.GoogleOptions>"
+            },
+            {
+              "Name": "logger",
+              "Type": "Microsoft.Extensions.Logging.ILoggerFactory"
+            },
+            {
+              "Name": "encoder",
+              "Type": "System.Text.Encodings.Web.UrlEncoder"
+            },
+            {
+              "Name": "clock",
+              "Type": "Microsoft.AspNetCore.Authentication.ISystemClock"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleHelper",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "GetEmail",
+          "Parameters": [
+            {
+              "Name": "user",
+              "Type": "Newtonsoft.Json.Linq.JObject"
+            }
+          ],
+          "ReturnType": "System.String",
+          "Static": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Authentication.Google.GoogleOptions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_AccessType",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_AccessType",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Builder.GoogleAppBuilderExtensions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "UseGoogleAuthentication",
+          "Parameters": [
+            {
+              "Name": "app",
+              "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "UseGoogleAuthentication",
+          "Parameters": [
+            {
+              "Name": "app",
+              "Type": "Microsoft.AspNetCore.Builder.IApplicationBuilder"
+            },
+            {
+              "Name": "options",
+              "Type": "Microsoft.AspNetCore.Authentication.Google.GoogleOptions"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Builder.IApplicationBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    }
+  ]
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов