title: ASP.NET Core 2 API call is redirected (302)
body: <p>I'm trying to migrate this project 
  <a href="https://github.com/asadsahi/AspNetCoreSpa" rel="noreferrer">https://github.com/asadsahi/AspNetCoreSpa</a> from .net core 1.1 to 2.0 but have a problem after a successful login. After the login my GET api calls e. g. to <a href="https://localhost:44331/api/profile/test" rel="noreferrer">https://localhost:44331/api/profile/test</a> end up with a redirect (302) and I don't know why. I received a bearer token and it looks fine.</p>
  
  <p>Request header format: 
  authorization: Bearer [token]</p>
  
  <pre><code>[Route("api/[controller]")]
  public class ProfileController : BaseController
  {
      private readonly UserManager&lt;ApplicationUser&gt; _userManager;
      private readonly ILogger _logger;
  
      public ProfileController(ILoggerFactory loggerFactory, UserManager&lt;ApplicationUser&gt; userManager)
      {
          _logger = loggerFactory.CreateLogger&lt;ProfileController&gt;();
          _userManager = userManager;
      }
  
      [HttpGet("test")]
      public async Task&lt;IActionResult&gt; Test()
      {
          return  Json(ModelState.GetModelErrors());
      }
  }
  
  [Authorize]
  [ServiceFilter(typeof(ApiExceptionFilter))]
  [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
  public class BaseController : Controller
  {
      public BaseController()
      {
      }
  }
  </code></pre>
  
  <p>Startup.cs:</p>
  
  <pre><code>public void ConfigureServices(IServiceCollection services)
  {
      if (_hostingEnv.IsDevelopment())
      {
          services.AddSslCertificate(_hostingEnv);
      }
      else
      {
          services.Configure&lt;MvcOptions&gt;(o =&gt; o.Filters.Add(new RequireHttpsAttribute()));
      }
      services.AddOptions();
      services.AddCors();
      services.AddLogging();
      services.AddResponseCompression(options =&gt;
      {
          options.MimeTypes = Helpers.DefaultMimeTypes;
      });
  
      services.AddAuthentication(sharedOptions =&gt;
      {
          sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
          sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
          sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  
  
      }).AddJwtBearer(cfg =&gt;
      {
          cfg.SaveToken = true;
          cfg.TokenValidationParameters = new TokenValidationParameters
          {
              ValidIssuer = Configuration["Authentication:BearerTokens:Issuer"],
              ValidAudience = Configuration["Authentication:BearerTokens:Audience"],
              IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Authentication:BearerTokens:Key"])),
              ValidateIssuerSigningKey = false,
              ValidateLifetime = true,
              ClockSkew = TimeSpan.Zero
          };
          cfg.Events = new JwtBearerEvents
          {
  
              OnAuthenticationFailed = context =&gt;
              {
                  var logger = context.HttpContext.RequestServices.GetRequiredService&lt;ILoggerFactory&gt;().CreateLogger(nameof(JwtBearerEvents));
                  logger.LogError("Authentication failed.", context.Exception);
                  return Task.CompletedTask;
              },
  
              OnMessageReceived = context =&gt;
              {
                  return Task.CompletedTask;
              },
              OnChallenge = context =&gt;
              {
                  var logger = context.HttpContext.RequestServices.GetRequiredService&lt;ILoggerFactory&gt;().CreateLogger(nameof(JwtBearerEvents));
                  logger.LogError("OnChallenge error", context.Error, context.ErrorDescription);
                  return Task.CompletedTask;
              }
          };
      });
  
      services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;
      {
          string useSqLite = Startup.Configuration["Data:useSqLite"];
          if (useSqLite.ToLower() == "true")
          {
              options.UseSqlite(Startup.Configuration["Data:SqlLiteConnectionString"]);
          }
          else
          {
              options.UseSqlServer(Startup.Configuration["Data:SqlServerConnectionString"]);
          }
          options.UseOpenIddict();
      });
  
  
      services.AddIdentity&lt;ApplicationUser, ApplicationRole&gt;()
          .AddEntityFrameworkStores&lt;ApplicationDbContext&gt;()
          .AddDefaultTokenProviders();
  
      //services.ConfigureApplicationCookie(options =&gt;
      //{
  
      //    options.LoginPath = "/login";
      //    options.Events.OnRedirectToLogin = context =&gt;
      //    {
      //        if (context.Request.Path.StartsWithSegments("/api") &amp;&amp;
      //            context.Response.StatusCode == (int)HttpStatusCode.OK)
      //        {
      //            context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
      //        }
      //        else
      //        {
      //            context.Response.Redirect(context.RedirectUri);
      //        }
      //        return Task.FromResult(0);
      //    };
      //});
  
  
      services.AddOAuthProviders();
  
      services.AddCustomOpenIddict();
  
      services.AddMemoryCache();
  
      services.RegisterCustomServices();
  
      services.AddAntiforgery(options =&gt; options.HeaderName = "X-XSRF-TOKEN");
  
      services.AddCustomizedMvc();
  
      // Node services are to execute any arbitrary nodejs code from .net
      services.AddNodeServices();
  
      services.AddSwaggerGen(c =&gt;
      {
          c.SwaggerDoc("v1", new Info { Title = "AspNetCoreSpa", Version = "v1" });
      });
  }
  
  public void Configure(IApplicationBuilder app)
  {
      app.AddDevMiddlewares();
  
      if (_hostingEnv.IsProduction())
      {
          app.UseResponseCompression();
      }
  
      app.SetupMigrations();
  
      app.UseXsrf();
  
      app.UseStaticFiles();
  
      app.UseAuthentication();
  
      app.UseMvc(routes =&gt;
      {
          // http://stackoverflow.com/questions/25982095/using-googleoauth2authenticationoptions-got-a-redirect-uri-mismatch-error
          routes.MapRoute(name: "signin-google", template: "signin-google", defaults: new { controller = "Account", action = "ExternalLoginCallback" });
  
          routes.MapSpaFallbackRoute(
              name: "spa-fallback",
              defaults: new { controller = "Home", action = "Index" });
      });
  }
  </code></pre>
  
  <p>My IServiceCollection-Extensions:</p>
  
  <pre><code>public static IServiceCollection AddCustomizedMvc(this IServiceCollection services)
  {
      services.AddMvc(options =&gt;
      {
          options.Filters.Add(typeof(ModelValidationFilter));
      })
      .AddJsonOptions(options =&gt;
      {
          options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
      });
  
      return services;
  }
  
  public static IServiceCollection AddOAuthProviders(this IServiceCollection services)
  {
      services.AddAuthentication()
          .AddFacebook(o =&gt;
          {
              o.AppId = Startup.Configuration["Authentication:Facebook:AppId"];
              o.AppSecret = Startup.Configuration["Authentication:Facebook:AppSecret"];
          });
  
      services.AddAuthentication()
          .AddGoogle(o =&gt;
          {
              o.ClientId = Startup.Configuration["Authentication:Google:ClientId"];
              o.ClientSecret = Startup.Configuration["Authentication:Google:ClientSecret"];
          });
      services.AddAuthentication()
          .AddTwitter(o =&gt;
          {
              o.ConsumerKey = Startup.Configuration["Authentication:Twitter:ConsumerKey"];
              o.ConsumerSecret = Startup.Configuration["Authentication:Twitter:ConsumerSecret"];
          });
  
      services.AddAuthentication()
          .AddMicrosoftAccount(o =&gt;
          {
              o.ClientId= Startup.Configuration["Authentication:Microsoft:ClientId"];
              o.ClientSecret = Startup.Configuration["Authentication:Microsoft:ClientSecret"];
          });
  
      return services;
  }
  
  public static IServiceCollection AddCustomOpenIddict(this IServiceCollection services)
  {
  
      // Configure Identity to use the same JWT claims as OpenIddict instead
      // of the legacy WS-Federation claims it uses by default (ClaimTypes),
      // which saves you from doing the mapping in your authorization controller.
      services.Configure&lt;IdentityOptions&gt;(options =&gt;
      {
          options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
          options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
          options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
  
      });
  
      // Register the OpenIddict services.
      services.AddOpenIddict()
          // Register the Entity Framework stores.
          .AddEntityFrameworkCoreStores&lt;ApplicationDbContext&gt;()
  
          // Register the ASP.NET Core MVC binder used by OpenIddict.
          // Note: if you don't call this method, you won't be able to
          // bind OpenIdConnectRequest or OpenIdConnectResponse parameters.
          .AddMvcBinders()
  
          // Enable the token endpoint.
          .EnableTokenEndpoint("/connect/token")
  
          // Enable the password and the refresh token flows.
          .AllowPasswordFlow()
          .AllowRefreshTokenFlow()
  
          // During development, you can disable the HTTPS requirement.
          .DisableHttpsRequirement()
  
          // Register a new ephemeral key, that is discarded when the application
          // shuts down. Tokens signed using this key are automatically invalidated.
          // This method should only be used during development.
          .AddEphemeralSigningKey();
  
      // On production, using a X.509 certificate stored in the machine store is recommended.
      // You can generate a self-signed certificate using Pluralsight's self-cert utility:
      // https://s3.amazonaws.com/pluralsight-free/keith-brown/samples/SelfCert.zip
      //
      // services.AddOpenIddict()
      //     .AddSigningCertificate("7D2A741FE34CC2C7369237A5F2078988E17A6A75");
      //
      // Alternatively, you can also store the certificate as an embedded .pfx resource
      // directly in this assembly or in a file published alongside this project:
      //
      // services.AddOpenIddict()
      //     .AddSigningCertificate(
      //          assembly: typeof(Startup).GetTypeInfo().Assembly,
      //          resource: "AuthorizationServer.Certificate.pfx",
      //          password: "OpenIddict");
  
      return services;
  }
  
  public static IServiceCollection AddCustomDbContext(this IServiceCollection services)
  {
      // Add framework services.
  
      return services;
  }
  
  public static IServiceCollection RegisterCustomServices(this IServiceCollection services)
  {
      // New instance every time, only configuration class needs so its ok
      services.Configure&lt;SmsSettings&gt;(options =&gt; Startup.Configuration.GetSection("SmsSettingsTwillio").Bind(options));
      services.AddTransient&lt;UserResolverService&gt;();
      services.AddTransient&lt;IEmailSender, EmailSender&gt;();
      services.AddTransient&lt;ISmsSender, SmsSender&gt;();
      services.AddScoped&lt;ApiExceptionFilter&gt;();
      return services;
  }
  </code></pre>
  
  <p>Here my packages: </p>
  
  <pre><code>&lt;ItemGroup&gt;
  &lt;PackageReference Include="AspNet.Security.OAuth.Introspection" Version="2.0.0-*" /&gt;
  &lt;PackageReference Include="AspNet.Security.OAuth.Validation" Version="2.0.0-*" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.AzureAppServicesIntegration" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Cors" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Antiforgery" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Authorization" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Authentication.Facebook" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Authentication.Twitter" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.Extensions.Logging" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.0.0" /&gt;
  &lt;PackageReference Include="Microsoft.AspNetCore.AngularServices" Version="1.1.0-beta-000002" /&gt;
  &lt;PackageReference Include="AspNet.Security.OAuth.GitHub" Version="1.0.0-beta3-final" /&gt;
  &lt;PackageReference Include="AspNet.Security.OAuth.LinkedIn" Version="1.0.0-beta3-final" /&gt;
  &lt;PackageReference Include="OpenIddict" Version="2.0.0-*" /&gt;
  &lt;PackageReference Include="OpenIddict.EntityFrameworkCore" Version="2.0.0-*" /&gt;
  &lt;PackageReference Include="OpenIddict.Mvc" Version="2.0.0-*" /&gt;
  &lt;PackageReference Include="SendGrid" Version="9.9.0" /&gt;
  &lt;PackageReference Include="MailKit" Version="1.18.0" /&gt;
  &lt;PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" /&gt;
  &lt;PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="1.0.0" /&gt;
  &lt;PackageReference Include="Twilio" Version="5.6.3" /&gt;
  &lt;PackageReference Include="Stripe.net" Version="10.4.0" /&gt;
  &lt;PackageReference Include="Newtonsoft.Json" Version="10.0.3" /&gt;
  &lt;PackageReference Include="Webpack" Version="4.0.0" /&gt;
  &lt;PackageReference Include="Serilog" Version="2.5.0" /&gt;
  &lt;PackageReference Include="Serilog.Extensions.Logging" Version="2.0.2" /&gt;
  &lt;PackageReference Include="Serilog.Sinks.Seq" Version="3.3.3" /&gt;
  &lt;PackageReference Include="Bogus" Version="17.0.1" /&gt;
  &lt;PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0"&gt;
    &lt;PrivateAssets&gt;All&lt;/PrivateAssets&gt;
  &lt;/PackageReference&gt;
  &lt;PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.0.0"&gt;
    &lt;PrivateAssets&gt;All&lt;/PrivateAssets&gt;
  &lt;/PackageReference&gt;
  
    &lt;PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Version="2.0.0" PrivateAssets="All" /&gt;
    &lt;/ItemGroup&gt;
  
    &lt;ItemGroup&gt;
  &lt;DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" /&gt;
  &lt;DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" /&gt;
  &lt;DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.0" /&gt;
  &lt;DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" /&gt;
    &lt;/ItemGroup&gt;
  </code></pre>
  
  <p>Here are my logs:</p>
  
  <pre><code>info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
    Request starting HTTP/1.1 GET http://localhost:44331/api/profile/test 
  application/json; charset=UTF-8 
  info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
    Authorization failed for user: (null).
  info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
    Authorization failed for user: (null).
  info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
    Authorization failed for the request at filter 
  'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
  info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
    Authorization failed for the request at filter 
  'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
  info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
    Executing ChallengeResult with authentication schemes ().
  info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
    Executing ChallengeResult with authentication schemes ().
  info: 
  Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[12]
    AuthenticationScheme: Identity.Application was challenged.
  info: 
  Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[12]
    AuthenticationScheme: Identity.Application was challenged.
  info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
    Executed action 
  AspNetCoreSpa.Server.Controllers.api.ProfileController.Test (AspNetCoreSpa) 
  in 43.3105ms
  info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
    Executed action 
  AspNetCoreSpa.Server.Controllers.api.ProfileController.Test (AspNetCoreSpa) 
  in 43.3105ms
  info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
    Request finished in 67.4133ms 302 
  infoinfo: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
    Request finished in 67.4133ms 302 
  : Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
    Request starting HTTP/1.1 GET http://localhost:44331/Account/Login?
  ReturnUrl=%2Fapi%2Fprofile%2Ftest application/json; charset=UTF-8 
  info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
    Request starting HTTP/1.1 GET http://localhost:44331/Account/Login?
  ReturnUrl=%2Fapi%2Fprofile%2Ftest application/json; charset=UTF-8 
  info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
    Executing action method 
  AspNetCoreSpa.Server.Controllers.HomeController.Index (AspNetCoreSpa) with 
  arguments ((null)) - ModelState is Valid
  info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
    Executing action method 
  AspNetCoreSpa.Server.Controllers.HomeController.Index (AspNetCoreSpa) with 
  arguments ((null)) - ModelState is Valid
  info: Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ViewResultExecutor[1]
    Executing ViewResult, running view at path /Views/Home/Index.cshtml.
  info: Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ViewResultExecutor[1]
    Executing ViewResult, running view at path /Views/Home/Index.cshtml.
  info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
    Executed action AspNetCoreSpa.Server.Controllers.HomeController.Index 
  (AspNetCoreSpa) in 13.2746ms
  info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
    Executed action AspNetCoreSpa.Server.Controllers.HomeController.Index 
  (AspNetCoreSpa) in 13.2746ms
  info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
    Request finished in 79.2352ms 200 text/html; charset=utf-8
  info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
    Request finished in 79.2352ms 200 text/html; charset=utf-8
  </code></pre>
  
  <p>I wonder about the following line:</p>
  
  <p><strong>Authorization failed for user: (null)</strong></p>
  
  <p>Already found this <a href="https://stackoverflow.com/questions/45198275/asp-net-core-authorization-failed-for-user-null">Authorization failed for user: (null)</a>
  but there is no answer yet and I think it's a .NET Core 1 issue.</p>