IdentityServer4 Invalid Scope in Client application - oauth-2.0

I am currently implementing IdentityServer4 with my microservices to authenticate users. My client application is a MVC project. While I run the project client application return an error as following,
Sorry, there was an error : invalid_scope
Invalid scope
Request Id: 8000008d-0000-f700-b63f-84710c7967bb
When I removed apiscopes from config file application works fine but then I didn't get any user claims in my authorization handler.
Here's my code
Config.cs
public static class Config
{
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
}
public static IEnumerable<ApiResource> GetApis()
{
return new List<ApiResource>
{
new ApiResource("masterweb_api", "Master API")
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "mvc",
ClientSecrets =
{
new Secret("Secret".Sha256())
},
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
RequireConsent = false,
RequirePkce = false,
// where to redirect to after login
RedirectUris = { "https://localhost:44367/signin-oidc" },
// where to redirect to after logout
FrontChannelLogoutUri = "https://localhost:44367/signout-oidc",
PostLogoutRedirectUris = { "https://localhost:44367/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"masterweb_api"
},
AllowOfflineAccess = true,
AlwaysSendClientClaims = true,
AlwaysIncludeUserClaimsInIdToken = true
}
};
}
}
AuthServer Startup.cs
public class Startup
{
public IWebHostEnvironment Environment { get; }
public IConfiguration Configuration { get; }
public Startup(IWebHostEnvironment environment, IConfiguration configuration)
{
Environment = environment;
Configuration = configuration;
}
// 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.AddControllersWithViews();
/****Register asp.net core Identity DBConetexts***/
var idenConnectionString = Configuration["DbContextSettings:IdentityConnectionString"];
var dbPassword = Configuration["DbContextSettings:DbPassword"];
var builder = new NpgsqlConnectionStringBuilder(idenConnectionString)
{
Password = dbPassword
};
services.AddDbContext<MembershipDBContext>(opts => opts.UseNpgsql(builder.ConnectionString));
services.AddIdentity<MembershipUser, MembershipRole>(options =>
{
options.Password.RequiredLength = 8;
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._#+ ";
options.SignIn.RequireConfirmedEmail = false;
}).AddRoles<MembershipRole>().AddEntityFrameworkStores<MembershipDBContext>()
.AddDefaultTokenProviders();
/****Identity Server implementation with asp.net core Identity***/
var idsServerConnectionString = Configuration["DbContextSettings:IdentityServer4ConnectionString"];
var migrationAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
//var userConnectionString = Configuration["DbContextSettings:UserConnectionString"];
var idsServerdbPassword = Configuration["DbContextSettings:DbPassword"];
var idsServerbuilder = new NpgsqlConnectionStringBuilder(idsServerConnectionString)
{
Password = dbPassword
};
var idBuilder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
options.UserInteraction.LoginUrl = "/Account/Login";
options.UserInteraction.LogoutUrl = "/Account/Logout";
options.Authentication = new AuthenticationOptions()
{
CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
CookieSlidingExpiration = true
};
}).AddDeveloperSigningCredential()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseNpgsql(idsServerbuilder.ConnectionString, sql => sql.MigrationsAssembly(migrationAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseNpgsql(idsServerbuilder.ConnectionString, sql => sql.MigrationsAssembly(migrationAssembly));
options.EnableTokenCleanup = true;
}).AddAspNetIdentity<MembershipUser>()
.AddProfileService<ProfileService>();
idBuilder.Services.ConfigureExternalCookie(options =>
{
options.Cookie.IsEssential = true;
options.Cookie.SameSite = (SameSiteMode)(-1); //SameSiteMode.Unspecified in .NET Core 3.1
});
idBuilder.Services.ConfigureApplicationCookie(options =>
{
options.Cookie.IsEssential = true;
options.Cookie.SameSite = (SameSiteMode)(-1); //SameSiteMode.Unspecified in .NET Core 3.1
});
}
private void InitializeDatabase(IApplicationBuilder app)
{
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
context.Database.Migrate();
if (!context.Clients.Any())
{
foreach (var client in Config.GetClients())
{
context.Clients.Add(client.ToEntity());
}
context.SaveChanges();
}
if (!context.IdentityResources.Any())
{
foreach (var resource in Config.GetIdentityResources())
{
context.IdentityResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
if (!context.ApiResources.Any())
{
foreach (var resource in Config.GetApis())
{
context.ApiResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
}
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
// this will do the initial DB population
InitializeDatabase(app);
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// uncomment if you want to add MVC
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
}
Api Startup.cs
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.AddControllers();
var key = AesOperation.AesKey;
//var str = Configuration["PostgreSql:ConnectionString"];
//var encryptedString = AesOperation.EncryptString(key, str);
var encryptedString = Configuration["PostgreSql:ConnectionString"];
var decryptedString = AesOperation.DecryptString(key, encryptedString);
var connectionString = decryptedString;
encryptedString = Configuration["PostgreSql:DbPassword"];
decryptedString = AesOperation.DecryptString(key, encryptedString);
var dbPassword = decryptedString;
var builder = new NpgsqlConnectionStringBuilder(connectionString)
{
Password = dbPassword
};
services.AddDbContext<MasterDbContext>(options => options.UseNpgsql(builder.ConnectionString));
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Master Microservice", Version = "v1" });
});
services.AddMediatR(typeof(Startup));
RegisterServices(services);
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddAuthorization(options =>
{
options.AddPolicy("MasterCompanyCreatePolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RoleMasterCompanyCreate", "UserMasterCompanyCreate")));
options.AddPolicy("MasterCompanyReadPolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RoleMasterCompanyRead", "UserMasterCompanyRead")));
options.AddPolicy("MasterCompanyUpdatePolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RoleMasterCompanyUpdate", "UserMasterCompanyUpdate")));
options.AddPolicy("MasterCompanyDeletePolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RoleMasterCompanyDelete", "UserMasterCompanyDelete")));
});
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:44396";
options.RequireHttpsMetadata = false;
options.Audience = "masterweb_api";
options.SaveToken = true;
});
}
private bool AuthorizeAccess(AuthorizationHandlerContext context, string roleClaim, string userClaim)
{
return context.User.HasClaim(claim => claim.Type == roleClaim) &&
context.User.HasClaim(claim => claim.Type == userClaim) ||
context.User.IsInRole("SuperAdmin");
}
private void RegisterServices(IServiceCollection services)
{
DependencyContainer.RegisterServices(services);
}
// 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.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Master Microservice V1");
});
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Mvc Startup.cs
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.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddAuthorization(options =>
{
options.AddPolicy("MasterCompanyCreatePolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RoleMasterCompanyCreate", "UserMasterCompanyCreate")));
options.AddPolicy("MasterCompanyReadPolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RoleMasterCompanyRead", "UserMasterCompanyRead")));
options.AddPolicy("MasterCompanyUpdatePolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RoleMasterCompanyUpdate", "UserMasterCompanyUpdate")));
options.AddPolicy("MasterCompanyDeletePolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RoleMasterCompanyDelete", "UserMasterCompanyDelete")));
//options.AddPolicy("SaleCancelPolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RoleSaleCancel", "UserSaleCancel")));
});
services.AddControllersWithViews();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = "cookie";
options.DefaultChallengeScheme = "oidc";
}).AddCookie("cookie")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "cookie";
options.Authority = "https://localhost:44396";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.ClientSecret = "Secret";
options.ResponseType = "code id_token";
options.UsePkce = false;
options.Scope.Add("masterweb_api");
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
});
}
private bool AuthorizeAccess(AuthorizationHandlerContext context, string roleClaim, string userClaim)
{
return context.User.HasClaim(claim => claim.Type == roleClaim) &&
context.User.HasClaim(claim => claim.Type == userClaim) ||
context.User.IsInRole("SuperAdmin");
}
// 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();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
RotativaConfiguration.Setup(env.WebRootPath, "Rotativa");
}
}
How to solve this issue. I am totally clueless. Thanks in advance.

You should change the grant type to Code and also enable PKCE, because that is best practice to use when you use the authorization code flow.

Related

IdentityServer token return UnAuthorized when calling from Client

Im protecting my API with IdentityServer and
I can get token from server in client mvc app successfully but when passing the token in Header when "Authorize" enable i'm getting unauthorized error .
And http client using Async call.
below is my entire code
Not sure why getting unauthorized when i'm getting token from server without any issue.
Please guide/Help.
Thanks
Identity Server:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var builder = services.AddIdentityServer(
options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
});
// in-memory, json config
// builder.AddInMemoryIdentityResources(Configuration.GetSection("IdentityResources"));
builder.AddInMemoryApiResources(Configuration.GetSection("ApiResources"));
builder.AddInMemoryClients(Configuration.GetSection("clients"));
//TODO: replace PROD siging certificate
builder.AddDeveloperSigningCredential();
services.AddAuthentication();
services.AddTransient<ITokenCreationService, TokenService>();
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment()) { app.UseDeveloperExceptionPage();}
app.UseIdentityServer();
}
}
Protected API:
public void ConfigureServices(IServiceCollection services)
{
var config = Configuration.GetSection("AuthSettings").Get<AuthSettings>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(o =>
{
o.Authority = config.AuthUrl;
o.Audience = config.AuthAudience;
o.RequireHttpsMetadata = false;
o.SaveToken = true;
o.BackchannelHttpHandler = new HttpClientHandler()
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator,
Proxy = new WebProxy(Configuration["System:Proxy"])
};
});
services.AddControllers();
services.AddSingleton(typeof(IAppLogger<>), typeof(SerilogService<>));
services.AddCustomMvc();
KeySettings keySettings = new KeySettings(Configuration.GetSection("KeySettings")["Thumbprint"]);
services.AddSingleton(keySettings);
services.AddScoped<CommandQueryMediator>();
services.AddCommandQueryHandlers(typeof(GetPageMetadata).Assembly);
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingProfile());
mc.AddProfile(new DomainToDtoMappingProfile());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Automation API", Version = "v1" });
});
IdentityModelEventSource.ShowPII = true;
}
// 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();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Client MVC app:
public void ConfigureServices(IServiceCollection services)
{
var authConfig = Configuration.GetSection("AppSettings").Get<AppSettings>();
// Adds an instance of the class that contains credentials
services.AddSingleton(new ClientCredentialsTokenRequest
{
Address = authConfig.AuthURL,
ClientId = authConfig.AuthClientId,
ClientSecret = authConfig.AuthClientSecret,
Scope = authConfig.AuthScope
});
services.AddControllersWithViews();
services.AddRepository(Configuration);
services.AddHttpContextAccessor();
services.AddDataProtection()
.SetApplicationName("DataTransition_Web")
.PersistKeysToFileSystem(new DirectoryInfo(Configuration.GetSection("AppSettings")["DataProtectionKeyPath"]))
.UseCryptographicAlgorithms(
new AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// 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(); }
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
}
Call to API with Token:
public async Task<ReviewSearchViewModel> SearchReviews()
{
try
{
var apiClientCredentials = new ClientCredentialsTokenRequest
{
Address = "http://localhost:20102/connect/token",
ClientId = "automation.portal",
ClientSecret = "0b4168e4-2832-48ea-8fc8-7e4686b3620b",
Scope = "automation.apiscope",
};
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("http://localhost:20102");
// 2. Authenticates and get an access token from Identity Server
var tokenResponse = await client.RequestClientCredentialsTokenAsync(apiClientCredentials);
var model = new ReviewSearchViewModel();
ReviewSearchResultDto _reviewSearchResultObj = await WebAPIHelper.GetAPIData<ReviewSearchResultDto>(
appSettings.ReviewSearchUrl,
loggedinUser.CookieCollection, tokenResponse.AccessToken);
if (_reviewSearchResultObj != null )
{
model = mapper.Map<ReviewSearchResultDto, ReviewSearchViewModel>(_reviewSearchResultObj, opt =>
{
opt.AfterMap((src, dest) =>
{
});
});
return model;
}
else
{
return new ReviewSearchViewModel();
}
}
catch (Exception ex)
{
logger.LogWarning("WEB | ERROR | ", ex);
}
Helper Method GetAPIData:
public static String GetAPIData(String url, Dictionary<String, Object> headerdata = null,string accessToken=null)
{
string APIsecretkey = "APISecretKeyTest";
string response = String.Empty;
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
try
{
//DEV ONLY
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
//_logger.LogInformation("Starting API Call to " + url);
//Set HttpWebRequest properties
httpWebRequest.Method = "GET";
httpWebRequest.ContentType = "application/json; encoding='utf-8'";
httpWebRequest.Accept = "application/json; encoding='utf-8'";
//TODO: token type should be from config.
if(! String.IsNullOrWhiteSpace(accessToken))
httpWebRequest.Headers.Add("Authorization", "Bearer" + accessToken);
using (HttpWebResponse httpWebResponse = (HttpWebResponse) httpWebRequest.GetResponse())
{
//_logger.LogInformation("Completed API Call to " + url);
if (httpWebResponse.StatusCode == HttpStatusCode.OK) //200
{
//Get response stream into StreamReader
using (Stream responseStream = httpWebResponse.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
response = reader.ReadToEnd();
}
}
else
{
APIException apiException = new APIException();
apiException.StatusCode = httpWebResponse.StatusCode;
throw apiException;
}
}
}
catch (WebException we) when ((we.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound)
{
//_logger.LogError("API Notfound Error:",we);
throw AuthException(we, HttpStatusCode.NotFound);
}
catch (WebException we) when ((we.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.BadRequest)
{
//_logger.LogError("API BadRequest Error:", we);
throw AuthException(we, HttpStatusCode.BadRequest);
}
catch (WebException we) when ((we.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.InternalServerError)
{
//_logger.LogError("API InternalServerError Error:", we);
throw AuthException(we, HttpStatusCode.InternalServerError);
}
catch (Exception ex)
{ //_logger.LogError("API Exception Error:", ex);
throw new Exception(ex.Message);
}
finally
{
httpWebRequest = null;
}
return response;
}
You are using `httpWebRequest.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);'
You need to have a space between "Bearer" and the access token string.
It would be better to use AuthenticationHeaderValue instead to handle this for you:
httpWebRequest.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

.NET Core 3.1 IdentityServer4: getting invalid access token when using Resource Owner Password Credentials grant

I'm trying to get an access token from Identity Provider using Resource Owner Password Credentials grant type. The same configuration worked for .NET Core 2.2, but it doesn't work anymore for .NET Core 3.1. Here is the configuration of Identity Provider:
public class Startup
{
public IConfiguration Configuration { get; }
private readonly string _MyAllowSpecificOrigins = "fooorigin";
private readonly IWebHostEnvironment _env;
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
IdentityModelEventSource.ShowPII = true;
_env = env;
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddPersistence(Configuration); //Custom extension
services.AddAutoMapper(Assembly.GetAssembly(typeof(BaseMappingProfile)));
#region Options
services.Configure<IdentityServerOptions>(Configuration.GetSection("IdentityServerOptions"));
services.Configure<Settings>(Configuration.GetSection("Settings"));
#endregion
#region Configurations
services.AddTransient<IdentityServerOptions>();
#endregion
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<ITokenManagerHelper, TokenManagerHelper>();
services.AddScoped<IUserService, UserService>();
services.AddCors(options =>
{
options.AddPolicy(_MyAllowSpecificOrigins,
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddMvc().AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblyContaining<CommonValidator>();
fv.ImplicitlyValidateChildProperties = true;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
var identityServerDataDBConnectionString = Configuration.GetConnectionString("IdentityServerConfigDatabase");
var migrationsAssembly = typeof(UsersDbContext).GetTypeInfo().Assembly.GetName().Name;
var identityAuthority = Configuration.GetValue<string>("IdentityServerOptions:Authority");
// Add Authentication
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = "oidc";
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = Configuration.GetValue<string>("IdentityServerOptions:Authority");
options.ClientId = Configuration.GetValue<string>("IdentityServerOptions:ClientName");
options.ClientSecret = Configuration.GetValue<string>("IdentityServerOptions:ClientSecret");
options.ResponseType = Configuration.GetValue<string>("IdentityServerOptions:ResponseType");
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("roles");
options.Scope.Add("fooapi");
options.Scope.Add("fooidentityapi");
options.Scope.Add("offline_access");
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.ClaimActions.Remove("amr");
options.ClaimActions.DeleteClaim("sid");
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.GivenName,
RoleClaimType = JwtClaimTypes.Role,
};
});
services.AddTransient<IPersistedGrantStore, PersistedGrantStore>();
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
// Add Identity Server
// Add Signing Certificate
// Add Users Store
// Add Configurations Store
// Add Operational Stores
if (_env.IsDevelopment() || _env.IsStaging())
{
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddUserStore()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
{
builder.UseSqlServer(identityServerDataDBConnectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
};
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
{
builder.UseSqlServer(identityServerDataDBConnectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
};
})
.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>();
}
else
{
//Todo: add certificate
}
}
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IOptions<Settings> settingOptions)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseCors(_MyAllowSpecificOrigins);
app.UseCookiePolicy();
var forwardOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
RequireHeaderSymmetry = false
};
forwardOptions.KnownNetworks.Clear();
forwardOptions.KnownProxies.Clear();
app.UseForwardedHeaders(forwardOptions);
app.UseAuthentication();
app.UseRouting();
app.UseIdentityServer();
}
}
And here's the configuration of API:
public class Startup
{
#region Private Fields
private readonly string _allowedOrigins = "fooorigin";
#endregion
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthorization();
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = Configuration.GetValue<string>("IdentityServerOptions:Authority");
options.RequireHttpsMetadata = false;
options.ApiName = Configuration.GetValue<string>("IdentityServerOptions:ApiName");
options.SupportedTokens = IdentityServer4.AccessTokenValidation.SupportedTokens.Jwt;
});
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
#region Options
services.AddOptions();
#endregion
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddCors(options =>
{
options.AddPolicy(_allowedOrigins, builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddAntiforgery(options =>
{
options.HeaderName = "X-XSRF-TOKEN";
});
services.AddMvc(o =>
{
o.EnableEndpointRouting = false;
o.Conventions.Add(new ApiExplorerGroupPerVersionConvention());
o.Filters.Add(new ModelStateFilter());
}).AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblyContaining<CommonValidator>();
fv.ImplicitlyValidateChildProperties = true;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
#region Customise default API behavour
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
#endregion
#region Versioning
services.AddApiVersioning(o =>
{
o.ApiVersionReader = new HeaderApiVersionReader("api-version");
o.DefaultApiVersion = new ApiVersion(1, 0);
o.AssumeDefaultVersionWhenUnspecified = true;
o.ReportApiVersions = true;
});
#endregion
#region Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1.0", new OpenApiInfo
{
Title = Configuration.GetValue<string>("SwaggerDocOptions:Title"),
Version = Configuration.GetValue<string>("SwaggerDocOptions:Version"),
Description = Configuration.GetValue<string>("SwaggerDocOptions:Description")
});
c.OperationFilter<RemoveApiVersionFromParamsOperationFilter>();
var basePath = PlatformServices.Default.Application.ApplicationBasePath;
var xmlPath = Path.Combine(basePath, "foo.xml");
c.IncludeXmlComments(xmlPath);
var scopes = Configuration.GetValue<string>("IdentityServerOptions:RequiredScopes").Split(',').ToList();
var scopesDictionary = new Dictionary<string, string>();
foreach (var scope in scopes)
{
scopesDictionary.Add(scope, scope);
}
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = SecuritySchemeType.OAuth2,
Scheme = "Bearer",
Flows = new OpenApiOAuthFlows
{
Password = new OpenApiOAuthFlow
{
TokenUrl = new Uri(Configuration.GetValue<string>("IdentityServerOptions:TokenEndpoint")),
Scopes = scopesDictionary
}
},
In = ParameterLocation.Header
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Type = SecuritySchemeType.Http,
Scheme = "Bearer",
Name = "Bearer",
In = ParameterLocation.Header
},
new List<string>()
}
});
});
#endregion
}
/// <summary>
/// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
/// </summary>
/// <param name="app">Application builder</param>
/// <param name="env">Web host environment</param>
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseCors(_allowedOrigins);
app.UseAuthentication();
app.UseSerilogRequestLogging();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseSwagger(
o =>
{
o.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
{
var paths = new OpenApiPaths();
foreach (var x in swaggerDoc.Paths)
{
var key = x.Key.Contains("{version}") ? x.Key.Replace("{version}", swaggerDoc.Info.Version) : x.Key;
paths.Add(key, x.Value);
}
swaggerDoc.Paths = paths;
swaggerDoc.Extensions.Add(
new KeyValuePair<string,
IOpenApiExtension>("x-identity-authority",
new OpenApiString(Configuration.GetValue<string>("IdentityServerOptions:Authority"))));
});
o.RouteTemplate = "docs/{documentName}/swagger.json";
});
app.UseSwaggerUI(
c =>
{
c.SwaggerEndpoint("/docs/v1.0/swagger.json", "Foo API");
c.OAuthClientId(Configuration.GetValue<string>("IdentityServerOptions:ClientName"));
c.OAuthClientSecret(Configuration.GetValue<string>("IdentityServerOptions:ClientSecret"));
}
);
}
}
Now let's look at the process of getting an access token:
When I press "Authorize", it's validating and gets a token:
but when I try to access API resource which requires an authorization, it returns 401 error:
I tried to check the same in the Postman and when I try to access token endpoint it returns the access token like that:
I've been working for hours, tried many things but nothing worked. I tried to provide everything that can be cause of this problem, any help will be appreciated, thanks in advance.
After researching I found out that the ApiName must be the same as the name of the audience, also we should configure clients for JWT tokens, not the reference tokens.

How to solve Usermanage System.AggregateException: 'One or more errors occurred.'

The code was working perfectly but all of a sudden the seed method for the user is no longer working after I push to the production server with a fresh database.
Startup.cs
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.AddDbContext<ApplicationDbContext>(options =>
options.UseMySql(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<IdentityUser, IdentityRole>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequiredLength = 4;
options.Password.RequireUppercase = false;
})
.AddErrorDescriber<JapaneseErrorDescriber>()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddDefaultUI()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddDistributedMemoryCache();
services.AddMemoryCache();
services.AddHttpContextAccessor();
services.AddSession(options =>
{
options.Cookie.Name = ".AdventureWorks.Session";
options.IdleTimeout = TimeSpan.FromDays(365);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, UserManager<IdentityUser> userManager, ApplicationDbContext context, IServiceProvider service)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
ApplicationDbInitializer.SeedUsers(userManager, context);
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
-- Seed method
public static void SeedUsers(UserManager<IdentityUser> userManager, ApplicationDbContext context)
{
if (userManager.FindByEmailAsync("admin#admin.com").Result == null)
{
IdentityUser user = new IdentityUser
{
UserName = "admin#admin.com",
Email = "admin#admin.com"
};
IdentityResult result = userManager.CreateAsync(user, "adminpass").Result;
> System.AggregateException: 'One or more errors occurred. (Object reference not set to an instance of an object.)'
> NullReferenceException: Object reference not set to an instance of an object.
if (result.Succeeded)
{
userManager.AddToRoleAsync(user, "Admin").Wait();
}
}
}
So I deleted all the data from the Dev Database and tried to see what was going on. In debugging mode, I was getting the instance of the Usermanger but when the call to the CreateAsync() was called the error occurs.

401 Unauthorized : WWW-Authenticate: Bearer

I've seen similar threads to this issue, but I had no luck solving it.
LogIn worked successfuly but when I try to GET data of the user loggedIn in my home page I receive this error 401 Unauthorized the same erroe is showen also in Postman
My startup.cs
public class Startup
{
private string _connectionString=null;
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)
{
//Inject AppSettings
services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
_connectionString = Configuration["secretConnectionstring"];
//without this it will define for example id to Id
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(options => {
var resolver = options.SerializerSettings.ContractResolver;
if (resolver != null)
(resolver as DefaultContractResolver).NamingStrategy = null;
});
services.AddEntityFrameworkNpgsql()
.AddDbContext<ApiContext>(
opt => opt.UseNpgsql(_connectionString));
services.AddEntityFrameworkNpgsql()
.AddDbContext<AuthentificationContext>(
options => options.UseNpgsql(_connectionString));
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<AuthentificationContext>();
services.Configure<IdentityOptions>(options => {
options.Password.RequireDigit = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 4;
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
// Jwt Authentification
var key = Encoding.UTF8.GetBytes(Configuration["ApplicationSettings:JWT_Secret"].ToString());
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x=> {
x.RequireHttpsMetadata = false;
x.SaveToken = false;
x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero
};
});
services.AddTransient<dataSeed>();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, dataSeed seed)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
// global policy - assign here or on each controller
app.UseCors("CorsPolicy");
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
app.UseAuthentication();
}
}
}
UserprofileController
{
[Route("api/[controller]")]
[ApiController]
public class UserProfileController : ControllerBase
{
private UserManager<ApplicationUser> _userManager;
public UserProfileController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
[HttpGet]
[Authorize]
//GET : /api/UserProfile
public async Task<Object> GetUserProfile()
{
string userId = User.Claims.First(c => c.Type == "UserID").Value;
var user = await _userManager.FindByIdAsync(userId);
return new
{
user.fullName,
user.Email,
user.UserName
};
}
}
}
UserServices
headers = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json'
})
}
readonly BaseUrl = 'http://localhost:53847/api';
constructor(private fb: FormBuilder, private http: HttpClient) { }
formModel = this.fb.group({
UserName: ['', Validators.required],
Email: ['', Validators.email],
fullName: ['', Validators.required],
Passwords: this.fb.group({
Password: ['',[Validators.required, Validators.minLength(4)]],
ConfirmPassword: ['', Validators.required],
}, { validator : this.comparePasswords})
});
comparePasswords(fb: FormGroup) {
let confirmPswdCtrl = fb.get('ConfirmPassword');
//passowrdMismatch
//confirmPswdCtrl.errors={passowrdMismatch:true}
if (confirmPswdCtrl.errors == null || 'passowrdMismatch' in confirmPswdCtrl.errors) {
if (fb.get('Password').value != confirmPswdCtrl.value)
confirmPswdCtrl.setErrors({ passowrdMismatch: true });
else
confirmPswdCtrl.setErrors(null);
}
}
register() {
var body = {
UserName: this.formModel.value.UserName,
Email: this.formModel.value.Email,
fullName: this.formModel.value.fullName,
Password: this.formModel.value.Passwords.Password,
};
return this.http.post(this.BaseUrl + '/ApplicationUser/Register', body, this.headers);
}
login(formData) {
return this.http.post(this.BaseUrl + '/ApplicationUser/Login', formData, this.headers);
}
getUserProfile() {
var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer' + localStorage.getItem('token'), 'Content-Type': 'application/json' });
return this.http.get(this.BaseUrl + '/UserProfile', { headers: tokenHeader });
}
}
ApplicationUserController the PostMethod
[HttpPost]
[Route("Login")]
//POST : /api/ApplicationUser/Login
public async Task<IActionResult> Login(LoginModel model)
{
var user = await _userManager.FindByNameAsync(model.UserName);
if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
{
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim("UserID",user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.JWT_Secret)), SecurityAlgorithms.HmacSha256Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var securityToken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(securityToken);
return Ok(new { token });
}
else
return BadRequest(new { message = "Username or password is incorrect." });
}
}
Help Plz .. Thx
In my case I wasn't getting an error and everything appeared to work but my API returned 401 every time.
Having banged my head a lot on this.
I had ...
[Authorize]
on my Controller and found that the site was trying to use cookie authentication so although my JWT worked fine, the lack of a cookie auth made it fail.
I changed the attribute to ...
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
and this fixed the issue as now the controller ignores cookie auth and concentrates only on jwt.
Hope this helps someone
I found that changing the order of statements was my problem. Configure() requires ASP.NET Core middleware to be in the correct order.
This DID NOT work, and required me to add [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] to every controller...
app.UseAuthorization();
app.UseAuthentication();
This DOES work:
app.UseAuthentication();
app.UseAuthorization();
One problem I see is here:
var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer' + localStorage.getItem('token'), 'Content-Type': 'application/json' });
When specifying a Bearer token, you need to leave a space between Bearer and the token itself, so that the result looks like this:
Authorization: <type> <credentials>
In your case, that would translate to:
Authorization: Bearer token
However, if you look at the code above, you'll see you're actually going to supply it like so:
Authorization: Bearertoken
which isn't going to work. Therefore, change your code to be:
var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer ' + localStorage.getItem('token'), 'Content-Type': 'application/json' });
// ---------------------------------------------------------^ Notice I've added a space here.
The code you show does not have the UseAuthorization() declaration.
In .NET 6 I am doing:
builder.Services.AddAuthentication(opt =>
{
opt.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:XXXX";
options.Audience = "idwebclient";
options.TokenValidationParameters.ValidateAudience = false;
options.TokenValidationParameters.IssuerSigningKey =
new SymmetricSecurityKey(Encoding.UTF8.GetBytes("XXXXXXXXXXXXXXXXXXXXXXXXX"));
});
Recap
In my case I was not using any Identity Server Yet I was providing the Host as a ValidIssuer.
It validated the Authority for the algo and keys which returned nothing, this caused the system to throw an unhandled exception.
Solved this By Removing options.Authority from JwtBearerOptions in AddJwtBearer(options => ...).
After that I faced the 401 ERROR, resolved it by removing options.Audience from JwtBearerOptions in AddJwtBearer(options => ...), Also added ValidateLifetime to TokenValidationParameters (which you can see below in part 1)
Code
PART (1) JWT Configuration
in .NET 6 :
builder.services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuerSigningKey = jwtSettings.ValidateIssuerSigningKey,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.IssuerSigningKey)),
ValidateIssuer = jwtSettings.ValidateIssuer,
ValidIssuer = jwtSettings.ValidIssuer,
ValidateAudience = jwtSettings.ValidateAudience,
ValidAudience = jwtSettings.ValidAudience,
RequireExpirationTime = jwtSettings.RequireExpirationTime,
ValidateLifetime = jwtSettings.RequireExpirationTime,
ClockSkew = TimeSpan.FromDays(1),
};
});
Extra
GET your JWT Settings from Appsettings using Either this
Where
"JsonWebTokenKeys"
is the name of section in configuration :
var jwtSettings = new JwtSettings();
Configuration.Bind("JsonWebTokenKeys", jwtSettings);
builder.services.AddSingleton(jwtSettings);
//PART (1) => JWT Configuration goes here
//..
//..
OR this :
services.Configure<JwtSettings>(configuration.GetSection("JsonWebTokenKeys"));
using (ServiceProvider serviceProvider = services.BuildServiceProvider())
{
var jwtSettings = serviceProvider.GetRequiredService<IOptions<JwtSettings>>().Value;
//PART (1) => JWT Configuration goes here
//..
//..
}

JWT Token based Authentication in Azure AD

i m getting below Error in startup.css while authenticateing token issued by Azure AD
JwtBearerAppBuilderExtensions.UseJwtBearerAuthentication(IA‌​pplicationBuilder, JwtBearerOptions)' is obsolete: 'See go.microsoft.com/fwlink/?linkid=845470';
And my code is
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAD:Tenant"]),
Audience = Configuration["AzureAd:Audience"],
});
Any suggestion please i am new to Azure and web API?
Thanks
Use the nuget package Microsoft.Owin.Security.ActiveDirectory instead:
app.UseWindowsAzureActiveDirectoryBearerAuthentication(new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["AzureAd:Audience"]
},
Tenant = ConfigurationManager.AppSettings["AzureAd:AADInstance"]
});
and with the below code i got it working now..Thanks
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwtOptions =>
{
jwtOptions.Authority = String.Format(Configuration["Logging:AzureAd:AadInstance"], Configuration["Logging:AzureAD:Tenant"]);
jwtOptions.Audience = Configuration["Logging:AzureAd:Audience"];
jwtOptions.Events = new JwtBearerEvents
{
OnAuthenticationFailed = AuthenticationFailed
};
});
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseAuthentication();
app.UseMvc();
}
private Task AuthenticationFailed(AuthenticationFailedContext arg)
{
// For debugging purposes only!
var s = $"AuthenticationFailed: {arg.Exception.Message}";
arg.Response.ContentLength = s.Length;
arg.Response.Body.Write(Encoding.UTF8.GetBytes(s), 0, s.Length);
return Task.FromResult(0);
}

Resources