I want to use OAuth for login
And can use cookies and Bearer Authorization for Authentication
Reference from ASP.NET Core 2.0 combining Cookies and Bearer Authorization for the same endpoint
but cookie can function normally, Bearer Authorization can't
Here is the setup I have for Authentication in my Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
// JWT tokens
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => // JwtBearerDefaults.AuthenticationScheme
{
options.Authority = Configuration["auth:oidc:AuthBaseUri"];
options.Audience = Configuration["auth:oidc:Scopes"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
NameClaimType = "name",
RoleClaimType = "role",
};
options.SaveToken = true;
});
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
options.Authority = Configuration["auth:oidc:AuthBaseUri"];
options.ClientId = Configuration["auth:oidc:ClientId"];
options.ClientSecret = Configuration["auth:oidc:ClientSecret"];
options.Scope.Clear();
options.Scope.Add("openid roles profile");
options.Scope.Add(Configuration["auth:oidc:Scopes"]);
options.GetClaimsFromUserInfoEndpoint = true;
options.ClaimActions.MapJsonKey("role", "role", "role");
options.UseTokenLifetime = true;
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
options.SaveTokens = true;
options.ResponseType = OpenIdConnectResponseType.Code;
});
services.AddAuthorization(options =>
{
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme);
defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.Use(async (context, next) =>
{
await next();
var bearerAuth = context.Request.Headers["Authorization"]
.FirstOrDefault()?.StartsWith("Bearer ") ?? false;
if (context.Response.StatusCode == 401
&& !context.User.Identity.IsAuthenticated
&& !bearerAuth)
{
await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme);
}
});
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
I have the following sample endpoint:
[HttpGet]
[Authorize(Roles = "xxxRole")]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
jwt sample:
eyJhbGciOiJSUzI1NiIsImtpZCI6InlYa2hPMTc5XzlUM0Jkc1ZBbjhEV2ciLCJ0eXAiOiJhdCtqd3QifQ.eyJuYmYiOjE2MjEzNDM3NzYsImV4cCI6MTYyMTM0NzM3NiwiaXNzIjoiaHR0cHM6Ly9taWNyb3N1Z2Fyb2F1dGguYXp1cmV3ZWJzaXRlcy5uZXQiLCJhdWQiOiJ0QXV0aG9yaXphdGlvbkNvZGVBcGkiLCJjbGllbnRfaWQiOiJ0QXV0aG9yaXphdGlvbkNvZGVDbGllbnRJZCIsInN1YiI6IjUxMzI1ODExLWU2Y2EtNGRkNS05NmMzLTk4YzY1OTYxNzQxNyIsImF1dGhfdGltZSI6MTYyMTMzNjc2NywiaWRwIjoibG9jYWwiLCJ3ZWJzaXRlIjpbImh0dHBzOi8vbG9jYWxob3N0OjQ0Mzg4IiwiaHR0cHM6Ly9sb2NhbGhvc3Q6NTAwMSJdLCJyb2xlIjoidFJvbGUiLCJqdGkiOiJzUUtvY3ZwbWdfcjY1cERtc1VXTXNnIiwic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSIsInRBdXRob3JpemF0aW9uQ29kZUFwaSJdLCJhbXIiOlsicHdkIl19.FiZJDMOXYA72yd-q7qesU1apqxURDKE73IfGGuyHmDVKlc8UWpkTIeEl4bUBpoahs2FSNs5FX7fdgS1uq3xhAH9D-7Mozg8R0C1fhmAkCU8JvQ9TRoKUf8IjdZTO0dv59mBryAisUBUfygiAOUbnvcsHODGX5MV7EmViw8rcgbusSmI7SC6wSeFBaD9IbiJVsBfdveD2NVMTpJacTZfDb15ngo5HS3K571pZ9mFMgMVqu9-SzOb6PdwZXcHuPXUXzFQfJCYBOpWMA_kVHtI5jhUEm1GeG7S92fgk7eHYHj7cBiPIqeHTvlf5ab6AQ3kooNgEzFgSQLU0M66z8HlocQ