Authorization in .Net Framework 4.8 returns Unauthorized using OpenIdentity4 - rest

I'm trying to use Authorization in .Net Framework 4.8, but making a get request returns Unauthorized using OpenIdentity4
I have to use Framework and not Core!
This is my Startup.cs:
public void Configuration(IAppBuilder app)
{
var authority = "https://localhost:5001";
var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(
authority + "/.well-known/openid-configuration",
new OpenIdConnectConfigurationRetriever(),
new HttpDocumentRetriever());
var discoveryDocument = Task.Run(() => configurationManager.GetConfigurationAsync()).GetAwaiter().GetResult();
System.Console.WriteLine(discoveryDocument.AuthorizationEndpoint);
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
TokenValidationParameters = new TokenValidationParameters()
{
ValidateAudience = false,
}
}) ;
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "RestAPI",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
app.UseWebApi(config);
}
}
}
OpenIdentity4 is running on https://localhost:5001
It's Startup:
public class Startup
{
public IWebHostEnvironment Environment { get; }
public Startup(IWebHostEnvironment environment)
{
Environment = environment;
}
public void ConfigureServices(IServiceCollection services)
{
var builder = services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients);
services.AddControllers();
services.AddAuthorization(options =>
{
options.AddPolicy("ApiScope", policy => {
policy.RequireAuthenticatedUser();
policy.RequireClaim("RestAPI", "APIRest");
});
});
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// uncomment if you want to add MVC
//app.UseStaticFiles();
//app.UseRouting();
app.UseIdentityServer();
app.UseRouting();
// uncomment, if you want to add MVC
app.UseAuthorization();
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapDefaultControllerRoute();
//});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers()
.RequireAuthorization("ApiScope");
});
}
}
}
It's probably a stupid mistake, but I can't figure it out.

Related

Unable to create an object of type 'ApplicationDbContex' Blazor ASP.NET Core 6.0

I'm creating a web application in Blazor ASP.NET Core web hosted with ASP.NET Core 6 and when I'm migrating the database I'm getting this error:
Unable to create an object of type 'ApplicationDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
I need to get a solution - this is my code:
Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Prueba")));
builder.Services.AddDefaultIdentity<ApplicationUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["JwtIssuer"],
ValidAudience = builder.Configuration["JwtAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JwtSecurityKey"]))
};
});
builder.Services.AddAuthorization(config =>
{
config.AddPolicy(Policies.IsAdmin, Policies.IsAdminPolicy());
config.AddPolicy(Policies.IsUser, Policies.IsUserPolicy());
});
builder.Services.AddSignalR();
builder.Services.AddMvc().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
builder.Services.AddControllersWithViews();
//builder.Services.AddRazorPages();
builder.Services.AddResponseCompression(option =>
{
option.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat
(new[] { "application/octet-stream"
});
});
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
SeedData.Initialize(services);
}
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebAssemblyDebugging();
}
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.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<UsuariosHub>("/UsuariosHub");
});
app.Run();
ApplicationDbContext.cs
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using ProyectoBP.Shared.Models;
namespace ProyectoBP.Server.Data;
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
public DbSet<Movie> Movies { get; set; }
}
SeedData.cs
using Microsoft.EntityFrameworkCore;
using ProyectoBP.Server.Data;
namespace ProyectoBP.Shared.Models
{
public static class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var context = new ApplicationDbContext(
serviceProvider.GetRequiredService<
DbContextOptions<ApplicationDbContext>>()))
{
context.SaveChanges();
if (context == null || context.Movies == null)
{
throw new ArgumentNullException("Null ApplicationDbContext");
}
// Look for any movies.
if (context.Movies.Any())
{
return; // DB has been seeded
}
context.SaveChanges();
}
}
}
}
appsettings.json
{
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Data Source=ISMAEL-PC;Initial Catalog=BP;Integrated Security=False;uid=JoseD;password=Laugama2021.",
"Prueba": "Data Source=ISMAEL-PC;Initial Catalog=BP;Integrated Security=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
I don't have a StartUp Class because apparently in ASP.NET Core 6 it's not needed
Add parameterless constructor on your DbContext (ApplicationDbContext.cs)
public ApplicationDbContext ()
{
}
Make sure you set the default startup project to the WebApplication
or add -s {Satrtup project name here} at end of the update command
Add Microsoft.EntityFrameworkCore.Design package to the WebApplication project
I solved my problem by checking the include prerelease option since I'm using ASP.NET Core 6 in a prerelease version but I was trying to migrate with the current stable version. So I hope this can help you.
You should replace
serviceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>()
to
serviceProvider.GetRequiredService<ApplicationDbContext>()
in SeedData class :
using Microsoft.EntityFrameworkCore;
using ProyectoBP.Server.Data;
namespace ProyectoBP.Shared.Models
{
public static class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
using (var context = serviceProvider.GetRequiredService<ApplicationDbContext>())
{
context.SaveChanges();
if (context == null || context.Movies == null)
{
throw new ArgumentNullException("Null ApplicationDbContext");
}
// Look for any movies.
if (context.Movies.Any())
{
return; // DB has been seeded
}
context.SaveChanges();
}
}
}
}
Temporary re-register all services from AddSingleton and AddScoped to AddTransient. It Worked for me.

Change EF connection string when user logs in with Identity

My question is about extending this previous post using identity to calculate the connection string for each user: ASP.NET Core change EF connection string when user logs in
I tried the following approach :
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
var c = new SqlConnectionStringBuilder
{
-- the connection string to the users repository --
};
services.AddDbContextFactory<MasterDBContext>(options =>
options.UseSqlServer(c.ConnectionString));
services.AddScoped<MasterDBContext>(p => p.GetRequiredService<IDbContextFactory<MasterDBContext>>().CreateDbContext());
services.AddDefaultIdentity<MyUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<MasterDBContext>();
services.AddTransient<IMasterUserService, MasterUserService>();
services.AddDbContextFactory<UserDbContext>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
UserDbContext:
public MyContext(IServiceProvider provider)
{
_provider = provider;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var haccess = (IHttpContextAccessor)_provider.GetService(typeof(IHttpContextAccessor));
var scopefactory = haccess.HttpContext.RequestServices.GetService<IServiceScopeFactory>();
using (var scope = scopefactory.CreateScope())
{
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<MyUser>>();
var user = userManager.GetUserAsync(haccess.HttpContext.User).Result;
var userServ = scope.ServiceProvider.GetRequiredService<IMasterUserService>();
optionsBuilder.UseSqlServer(userServ.GetConnectionString(user).Result);
}
base.OnConfiguring(optionsBuilder);
}
But, even in a scope, no way to get access to UserManager service (usermanager injection works fine from others services and controllers). I get an "invalid operation exception" at the usermanager connection point.
What is wrong with that code ?
Thanks in advance
I found the solution at the end... My code in MyContext.OnConfiguring is correct if you add services.TryAddScoped<UserManager>(); in the ConfigureServices function of statup.cs.
All together, I'm able to get a connection string depending of the current user from any service :
public class MyService : IMyService
{
private IDbContextFactory _dbfactory;
public MyService(IDbContextFactory<MyContext> dbfactory)
{
_dbfactory = dbfactory;
}
public async Task AnyAsync()
{
using (var dbtf = _dbfactory.CreateDbContext())
{
... your code ...
}
}
}

EntityFrameworkCore Task.WhenAll() A second operation started on this context before a previous operation completed

I want to read data from database. For this I create a query and queryhandler classes
QueryHandler
public class OrderGetQueryHandler: IQueryHandler<OrderGetQuery, OrderDTO>
{
private readonly GoodWillWebDbContext _context;
private readonly IQueryDispatcher _queryDispatcher;
public OrderGetQueryHandler(GoodWillWebDbContext context, IQueryDispatcher queryDispatcher)
{
_context = context;
_queryDispatcher = queryDispatcher;
}
private bool CheckPartnerBlock(BlockTypes blockType, decimal debtOverdue, bool payOff)
{
if (blockType == BlockTypes.Block)
return true;
if (blockType == BlockTypes.NotBlock)
return false;
if (blockType == BlockTypes.PreliminaryPayment)
return payOff;
return debtOverdue <= 0;
}
public async Task<OrderDTO> HandleAsync(OrderGetQuery query)
{
var order = await _context.Orders.FindAsync(query.OrderID);
if (order != null)
{
var getCustomerTask = _context.Partners.FindAsync(order.CustomerID).AsTask();
var getCuratorTask = _context.Users.FindAsync(order.CuratorID).AsTask();
var getPaymentTask = _context.Payments.OrderByDescending(x => x.PaymentID).FirstOrDefaultAsync(x => x.CustomerID == order.CustomerID);
var getOrderLinesTask =
_queryDispatcher.HandleAsync<OrderLinesGetQuery, OrderLineDTO[]>(
new OrderLinesGetQuery(query.OrderID));
await Task.WhenAll(getCustomerTask, getCuratorTask, getOrderLinesTask, getPaymentTask);
var priceRange = await _context.PriceRanges.FindAsync(getCustomerTask.Result.PriceRangeID);
return new OrderDTO
(
order.OrderID,
getCustomerTask.Result.Name,
getOrderLinesTask.Result,
order.CustomerID,
order.OrderStateID,
order.CanDelete,
order.CreationDate,
getPaymentTask.Result.DebtBank,
getPaymentTask.Result.DebtOverdue,
this.CheckPartnerBlock(getCustomerTask.Result.BlockTypeID, getPaymentTask.Result.DebtOverdue, order.PayOff),
priceRange.Name,
order.ReservationDate,
Mapper.Convert<DeliveryInfoDTO, BaseEntities.Entities.Sales.Order>(order)
);
}
throw new NullReferenceException();
}
}
this queryhandler i use in ASP.NET WEB Application. My startup class is
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
string connection = Configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<GoodWillWebDbContext>(options =>
options.UseSqlServer(connection), ServiceLifetime.Transient);
services.AddScoped<IQueryHandler<OrdersGetQuery, BaseEntities.DTO.Sales.Order.OrderDTO[]>, OrdersGetQueryHandler>();
services.AddScoped<IQueryHandler<OrderGetQuery, Sales.Queries.DTO.Order.OrderDTO>, OrderGetQueryHandler>();
services.AddScoped<ICommandDispatcher, CommandDispatcher>();
services.AddScoped<IQueryDispatcher, QueryDispatcher>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
I set ServiceLifetime.Transient for my context, but I still get an exception: InvalidOperationException A second operation started on this context before a previous operation completed.
What's wrong?
It seems you're running multiple operations on the context without waiting for the previous ones to end, which EF doesn't like:
var getCustomerTask = _context.Partners.FindAsync(order.CustomerID).AsTask();
var getCuratorTask = _context.Users.FindAsync(order.CuratorID).AsTask();
var getPaymentTask = _context.Payments.OrderByDescending(x => x.PaymentID).FirstOrDefaultAsync(x => x.CustomerID == order.CustomerID);
Either make these call sync or use the await keyword.

WSFederation ADFS login loop .Net Core 2.1

While logging into ADFS(on Premise), I am being redirected after I enter in my credentials and eventually it erros out with the error Exception details: Microsoft.IdentityServer.Web.InvalidRequestException: MSIS7042: The same client browser session has made '6' requests in the last '7' seconds. Contact your administrator for details in Event Viewer. I followed couple of stack overflow suggestion(link) but couldn't resolve the issue. I am running on https and made sure the certificate are right.
Here is my code
namespace TestApp
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
private static string HtmlEncode(string content) =>
string.IsNullOrEmpty(content) ? string.Empty : HtmlEncoder.Default.Encode(content);
// 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 =>
{
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
options.Secure = CookieSecurePolicy.SameAsRequest;
});
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
options =>
{
options.Cookie.Name = ".AspNet.SharedCookie";
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
options.Cookie.SameSite = SameSiteMode.None;
})
.AddWsFederation(options =>
{
options.MetadataAddress =
$"https://adfsdomain/FederationMetadata/2007-06/FederationMetadata.xml";
options.Wtrealm = "urn:apptest";
options.Wreply = "https://appdomain/apptest";
options.CallbackPath = "/apptest";
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://adfsdomain/adfs/services/trust/"
};
options.SaveTokens = true;
options.RequireHttpsMetadata = false;
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddMvc();//.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// 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.UseHsts();
}
app.UseCors(policy => policy.SetIsOriginAllowed(origin => origin == "https://adfsdomain"));
app.UseHttpsRedirection();
app.UseStaticFiles();
app.Use(async (context, next) =>
{
if (!context.User.Identity.IsAuthenticated)
{
await context.ChallengeAsync(WsFederationDefaults.AuthenticationScheme);
}
else
{
await next();
}
});
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
I am using .Net Core 2.1 and ADFS 3.0. If I take ASP.NET MVC app and publish it with the same adfs setting my code works like charm, which tells me that the configuration on ADFS has been configured correctly.
Not sure if this can help you guys but I got my ADFS to working with the following:
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddWsFederation(options =>
{
options.Wtrealm = this._Configuration["wsfed:realm"];
options.MetadataAddress = string.Format("{0}/federationmetadata/2007-06/federationmetadata.xml", this._Configuration["wsfed:metadata"]);
})
.AddCookie();
You need app.UseAuthorization() before the app.Use(async ...). That's the middleware that takes the headers from the redirect and populates the context.User.

Identity Server 4 JWT "access_token" is not valid for Identity Server Authorized endpoints

I have an Identity Server & API apps with ResourceOwnerPasswordAndClientCredentials flow.
After getting "access_token" from RequestResourceOwnerPasswordAsync method I can use my [Authorized] endpoints in my API project, but can't access [Authorized] endpoints in my Identity Server app.
May be I'm missing something in AllowedScopes?
Identity Server's Starup.cs:
public class Startup
{
public Startup(IHostingEnvironment env, ILoggerFactory loggerFactory)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
builder.AddEnvironmentVariables();
Configuration = builder.Build();
var section = Configuration.GetSection("Logging");
loggerFactory.AddConsole(section);
loggerFactory.AddDebug();
loggerFactory.AddProvider(new FileLoggerProvider());
}
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<IdentityDataContext>(optionsAction =>
optionsAction.UseSqlServer(Configuration.GetConnectionString("DevelopersConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<IdentityDataContext>()
.AddDefaultTokenProviders();
services.AddMvc();
services.AddIdentityServer()
.AddDeveloperSigningCredential(filename: "tempkey.rsa")
.AddInMemoryClients(IdentityConfig.GetClients("http://localhost:7017"))
.AddInMemoryIdentityResources(IdentityConfig.GetIdentityResources())
.AddInMemoryApiResources(IdentityConfig.GetApiResources())
.AddAspNetIdentity<ApplicationUser>();
services.AddCors();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink();
}
RolesData.SeedRoles(app).Wait();
app.UseCors(x =>
x.WithOrigins("http://localhost:7017")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
);
app.UseStaticFiles();
app.UseIdentityServer();
app.UseMvc();
}
}
Web Api Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient(typeof(IDataRepository<>), typeof(DataRepository<>));
services.AddDbContext<DataContext>(optionsAction =>
optionsAction.UseSqlServer(Configuration.GetConnectionString("DevelopersConnection")));
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddAuthentication(
JwtBearerDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:7777"; // Auth Server
options.RequireHttpsMetadata = false; // only for development
options.ApiName = "api"; // API Resource Id
options.SupportedTokens = SupportedTokens.Jwt;
});
services.AddCors();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(x =>
x.WithOrigins("http://localhost:7017")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
);
app.UseAuthentication();
app.UseMvc();
}
}
IdentityConfig.cs:
public class IdentityConfig
{
public static IEnumerable<Client> GetClients(string hostname) => new List<Client>
{
new Client
{
ClientId = "client",
ClientName = "application",
AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
AccessTokenType = AccessTokenType.Jwt,
AllowAccessTokensViaBrowser = true,
ClientSecrets = {new Secret("secret".Sha256())},
RequireConsent = false,
RedirectUris = { $"{hostname}/callback.html" },
PostLogoutRedirectUris = { $"{hostname}/index.html" },
AllowedCorsOrigins = { hostname },
AlwaysIncludeUserClaimsInIdToken = true,
AllowOfflineAccess = true,
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.OfflineAccess,
JwtClaimTypes.Role,
"api"
}
},
};
public static IEnumerable<IdentityResource> GetIdentityResources() => new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Email(),
new IdentityResources.Profile(),
new IdentityResource("role", new []{ JwtClaimTypes.Role })
};
public static IEnumerable<ApiResource> GetApiResources() => new List<ApiResource>
{
new ApiResource("api")
{
UserClaims =
{
JwtClaimTypes.Email,
JwtClaimTypes.Role,
JwtClaimTypes.IdentityProvider,
IdentityServerConstants.StandardScopes.OpenId
}
}
};
}
Getting Jwt access_token:
var disco = await DiscoveryClient.GetAsync("http://localhost:7777");
var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret");
var tokenResponse =
await tokenClient.RequestResourceOwnerPasswordAsync("username", "password", "openid api");
var access_token = tokenResponse.AccessToken;