Cant access authorized routes using jwt after getting token - .net-core
I can login and get a jwt
{
"resource": "resource-server",
"token_type": "Bearer",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4NzJlMTY5OS0xNGQwLTRhYmItYTU4Mi1kZDZmODkzNWU1NGEiLCJuYW1lIjoidGVzdEB0ZXN0LmNvbSIsInRva2VuX3VzYWdlIjoiYWNjZXNzX3Rva2VuIiwianRpIjoiNzdlMDhiMGMtMGRmMy00NDJjLTgxOTItMDk4YWNiYjdiZWQyIiwiYXVkIjoicmVzb3VyY2Utc2VydmVyIiwibmJmIjoxNDk1NTY0ODI5LCJleHAiOjE0OTU1Njg0MjksImlhdCI6MTQ5NTU2NDgyOSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTY2NC8ifQ.00X9de2jtetmWoj4BNaskvtPryElEsenpoVgisCxEoA",
"expires_in": 3600
}
But when I try and get a protected route, I get a 401.
This is my startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Authorization.Data;
using Authorization.Models;
using Authorization.Services;
using OpenIddict.Core;
using OpenIddict.Models;
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace Authorization
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment())
{
// For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets<Startup>();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
options.UseOpenIddict();
});
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
});
var secretKey = "mysupersecret_secretkey!123";
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
services.AddOpenIddict(options =>
{
options.AddEntityFrameworkCoreStores<ApplicationDbContext>();
options.AddMvcBinders();
options.EnableTokenEndpoint("/connect/token");
options.UseJsonWebTokens();
options.AllowPasswordFlow();
options.AddSigningKey(signingKey);
options.DisableHttpsRequirement();
});
services.AddMvc();
// Add application services.
//services.AddTransient<IEmailSender, AuthMessageSender>();
//services.AddTransient<ISmsSender, AuthMessageSender>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseCors(builder =>
{
builder.AllowAnyHeader();
builder.AllowAnyMethod();
builder.AllowCredentials();
builder.AllowAnyOrigin(); // For anyone access.
//corsBuilder.WithOrigins("http://localhost:56573"); // for a specific url.
});
app.UseStaticFiles();
//app.UseOAuthValidation();
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = "http://localhost:55664",
Audience = "resource-server",
AutomaticAuthenticate = true,
AutomaticChallenge = true,
RequireHttpsMetadata = false,
});
app.UseOpenIddict();
// Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715
app.UseMvcWithDefaultRoute();
}
}
}
I've tried setting authority and audience to all sorts of different things. I've tried removing them completely and I can not get a 200 back on a route with
[Authorize]
added on.
When I try and do this in Postman, I get the error
Bearer error="invalid_token", error_description="The signature is
invalid"
It's a GET with 1 header, Authorization = bearer {token here}
I'm just at a loss. Been at this for 3 days now. I feel like it's almost right, I'm just missing some key thing. Missing a header or something.
Also note, I have an angular 2 app at localhost:4200. But my understanding is this should still work within postman?
This is the server output when I hit the authorized route
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.2832518Z","tags":{"ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.operation.id":"0HL5214V879CK","ai.application.ver":"1.0.0.0"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request starting HTTP/1.1 GET http://localhost:55664/api/values","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Hosting.Internal.WebHost","Protocol":"HTTP/1.1","AspNetCoreEnvironment":"Development","DeveloperMode":"true","Scheme":"http","Host":"localhost:55664","Path":"/api/values","Method":"GET"}}}}
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:55664/api/values
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.2902711Z","tags":{"ai.operation.name":"GET /api/values","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"The request path /api/values does not match a supported file type","severityLevel":"Verbose","properties":{"CategoryName":"Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware","{OriginalFormat}":"The request path {Path} does not match a supported file type","AspNetCoreEnvironment":"Development","DeveloperMode":"true","Path":"/api/values"}}}}
Exception thrown: 'Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException' in System.IdentityModel.Tokens.Jwt.dll
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3128307Z","tags":{"ai.operation.name":"GET /api/values","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Failed to validate the token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4NzJlMTY5OS0xNGQwLTRhYmItYTU4Mi1kZDZmODkzNWU1NGEiLCJuYW1lIjoidGVzdEB0ZXN0LmNvbSIsInRva2VuX3VzYWdlIjoiYWNjZXNzX3Rva2VuIiwianRpIjoiNzdlMDhiMGMtMGRmMy00NDJjLTgxOTItMDk4YWNiYjdiZWQyIiwiYXVkIjoicmVzb3VyY2Utc2VydmVyIiwibmJmIjoxNDk1NTY0ODI5LCJleHAiOjE0OTU1Njg0MjksImlhdCI6MTQ5NTU2NDgyOSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTY2NC8ifQ.00X9de2jtetmWoj4BNaskvtPryElEsenpoVgisCxEoA.","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware","{OriginalFormat}":"Failed to validate the token {Token}.","Token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4NzJlMTY5OS0xNGQwLTRhYmItYTU4Mi1kZDZmODkzNWU1NGEiLCJuYW1lIjoidGVzdEB0ZXN0LmNvbSIsInRva2VuX3VzYWdlIjoiYWNjZXNzX3Rva2VuIiwianRpIjoiNzdlMDhiMGMtMGRmMy00NDJjLTgxOTItMDk4YWNiYjdiZWQyIiwiYXVkIjoicmVzb3VyY2Utc2VydmVyIiwibmJmIjoxNDk1NTY0ODI5LCJleHAiOjE0OTU1Njg0MjksImlhdCI6MTQ5NTU2NDgyOSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTY2NC8ifQ.00X9de2jtetmWoj4BNaskvtPryElEsenpoVgisCxEoA","AspNetCoreEnvironment":"Development","DeveloperMode":"true","Exception":"Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10500: Signature validation failed. No security keys were provided to validate the signature.\r\n at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)\r\n at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)\r\n at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.<HandleAuthenticateAsync>d__1.MoveNext()"}}}}
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: Failed to validate the token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4NzJlMTY5OS0xNGQwLTRhYmItYTU4Mi1kZDZmODkzNWU1NGEiLCJuYW1lIjoidGVzdEB0ZXN0LmNvbSIsInRva2VuX3VzYWdlIjoiYWNjZXNzX3Rva2VuIiwianRpIjoiNzdlMDhiMGMtMGRmMy00NDJjLTgxOTItMDk4YWNiYjdiZWQyIiwiYXVkIjoicmVzb3VyY2Utc2VydmVyIiwibmJmIjoxNDk1NTY0ODI5LCJleHAiOjE0OTU1Njg0MjksImlhdCI6MTQ5NTU2NDgyOSwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NTY2NC8ifQ.00X9de2jtetmWoj4BNaskvtPryElEsenpoVgisCxEoA.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10500: Signature validation failed. No security keys were provided to validate the signature.
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.<HandleAuthenticateAsync>d__1.MoveNext()
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3173431Z","tags":{"ai.operation.name":"GET /api/values","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Bearer was not authenticated. Failure message: IDX10500: Signature validation failed. No security keys were provided to validate the signature.","severityLevel":"Information","properties":{"FailureMessage":"IDX10500: Signature validation failed. No security keys were provided to validate the signature.","CategoryName":"Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware","AuthenticationScheme":"Bearer","{OriginalFormat}":"{AuthenticationScheme} was not authenticated. Failure message: {FailureMessage}","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: Bearer was not authenticated. Failure message: IDX10500: Signature validation failed. No security keys were provided to validate the signature.
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3238602Z","tags":{"ai.operation.name":"GET /api/values","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request successfully matched the route with name '(null)' and template 'api/Values'.","severityLevel":"Verbose","properties":{"CategoryName":"Microsoft.AspNetCore.Routing.Tree.TreeRouter","{OriginalFormat}":"Request successfully matched the route with name '{RouteName}' and template '{RouteTemplate}'.","AspNetCoreEnvironment":"Development","DeveloperMode":"true","RouteTemplate":"api/Values"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3253638Z","tags":{"ai.operation.name":"GET /api/values","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Action 'AspToken.Controllers.ValuesController.Post (Authorization)' with id 'd8fd53b2-6692-4c31-b8ce-0d7965e7e5b1' did not match the constraint 'Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint'","severityLevel":"Verbose","properties":{"CategoryName":"Microsoft.AspNetCore.Mvc.Internal.ActionSelector","{OriginalFormat}":"Action '{ActionName}' with id '{ActionId}' did not match the constraint '{ActionConstraint}'","AspNetCoreEnvironment":"Development","ActionConstraint":"Microsoft.AspNetCore.Mvc.Internal.HttpMethodActionConstraint","ActionId":"d8fd53b2-6692-4c31-b8ce-0d7965e7e5b1","DeveloperMode":"true","ActionName":"AspToken.Controllers.ValuesController.Post (Authorization)"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3273695Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Executing action AspToken.Controllers.ValuesController.Get (Authorization)","severityLevel":"Verbose","properties":{"CategoryName":"Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker","{OriginalFormat}":"Executing action {ActionName}","AspNetCoreEnvironment":"Development","DeveloperMode":"true","ActionName":"AspToken.Controllers.ValuesController.Get (Authorization)"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3293745Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Authorization failed for user: (null).","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Authorization.DefaultAuthorizationService","{OriginalFormat}":"Authorization failed for user: {UserName}.","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: (null).
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3323827Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker","{OriginalFormat}":"Authorization failed for the request at filter '{AuthorizationFilter}'.","AuthorizationFilter":"Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3348898Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Executing ChallengeResult with authentication schemes ().","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Mvc.ChallengeResult","{OriginalFormat}":"Executing ChallengeResult with authentication schemes ({Schemes}).","AspNetCoreEnvironment":"Development","DeveloperMode":"true","Schemes":"System.String[]"}}}}
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3378977Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"AuthenticationScheme: Bearer was challenged.","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware","AuthenticationScheme":"Bearer","{OriginalFormat}":"AuthenticationScheme: {AuthenticationScheme} was challenged.","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: AuthenticationScheme: Bearer was challenged.
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3409055Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Executed action AspToken.Controllers.ValuesController.Get (Authorization) in 11.408ms","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker","ElapsedMilliseconds":"11.408","{OriginalFormat}":"Executed action {ActionName} in {ElapsedMilliseconds}ms","AspNetCoreEnvironment":"Development","DeveloperMode":"true","ActionName":"AspToken.Controllers.ValuesController.Get (Authorization)"}}}}
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action AspToken.Controllers.ValuesController.Get (Authorization) in 11.408ms
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3439137Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Connection id \"0HL5214V6KQ2K\" completed keep alive response.","severityLevel":"Verbose","properties":{"CategoryName":"Microsoft.AspNetCore.Server.Kestrel","{OriginalFormat}":"Connection id \"{ConnectionId}\" completed keep alive response.","AspNetCoreEnvironment":"Development","DeveloperMode":"true","ConnectionId":"0HL5214V6KQ2K"}}}}
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2017-05-23T18:49:45.3454177Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Request finished in 61.7295ms 401","severityLevel":"Information","properties":{"CategoryName":"Microsoft.AspNetCore.Hosting.Internal.WebHost","ElapsedMilliseconds":"61.7295","StatusCode":"401","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 61.7295ms 401
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Request","time":"2017-05-23T18:49:45.3318446Z","tags":{"ai.operation.name":"GET Values/Get","ai.internal.nodeName":"GA-BRU-D9V2XBH2","ai.internal.sdkVersion":"aspnet5c:2.0.0","ai.cloud.roleInstance":"GA-BRU-D9V2XBH2","ai.operation.id":"0HL5214V879CL","ai.application.ver":"1.0.0.0","ai.location.ip":"::1"},"data":{"baseType":"RequestData","baseData":{"ver":2,"id":"5sE5TCp7osw=","name":"GET Values/Get","duration":"00:00:00.0180848","success":false,"responseCode":"401","url":"http://localhost:55664/api/values","properties":{"httpMethod":"GET","AspNetCoreEnvironment":"Development","DeveloperMode":"true"}}}}
Sigh. I'm an idiot.
If you sign your key
options.AddSigningKey(signingKey);
Then you need to tell the
app.UseJwtBearerAuthentication
how to validate that key.
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = audience,
ValidateLifetime = true,
}
My complete startup file for anyone that also gets stuck on this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Authorization.Data;
using Authorization.Models;
using Authorization.Services;
using OpenIddict.Core;
using OpenIddict.Models;
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace Authorization
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment())
{
// For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets<Startup>();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
options.UseOpenIddict();
});
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
});
var secretKey = "mysupersecret_secretkey!123";
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
services.AddOpenIddict(options =>
{
options.AddEntityFrameworkCoreStores<ApplicationDbContext>();
options.AddMvcBinders();
options.EnableTokenEndpoint("/connect/token");
options.UseJsonWebTokens();
options.AllowPasswordFlow();
options.AddSigningKey(signingKey);
options.DisableHttpsRequirement();
});
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseCors(builder =>
{
builder.AllowAnyHeader();
builder.AllowAnyMethod();
builder.AllowCredentials();
builder.AllowAnyOrigin(); // For anyone access.
//corsBuilder.WithOrigins("http://localhost:56573"); // for a specific url.
});
app.UseStaticFiles();
var audience = "resource-server";
var authority = "http://localhost:55664";
var secretKey = "mysupersecret_secretkey!123";
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
//app.UseOAuthValidation();
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = authority,
Audience = audience,
AutomaticAuthenticate = true,
AutomaticChallenge = true,
RequireHttpsMetadata = false,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = true,
// makes no difference seemingly being ignored
//ValidIssuer = Configuration.Get<AppOptions>().Jwt.Authority,
ValidateAudience = true,
ValidAudience = audience,
ValidateLifetime = true,
}
});
app.UseOpenIddict();
// Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715
app.UseMvcWithDefaultRoute();
}
}
}
Related
How to implement OAuth2.0 Authentication token in ASP.NET Core Web API?
I want to implement OAuth2.0 token in ASP.NET Core Web API. I have seen many tutorials and videos but all are doing the traditional way or in ASP.NET only not in Core. So I want the way to implement in visual studio 2022 with latest version of ASP.NET Core. Please help I have seen many tutorials and videos but all are doing the traditional way or in ASP.NET only not in Core. So I want the way to implement in visual studio 2022 with latest version of ASP.NET Core. Please help
You can use Jwt authentication to protect your web api and this is one of the method based on OAuth2.0. Here's a blog and the following codes are based on it. OAuth2.0 is a protocol but not the implement. So you can't find samples for it. But when you searched Jwt auth, Azure AD into .net 6 or some other products, you will find many doucuments. Let's see some additional information which may also help you: Let's go back to the sample, in this scenario, you have to integrate the authentication first. In .net 6, going to program.cs and adding these code: using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; var builder = WebApplication.CreateBuilder(args); //adding jwt auth builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { //define which claim requires to check ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, //store the value in appsettings.json ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Issuer"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) }; }); ... app.UseRouting(); //adding UseAuthentication app.UseAuthentication(); app.UseAuthorization(); In appsettings.json: "Jwt": { "Key": "ThisismySecretKey", "Issuer": "Test.com" } Then, pls add [Authorize] before the api controller, then you've established the authentication and when accessing the api without the correct jwt token, you will get 401 error: Let's generate an access token then test calling the api with the token. In another Controller without [Authorize], adding code like this: using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; private IConfiguration _config; public HomeController(IConfiguration config) { _config = config; } public IActionResult Index() { ViewBag.accessToken = generateJwt(); return View(); } private string generateJwt() { var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"])); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); //If you've had the login module, you can also use the real user information here var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, "user_name"), new Claim(JwtRegisteredClaimNames.Email, "user_email"), new Claim("DateOfJoing", "2022-09-12"), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; var token = new JwtSecurityToken(_config["Jwt:Issuer"], _config["Jwt:Issuer"], claims, expires: DateTime.Now.AddMinutes(120), signingCredentials: credentials); return new JwtSecurityTokenHandler().WriteToken(token); } Then calling the api with the token, you can decode the token first:
CORS policy issue when consuming ASP NET Core 3.1 Web Api by Angular 8
I have encountered issue with CORS policy when developing Angular 8, ASP NET Core Web Api web application. My angular app is running on http://localhost:4200 There is one service created for communication with Web Api. It looks as follows #Injectable({ providedIn: 'root' }) export class AuthenticationService { apiUrl: string = ""; constructor(private http: HttpClient) { this.apiUrl = 'https://localhost:44316'; } login(Username: any, Password: any){ return this.http.post<Observable<ResultItem<AuthenticationResponse>>>(this.apiUrl + "/api/User/Authenticate", {Username: Username, Password: Password}); } } Services is later called within component, but it is simply injected, and used with subscribe method. onLogin(){ this.authenticationService.login(this.loginFormValues.username.value, this.loginFormValues.password.value).subscribe( result => {}); } Web Api is running seperatly, on https://localhost:44316/ End point for the method called from Angular looks as follows: [ApiController] [Route("api/[controller]")] public class UserController : ControllerBase { private readonly IUserService userService; public UserController(IUserService userService) { this.userService = userService; } [HttpPost("Authenticate")] public async Task<IActionResult> Authenticate(AuthenticationModel model) { return Ok(await userService.Login(model)); } } What I am most concerned about is my Startup file. So far, I have tried to change the CORS setting there, but with no successful results. Code of the Startup.cs file looks as follows. Quick note: Two lines of code within ConfigureServices method use some of my external functions, and their purpose is to: AddSubstracture: registers all repositories as transients and registers DbContext. AddApplication: registers services which are one layer above repositories as transients Startup.cs code looks as follows public class Startup { private IServiceCollection _services; public Startup(IConfiguration configuration, IWebHostEnvironment environment) { Configuration = configuration; Environment = environment; SportFacilityUnitSettings = configuration.Get<SportFacilityUnitSettings>(); } public IConfiguration Configuration { get; } public IWebHostEnvironment Environment { get; } public SportFacilityUnitSettings SportFacilityUnitSettings { get; } public void ConfigureServices(IServiceCollection services) { services.AddCors(); services.AddMvc(option => option.EnableEndpointRouting = false); services.AddSubstructure(Configuration, Environment, SportFacilityUnitSettings); services.AddApplication(); services.AddScoped<IPasswordHasher<User>, PasswordHasher<User>>(); var appSettingsSection = Configuration.GetSection("AppSettings"); services.Configure<AppSettings>(appSettingsSection); var appSettings = appSettingsSection.Get<AppSettings>(); var key = Encoding.ASCII.GetBytes(appSettings.Secret); services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(x => { x.RequireHttpsMetadata = false; x.SaveToken = true; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false }; }); services.AddControllers().AddNewtonsoftJson(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore ); services.Configure<AppSettings>(Configuration.GetSection("AppSettings")); services.AddHttpContextAccessor(); _services = services; } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseCors( options => options.SetIsOriginAllowed(x => _ = true).AllowAnyMethod().AllowAnyHeader().AllowCredentials() ); app.UseMvc(); app.UseHsts(); app.UseMiddleware<JwtMiddleware>(); app.UseAuthentication(); app.UseRouting(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } When I hit the login button, which purpose is to send the request, I receive following error in web browser console. Access to XMLHttpRequest at 'https://localhost:44316/api/User/Authenticate' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. The weirdest thing about it, is when I debug it, and set up a breakpoint in Api layer, debugger hits it, then it enters the service layer and fails somewhere inside Authentication method .
Go to IIS where your application is hosted and check if you have set the below information right. #Step 1 : IIS --> HTTP Response header] #Step 2 : : Setting 4 fields in your API app hosted under IIS #Step 3: If the above 2 steps does not work, make sure you follow the msdn information to enable cors for your application https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1 Step 4 : : Investigate the header information you are using in your web API and if that's allowed under your IIS setting (as mentioned in Step 1) Step 5 : : Place a breakpoint in your authenticate method to see where and why its failing. You may get more clue from this error information as well. Step 6 : Try enabling CrossDomain to true from your front end. Step 7 : Try enabling https for both the application (calling application and called application)
ADFS Sign Out Issue ID4037: The key needed to verify the signature could not be resolved from the following security key identifier
We have a homegrown webapp A and a 3rd party webapp B. Both are relying parties within our on-prem ADFS 4.0 server on a Windows 2019 Datacenter. Webapp A uses WS-Federation and webapp B probably uses SAML 2.0 but not 100% sure. Webapp A has no signature certificate. Webapp B has a valid signature certificate. A user can sign into webapp A and webapp B and sign out without any issues as long as this occurs in different browser sessions. But if users are in webapp A and open another browser tab to go to webapp B, and try to sign out from webapp A, they get an error "MSIS7054: The SAML logout did not complete properly." And ADFS Event Viewer shows the below exception: The Federation Service encountered an error while processing the SAML authentication request. Additional Data Exception details: Microsoft.IdentityModel.Protocols.XmlSignature.SignatureVerificationFailedException: ID4037: The key needed to verify the signature could not be resolved from the following security key identifier 'SecurityKeyIdentifier ( IsReadOnly = False, Count = 1, Clause[0] = Microsoft.IdentityServer.Tokens.MSISSecurityKeyIdentifierClause ) '. Ensure that the SecurityTokenResolver is populated with the required key. at Microsoft.IdentityModel.Protocols.XmlSignature.EnvelopedSignatureReader.ResolveSigningCredentials() at Microsoft.IdentityModel.Protocols.XmlSignature.EnvelopedSignatureReader.OnEndOfRootElement() at Microsoft.IdentityModel.Protocols.XmlSignature.EnvelopedSignatureReader.Read() at System.Xml.XmlReader.ReadEndElement() at Microsoft.IdentityServer.Protocols.Saml.SamlProtocolSerializer.ReadLogoutRequest(XmlReader reader) at Microsoft.IdentityServer.Protocols.Saml.HttpSamlBindingSerializer.ReadProtocolMessage(String encodedSamlMessage) at Microsoft.IdentityServer.Protocols.Saml.Contract.SamlContractUtility.CreateSamlMessage(MSISSamlBindingMessage message) at Microsoft.IdentityServer.Web.Protocols.Saml.SamlProtocolManager.Logout(HttpSamlMessage logoutMessage, String sessionState, String logoutState, Boolean partialLogout, Boolean isUrlTranslationNeeded, HttpSamlMessage& newLogoutMessage, String& newSessionState, String& newLogoutState, Boolean& validLogoutRequest) Webapp A is a dotnet core MVC app. Here is the sign out code: [Authorize] public async Task SignOut() { //redirect to /signoutcallback after signout await SignOutCustom("/signoutcallback"); } [Authorize] public async Task SignOutCustom(string redirectUri) { await HttpContext.SignOutAsync("Cookies"); var prop = new AuthenticationProperties { RedirectUri = redirectUri }; //redirect to provided target await HttpContext.SignOutAsync("WsFederation", prop); } [AllowAnonymous] public ActionResult SignOutCallback() { if (User.Identity.IsAuthenticated) { // Redirect to home page if the user is authenticated. return RedirectToAction("Index", "Home"); } return View(); } Startup.cs public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(sharedOptions => { sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; }) .AddWsFederation(options => { options.Wtrealm = Configuration["Federation:idaWtrealm"]; options.MetadataAddress = Configuration["Federation:idaADFSMetadata"]; }) .AddCookie(); Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true; services.AddControllersWithViews(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(policy)); }); services.AddRazorPages(); services.AddRouting(options => options.LowercaseUrls = true); services.AddHttpContextAccessor(); // Add functionality to inject IOptions<T> services.AddOptions(); // Add our Config object so it can be injected services.Configure<EndpointOptions>(Configuration.GetSection("Endpoints")); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/home/error"); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}"); endpoints.MapRazorPages(); }); }
Make sure the certificate from Webapp B is installed to the certificate store on the sever Webapp A runs. In the Web.config for Webapp A add a certificate reference (update the values in the curly braces): <serviceCertificate> <certificateReference x509FindType="FindByThumbprint" findValue="{{WebappB_Cert_Thumbprint}}" storeLocation="{{LocalMachine}}" storeName="{{My}}" /> </serviceCertificate> https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/windows-identity-foundation/certificatereference
IdentityServer4 Quickstart issues
I am currently at this page of the IdentityServer 4 guide http://docs.identityserver.io/en/dev/quickstarts/3_interactive_login.html and I am trying to start the MVC application. However, I keep getting this error when I start my Client application InvalidOperationException: Unable to resolve service for type 'IdentityServer4.Services.IIdentityServerInteractionService' while attempting to activate 'IdentityServer4.Quickstart.UI.HomeController'. I went into the IdentityServer4 GitHub and copied the code from there but it doesn't run at all. I am not sure how to proceed from here. This is my Startup.cs using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; namespace IdentityServerClient { public class Startup { // 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 https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddMvc(); JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.SignInScheme = "Cookies"; options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; options.ClientId = "mvc"; options.SaveTokens = true; }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseAuthentication(); app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); } } } I can't get to the login page shown on the documentation as well.
If you're using the quickstart UI, you should be using the guide on it, here: https://github.com/IdentityServer/IdentityServer4.Quickstart.UI To quote that page: Next you need to configure the authentication handlers: public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(); // some details omitted services.AddIdentityServer(); services.AddAuthentication() ... You're missing: services.AddIdentityServer() .AddInMemoryCaching() .AddClientStore<InMemoryClientStore>() .AddResourceStore<InMemoryResourcesStore>(); // <-- Add this As a result, none of the identity server services are registered to the dependency injection container, which is why you're seeing that error. Looks like the tutorial documentation you linked to is out of date. -- Here is a complete set of steps to follow: dotnet new sln -n HelloID4 dotnet new mvc -n HelloID4 dotnet sln add HelloID4/HelloID4.csproj cd HelloID4 git clone --depth 1 https://github.com/IdentityServer/IdentityServer4.Quickstart.UI cp -r IdentityServer4.Quickstart.UI/* . dotnet add package IdentityServer4 rm -r Controllers/ dotnet watch run Now modify your Startup.cs to look like this: // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddIdentityServer() .AddInMemoryCaching() .AddClientStore<InMemoryClientStore>() .AddResourceStore<InMemoryResourcesStore>(); }
UPDATE *Review this code : it may help, because i am also learning on it, and its working for me. * public void ConfigureServices(IServiceCollection services) { services.AddMvc(); var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; // configure identity server with in-memory stores, keys, clients and scopes services.AddIdentityServer() .AddDeveloperSigningCredential() .AddTestUsers(Config.GetUsers()) //.AddInMemoryClients(Config.GetClients()) // this adds the config data from DB (clients, resources) .AddConfigurationStore(options => { options.ConfigureDbContext = builder => builder.UseSqlServer(Configuration.GetConnectionString("IdentityConnectionString"), sql => sql.MigrationsAssembly(migrationsAssembly)); }) // this adds the operational data from DB (codes, tokens, consents) .AddOperationalStore(options => { options.ConfigureDbContext = builder => builder.UseSqlServer(Configuration.GetConnectionString("IdentityConnectionString"), sql => sql.MigrationsAssembly(migrationsAssembly)); // this enables automatic token cleanup. this is optional. options.EnableTokenCleanup = true; options.TokenCleanupInterval = 30; }); //.AddInMemoryIdentityResources(Config.GetIdentityResources()) //.AddInMemoryApiResources(Config.GetApiResources()) services.AddAuthentication(); } // clients want to access resources (aka scopes) public static IEnumerable<Client> GetClients() { // client credentials client return new List<Client> { new Client { ClientId = "client", AllowedGrantTypes = GrantTypes.ClientCredentials, ClientSecrets = { new Secret("secret".Sha256()) }, AllowedScopes = { "api1" } }, // resource owner password grant client new Client { ClientId = "ro.client", AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = { new Secret("secret".Sha256()) }, AllowedScopes = { "api1" } }, // OpenID Connect hybrid flow and client credentials client (MVC) }; } if you are not using in-memory service If you are getting this error : Unable to resolve service for type 'IdentityServer4.Stores.IClientStore' Register the stores and implementation explicitly : ( give a try ) services.AddScoped<IUserStore<User>, UserService>(); services.AddScoped<IClientStore, ClientService>(); services.AddScoped<IScopeStore, ScopeService>(); services.AddScoped<IPersistedGrantStore, GrantService>();
OpenIddict - hosting auth server and web api resource in same project
I want to implement an OpenIdConnect/Oauth2 server using OpenIddict in order to secure a .NET core API app. Most examples I have seen implement these as separate projects. The client app is a SPA and we are using implicit flow. I have based my solution on the code shown in the OpenIddict samples here: https://github.com/openiddict/openiddict-samples For the project I am working on it would ideally have the Auth server and API to use the same port and be in the same project. ( One of the customer's requirements is that they don't want another server to configure since they own the API resource and it will be on the same server) I have configured OpenIddict and combined it with our API project. Almost everything works correctly - the API endpoints are protected with the [Authorize] attribute and prevent access to protected API end points. However, when the API resource is protected, instead of returning a 401 Unauthorized HTTP status code, the returned result is the HTML Login page of the Auth server itself. Here is the relevant setup code in my Startup.cs file: // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseApplicationInsightsRequestTelemetry(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseDatabaseErrorPage(); app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseApplicationInsightsExceptionTelemetry(); app.UseStaticFiles(); app.UseIdentity(); app.UseCors("AllowAll"); //app.UseCors(builder => //{ // builder.AllowAnyOrigin();//)WithOrigins("http://localhost:9000"); // builder.WithMethods("GET","POST", "PUT", "DELETE", "OPTIONS"); // builder.WithHeaders("Authorization"); //}); app.UseWhen(context => !context.Request.Path.StartsWithSegments("/api"), branch => { branch.UseIdentity(); }); app.UseWhen(context => context.Request.Path.StartsWithSegments("/api"), branch => { branch.UseOAuthValidation(); }); app.UseOpenIddict(); #region Adding resource config here (api) // Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715 app.UseOAuthIntrospection(options => { options.AutomaticAuthenticate = true; options.AutomaticChallenge = true; options.Authority = "http://localhost:5000"; options.Audiences.Add("resource-server-1"); options.ClientId = "resource-server-1"; options.ClientSecret = "846B62D0-DEF9-4215-A99D-86E6B8DAB342"; }); //app.UseCors(builder => { // builder.WithOrigins("http://localhost:9000"); // builder.WithMethods("GET"); // builder.WithHeaders("Authorization"); //}); #endregion app.UseMvcWithDefaultRoute(); // Seed the database with the sample applications. // Note: in a real world application, this step should be part of a setup script. InitializeAsync(app.ApplicationServices, CancellationToken.None).GetAwaiter().GetResult(); } private async Task InitializeAsync(IServiceProvider services, CancellationToken cancellationToken) { // Create a new service scope to ensure the database context is correctly disposed when this methods returns. using (var scope = services.GetRequiredService<IServiceScopeFactory>().CreateScope()) { var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>(); //await context.Database.EnsureCreatedAsync(); var manager = scope.ServiceProvider.GetRequiredService<OpenIddictApplicationManager<OpenIddictApplication>>(); if (await manager.FindByClientIdAsync("MySPA", cancellationToken) == null) { var application = new OpenIddictApplication { ClientId = "MySPA", DisplayName = "MySPA", LogoutRedirectUri = "http://localhost:9000/signout-oidc", RedirectUri = "http://localhost:9000/signin-oidc" }; await manager.CreateAsync(application, cancellationToken); } if (await manager.FindByClientIdAsync("resource-server-1", cancellationToken) == null) { var application = new OpenIddictApplication { ClientId = "resource-server-1" }; await manager.CreateAsync(application, "846B62D0-DEF9-4215-A99D-86E6B8DAB342", cancellationToken); } } } Not sure how to implement these both side by side in the same project. As mentioned it all "works" except the API is returning the HTML login page and not a desired HTTP status
app.UseIdentity(); is present twice in your pipeline, which defeats the whole purpose of using branch.UseIdentity() in a app.UseWhen() branching builder (i.e making sure the cookies middleware registered by Identity are not invoked for your API endpoints). Remove the first occurrence and it should work.
You set the AutomaticChallenge to true. According to the documentation this flag indicates that the middleware should redirect the browser to the LoginPath or AccessDeniedPath when authorization fails. So by setting this to false it will not redirect to the login.