title: Asp.net core 2 + Antiforgery: all POST endpoints return 400 Bad Request
body: <p>I have an asp.net core 2.1.4 app with a custom IXmlRepository to store the app keys using ef core + postgres. I deploy the app using Docker.</p>
  
  <p>Everything deploys and run fine except that all POST request return a 400 bad request response when running in Production. All is fine in Development.</p>
  
  <p>The problem is related to the setup of the antiforgery/dataprotection settings, I think</p>
  
  <p>This is my Startup.cs when I config the DataProtection and Antiforgery stuff. I have redacted it minimal just in case some other settings might be interfering.</p>
  
  <pre><code>public class Startup
  {
      IHostingEnvironment _env;
  
      public Startup(IConfiguration configuration, IHostingEnvironment env)
      {
          Configuration = configuration;
          _env = env;
      }
  
      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.AddDbContext&lt;AppDbContext&gt;(options =&gt;
              options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))
          );
  
          services.AddIdentity&lt;User, Role&gt;()
          .AddEntityFrameworkStores&lt;AppDbContext&gt;()
          .AddDefaultTokenProviders();
  
          services.Configure&lt;IdentityOptions&gt;(options =&gt;
          {
              // Password settings
              options.Password.RequireDigit = true;
              options.Password.RequiredLength = 8;
              options.Password.RequireNonAlphanumeric = false;
              options.Password.RequireUppercase = true;
              options.Password.RequireLowercase = false;
              options.Password.RequiredUniqueChars = 6;
  
              // Lockout settings
              options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
              options.Lockout.MaxFailedAccessAttempts = 10;
              options.Lockout.AllowedForNewUsers = true;
  
              // User settings
              options.User.RequireUniqueEmail = true;
          });
  
          ### HERE I SET THE CUSTOM KEY STORE ###
  
          services.AddSingleton&lt;IXmlRepository, EfXmlRepository&gt;();
          var sp = services.BuildServiceProvider();
          services.AddDataProtection()
                  .AddKeyManagementOptions(options =&gt; options.XmlRepository = sp.GetService&lt;IXmlRepository&gt;());
  
          services.AddMvc(options =&gt;
          {
              options.OutputFormatters.Add(new HtmlOutputFormatter());
              options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
          });
  
          ### HERE I SET THE ANTI FORGERY HEADER FOR SOME API CALLS ###
  
          services.AddAntiforgery(x =&gt; x.HeaderName = "X-XSRF-TOKEN");
  
          services.AddAuthentication()
          .AddCookie()         
          .AddJwtBearer(options =&gt;
          {
              options.TokenValidationParameters = new TokenValidationParameters
              {
                  ValidateIssuer = true,
                  ValidateAudience = true,
                  ValidateIssuerSigningKey = true,
                  ValidIssuer = "myapp.com",
                  ValidAudience = "myapp.com",
                  RequireExpirationTime = false,
                  IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SecurityKey"]))
              };
          });;
  
          services.AddTransient&lt;JwtService&gt;();
          services.AddTransient&lt;PaymentProviderService&gt;();
          services.AddTransient&lt;SubscriptionService&gt;();
          services.AddTransient&lt;IInvalidJwtTokenStore, EfInvalidJwtTokenStore&gt;();
  
          //setup hangfire
          GlobalConfiguration.Configuration.UsePostgreSqlStorage(Configuration.GetConnectionString("DefaultConnection"));
  
      }
  
      // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
      public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env)
      {
          if (env.IsDevelopment())
          {
              app.UseDeveloperExceptionPage();
          }
          else
          {
              app.UseExceptionHandler("/Home/Error");
          }
  
          app.UseStaticFiles();
          app.UseAuthentication();
  
          app.UseMvc(
              routes =&gt;
              {
                  routes.MapRoute(
                      name: "default",
                      template: "{controller=Home}/{action=Index}/{id?}");
              }
          );
  
          loggerFactory.AddConsole(LogLevel.Information);
      }
  </code></pre>
  
  <p>This is my ef core IXmlRepository implementation:</p>
  
  <pre><code>public class EfXmlRepository : IXmlRepository
  {
      AppDbContext _db;
  
      public EfXmlRepository(AppDbContext dbContext)
      {
          _db = dbContext;
      }
  
      public IReadOnlyCollection&lt;XElement&gt; GetAllElements()
      {
          var list = _db.XmlKeys.ToList().Select(x =&gt; XElement.Parse(x.Xml)).ToList();
          return list;
      }
  
      public void StoreElement(XElement element, string friendlyName)
      {
          _db.XmlKeys.Add(new XmlKey
          {
              Xml = element.ToString(SaveOptions.DisableFormatting)
          });
  
          _db.SaveChanges();
      }
  }
  </code></pre>
  
  <p>An an earlier stage the logs told me this:</p>
  
  <pre><code>2018-04-04T18:05:58.950344099Z app[web.1]: fail: 
  Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery[7]
  2018-04-04T18:05:58.950392982Z app[web.1]:       An exception was 
  thrown while deserializing the token.
  2018-04-04T18:05:58.950398037Z app[web.1]: 
  System.InvalidOperationException: The antiforgery token could not be 
  decrypted. ---&gt; System.Security.Cryptography.CryptographicException: 
  The key {9b8ab2d0-3ca5-4fcd-af54-b1a6601077af} was not found in the key 
  ring.
  </code></pre>
  
  <p>But this error disappeared when I tweaked the postgres settings for the IXmlRepository.</p>
  
  <p>Just in case this is my Dockerfile</p>
  
  <pre><code>FROM microsoft/dotnet:latest
  COPY . /app
  WORKDIR /app
  
  ENV ASPNETCORE_URLS http://0.0.0.0:5000
  ENV ASPNETCORE_ENVIRONMENT Production
  EXPOSE 5000
  
  RUN dotnet restore
  RUN dotnet publish -c Release
  
  WORKDIR /app/MyApp.Web
  RUN dotnet ef database update
  
  WORKDIR /app/MyApp.Web/bin/Release/netcoreapp2.0/publish
  ENTRYPOINT dotnet MyApp.Web.dll
  </code></pre>
  
  <p>Looking forward ot hearing your thoughts. Thanks!</p>