IdentityServer4 with ASP.NET Identity and client credentials flow - c#

I have IdentityServer4 (IDS4) working with multiple apps (Blazor WASM, ASP.NET Core API) using authorization_code. I'm using ASP.NET Identity for all apps.
I added one more API controller to Identityserver4 app (Controllers/Api/AccountController) and added one client for client_credentials flow. Purpose of this client is to access AccountController from API projects with authorization.
When I call IDS/api/Account/Register, it redirects to login page. Without [Authorize] attribute, it works fine.
How can I configure authorization for a client_credentials flow client?
Here are my IDS configs:
var services = builder.Services;
var configuration = builder.Configuration;
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.Lax;
});
builder.Services.AddControllersWithViews()
.AddSessionStateTempDataProvider()
.AddRazorPagesOptions(options =>
{
//options.AllowAreas = true;
//options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
});
var connectionString = configuration.GetConnectionString("MSSQLConnection");
var applicationName = builder.Environment.ApplicationName;
services.AddDbContext<AppDbContext>(builder => builder.UseSqlServer(connectionString,
options => options.MigrationsAssembly(applicationName)));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
//.AddDefaultUI();
services.AddLogging(options =>
{
options.AddConsole();
});
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
// ..or configures IIS out-of-proc settings
services.Configure<IISOptions>(iis =>
{
iis.AuthenticationDisplayName = "Windows";
iis.AutomaticAuthentication = false;
});
// ..or configures IIS in-proc settings
services.Configure<IISServerOptions>(iis =>
{
iis.AuthenticationDisplayName = "Windows";
iis.AutomaticAuthentication = false;
});
services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseSuccessEvents = true;
options.Discovery.ShowIdentityScopes = false;
options.Discovery.ShowApiScopes = false;
options.Discovery.ShowClaims = false;
options.Discovery.ShowExtensionGrantTypes = false;
options.UserInteraction.LoginUrl = "/Account/Login";
options.UserInteraction.LogoutUrl = "/Account/Logout";
options.Authentication = new IdentityServer4.Configuration.AuthenticationOptions()
{
CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
CookieSlidingExpiration = true
};
})
.AddOperationalStore(options => options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString, options => options.MigrationsAssembly(applicationName)))
.AddConfigurationStore(options => options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString, options => options.MigrationsAssembly(applicationName)))
.AddAspNetIdentity<ApplicationUser>()
.AddInMemoryCaching()
.AddResourceOwnerValidator<ResourceOwnerPasswordValidatorService>()
.AddSigningCredential(certificate);
services.AddAuthentication();
services.AddLocalApiAuthentication();
services.AddAuthorization(options =>
{
options.AddPolicy(Roles.Admin,
policy => policy.RequireClaim(JwtClaimTypes.Role, Roles.GetRoleName(UserRole.Admin)));
options.AddPolicy(Roles.SuperAdmin, policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(JwtClaimTypes.Role, Roles.SuperAdmin) || context.User.HasClaim(JwtClaimTypes.Role, Roles.Admin)));
});
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(10);
});
Update (Resolution)
Finally resolved using Bearer AuthenticationScheme support to IDS for Api Endpoints
In Program.cs
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = IdentityServerUtility.Authority;
options.ApiName = "IDS_API";
});
In Controller Authorization including policy works fine.
[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)]
public class AccountController : ControllerBase
{
[Authorize(Policy=Roles.Admin)]
[HttpPost("Register")]
public async Task<AppActionResult> Register([FromBody] UserDto model)
{
//...
}
}
Thank you.

Related

Handle Azure AD authentication in offline

Called Microsoft's azure ad api to get the configuration in the below code snippet,
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options =>
{
options.Instance = AzureADDetail.AuthenticationEndpoint;
options.Domain = ServerAppConfig.IdaTenant;
options.TenantId = "common";
});
services.AddAuthorization(options =>
{
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
JwtBearerDefaults.AuthenticationScheme,
AzureADDefaults.BearerAuthenticationScheme);
defaultAuthorizationPolicyBuilder =
defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});
}
During offline startup some API requests are failing, so changed like below and removed AddAuthentication of azure authentication,
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
JwtBearerDefaults.AuthenticationScheme);
defaultAuthorizationPolicyBuilder =
defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});
}
How to make the first sample to work in both online (network connected) and offline (network disconnected) of the machine during startup of c# api application in .netcore?

System.InvalidOperationException: IDX20803: Unable to obtain configuration from (OKTA)

I'm trying to implement the Okta.AspNetCore middleware based on their docs on their GitHub page https://github.com/okta/okta-aspnet/blob/master/docs/aspnetcore-webapi.md but to no avail.
This is the stack trace:
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[3]
Exception occurred while processing message.
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://company.oktapreview.com/oauth2/aus17ct73zmZrZjbh0h8/.well-known/openid-configuration'.
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Here is my config in program.cs
using Lamar;
using Lamar.Microsoft.DependencyInjection;
using Microsoft.IdentityModel.Logging;
using Microsoft.OpenApi.Models;
using NCL.StockSupplyChain.Common.Configuration;
using NCL.StockSupplyChain.PurchaseOrder.Web.API;
using NCL.StockSupplyChain.PurchaseOrder.Web.API.Classes;
using NCL.StockSupplyChain.ServiceInventory.Token;
using NCL.StockSupplyChain.ServiceInventory.Workflow;
using Okta.AspNetCore;
var corsPolicyName = "EnableCors";
var builder = WebApplication.CreateBuilder(args);
var logger = builder.Logging.Services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();
IdentityModelEventSource.ShowPII = true;
// use Lamar as DI.
builder.Host.UseLamar()
.ConfigureContainer<ServiceRegistry>(builder =>
{
builder.Scan(x =>
{
x.AssembliesFromApplicationBaseDirectory(filter => filter.FullName is not null && filter.FullName.StartsWith("NCL."));
x.TheCallingAssembly();
x.RegisterConcreteTypesAgainstTheFirstInterface();
});
});
builder.Services.AddControllers()
.AddJsonOptions(jsonOptions => jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null);
builder.Services
.AddRouting(options => options.LowercaseUrls = true)
.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "NCL.StockSupplyChain.PurchaseOrder.Web.API", Version = "v1" });
})
.AddCors(options =>
{
options.AddPolicy(name: corsPolicyName,
corsBuilder =>
{
var allowedOrigins = builder.Configuration.Get<Configuration>().Cors?.AllowedOrigins;
if (allowedOrigins?.Any() ?? false)
{
corsBuilder.WithOrigins(allowedOrigins.ToArray())
.AllowAnyHeader()
.AllowAnyMethod();
}
});
})
.AddHttpClient()
.Configure<Configuration>(builder.Configuration)
.Configure<ConnectionStringsConfiguration>(builder.Configuration.GetSection("ConnectionStrings"))
.Configure<WorkflowConfiguration>(builder.Configuration.GetSection("WorkflowService"))
.Configure<TokenConfiguration>(builder.Configuration.GetSection("TokenService"))
.AddLogging()
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = OktaDefaults.ApiAuthenticationScheme;
options.DefaultChallengeScheme = OktaDefaults.ApiAuthenticationScheme;
options.DefaultSignInScheme = OktaDefaults.ApiAuthenticationScheme;
})
.AddOktaWebApi(new OktaWebApiOptions()
{
OktaDomain = "https://company.oktapreview.com",
AuthorizationServerId = "aus17ct73zmZrZjbh0h8",
BackchannelHttpClientHandler = new MyLoggingHandler(logger),
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage()
.UseSwagger()
.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "NCL.StockSupplyChain.PurchaseOrder.Web.API"));
}
app.UseHttpsRedirection()
.UseRouting()
.UseAuthorization()
.UseCors(corsPolicyName)
.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
await app.RunAsync();
Does anyone know what I could be missing? This has left me scratching my head.
In the end I got it working with this code:
using Lamar;
using Lamar.Microsoft.DependencyInjection;
using Microsoft.IdentityModel.Logging;
using Microsoft.OpenApi.Models;
using NCL.StockSupplyChain.Common.Configuration;
using NCL.StockSupplyChain.PurchaseOrder.Web.API.Classes;
using NCL.StockSupplyChain.ServiceInventory.Token;
using NCL.StockSupplyChain.ServiceInventory.Workflow;
using Okta.AspNetCore;
var corsPolicyName = "EnableCors";
var builder = WebApplication.CreateBuilder(args);
var logger = builder.Logging.Services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();
// use Lamar as DI.
builder.Host.UseLamar()
.ConfigureContainer<ServiceRegistry>(builder =>
{
builder.Scan(x =>
{
x.AssembliesFromApplicationBaseDirectory(filter => filter.FullName is not null && filter.FullName.StartsWith("NCL."));
x.TheCallingAssembly();
x.RegisterConcreteTypesAgainstTheFirstInterface();
});
});
builder.Services.AddControllers()
.AddJsonOptions(jsonOptions => jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null);
builder.Services
.AddRouting(options => options.LowercaseUrls = true)
.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "NCL.StockSupplyChain.PurchaseOrder.Web.API", Version = "v1" });
})
.AddCors(options =>
{
options.AddPolicy(name: corsPolicyName,
corsBuilder =>
{
var allowedOrigins = builder.Configuration.Get<Configuration>().Cors?.AllowedOrigins;
if (allowedOrigins?.Any() ?? false)
{
corsBuilder.WithOrigins(allowedOrigins.ToArray())
.AllowAnyHeader()
.AllowAnyMethod();
}
});
})
.AddHttpClient()
.Configure<Configuration>(builder.Configuration)
.Configure<ConnectionStringsConfiguration>(builder.Configuration.GetSection("ConnectionStrings"))
.Configure<WorkflowConfiguration>(builder.Configuration.GetSection("WorkflowService"))
.Configure<TokenConfiguration>(builder.Configuration.GetSection("TokenService"))
.AddLogging()
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = OktaDefaults.ApiAuthenticationScheme;
options.DefaultChallengeScheme = OktaDefaults.ApiAuthenticationScheme;
options.DefaultSignInScheme = OktaDefaults.ApiAuthenticationScheme;
})
.AddOktaWebApi(new OktaWebApiOptions()
{
OktaDomain = "https://org.oktapreview.com",
AuthorizationServerId = "aus17ct73zmZrZjbh0h8",
Audience = "0oa173fmolqChJbj00h8"
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage()
.UseSwagger()
.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "NCL.StockSupplyChain.PurchaseOrder.Web.API"));
// This line enables more detailed stacktrace for auth code errors, Idendity framework, auth middleware etc
IdentityModelEventSource.ShowPII = true;
}
app.UseHttpsRedirection()
.UseRouting()
.UseAuthentication()
.UseAuthorization()
.UseCors(corsPolicyName)
.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
await app.RunAsync();
These two lines of code have to be in this order otherwise it will error:
.UseAuthentication()
.UseAuthorization()
Hopefully this helps someone who gets stuck with the error: System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://org.oktapreview.com/oauth2/aus17ct73zmZrZjbh0h8/.well-known/openid-configuration'. in the future because I thought I had configured Okta incorrectly.

Invalid Authentication method, invalid client error when trying to connect with OIDC

We're trying to develop an ASP Net application, and we have to use an oidc authentication system.
we've got our own OIDC server. When we try to connect we've got an error message :
"System.Exception: An error was encountered while handling the remote login.
---> Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolException: Message contains error: 'invalid_client', error_description: 'Invalid authentication method for accessing this endpoint.', error_uri: 'error_uri is null'."
here is our ConfigureService function and Configure function:
public void ConfigureServices(IServiceCollection services)
{
IdentityModelEventSource.ShowPII = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
services.AddMvc();
services.AddOptions();
SetGlobalConfig();
services.AddHttpContextAccessor();
services.AddResponseCompression(options =>
{
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
options.EnableForHttps = true;
});
services.AddAntiforgery(options =>
{
options.Cookie.Name = "X-CSRF-TOKEN-OurAppli";
options.HeaderName = "X-CSRF-TOKEN-OurAppli";
options.FormFieldName = "X-CSRF-TOKEN-OurAppli";
});
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(5);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.Always;
});
services.AddDetection();
services.AddControllersWithViews();
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
var bearerUrl = Configuration.GetValue<string>("BearerUrl");
var callBackUrl = Configuration.GetValue<string>("CallBackUrl");
var sessionCookieLifetime = Configuration.GetValue("SessionCookieLifetimeMinutes", 60);
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(setup => setup.ExpireTimeSpan = TimeSpan.FromMinutes(sessionCookieLifetime))
.AddOpenIdConnect(options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.ResponseType = "code";
options.ClientId = "*******";
options.ClientSecret = "********";
options.Authority = "https://ourOIDCServer/ourOIDCServerwebsso/oauth2/multiauth";
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Clear();
options.Scope.Add("openid uid isMemberOf");
options.SaveTokens = true;
options.Configuration = new OpenIdConnectConfiguration
{
AuthorizationEndpoint = "https://ourOIDCServer/ourOIDCServerwebsso/oauth2/multiauth/authorize",
TokenEndpoint = "https://ourOIDCServer/ourOIDCServerwebsso/oauth2/multiauth/access_token",
UserInfoEndpoint = "https://ourOIDCServer/ourOIDCServerwebsso/oauth2/multiauth/userinfo",
EndSessionEndpoint = "https://ourOIDCServer/ourOIDCServerwebsso/oauth2/multiauth/connect/endSession",
RegistrationEndpoint = "https://ourOIDCServer/ourOIDCServer/oauth2/multiauth/connect/register",
JwksUri = "ourOIDCServer/ourOIDCServer/oauth2/multiauth/connect/jwk_uri",
};
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.SetParameter("acr_values","ourACR");
context.ProtocolMessage.SetParameter("authlevel", "3");
var byteArray = Encoding.ASCII.GetBytes(options.ClientId + ":" + options.ClientSecret);
context.Request.Headers.Add("Authorization", "Post " + byteArray);
return Task.FromResult(0);
}
};
});
services.AddHsts(options =>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(365);
});
}
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/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.UseResponseCompression();
app.UseDetection();
app.UseSession();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.Use(async (context, next) =>
{
context.Response.Headers.Add("X-Frame-Options", "DENY");
context.Response.Headers.Add("Content-Security-Policy", "default-src 'self'; font-src 'self';script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; img-src 'self'; style-src 'self' 'unsafe-inline'");
await next();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "Index",
pattern: "{controller=Home}/{action=Index}");
});
app.UseStaticFiles();
}`
And there is our HomeController :
[Authorize]
public ActionResult Index()
{
Console.WriteLine(_user);
Console.WriteLine(_habilitation);
dynamic models = new ExpandoObject();
models.detection = _detectionService;
if (!string.IsNullOrEmpty(_user) || _user != "")
{
models.Authorization = _habilitation;
models.Name = _user;
Console.WriteLine(models.Name + " Auth= " + models.Authorization);
models.Habilitation = 1;
}
return View("Index", models);
}
I never used an OIDC authentication system with ASP Net so i don't know if there is something wrong with my code...
Hope someone can help me!
Can you add to the question how the client is defined? What OIDC provider are you using?
The problem seems that the client asks for "authorization code flow" here:
options.ResponseType = "code";
but the OIDC provider does not have that enabled. I would check that first.

dotnet core authorize always redirect to identity default login page

I create custom login page in pages/login.cshtml, and also i set [authorize] config in startup.cs to redirect to /login, but it keep redirect to Identity/Account/Login.
this is my 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.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
// Password settings.
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._#+";
options.User.RequireUniqueEmail = false;
});
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
options.LoginPath = "/Login";
options.AccessDeniedPath = "/AccessDenied";
options.LogoutPath = "/Logout";
options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
options.SlidingExpiration = true;
});
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddRazorPagesOptions(options =>
{
options.Conventions.AddPageRoute("/Dashboards/Dashboard1", "");
options.Conventions.AllowAnonymousToPage("/Login");
});
}
I already specify loginpath = "/login", but it always back to identity default page, why and how to solve it?
For this issue, try services.PostConfigure<CookieAuthenticationOptions> like
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddRazorPagesOptions(options =>
{
options.Conventions.AddPageRoute("/Dashboards/Dashboard1", "");
options.Conventions.AllowAnonymousToPage("/Login");
});
services.PostConfigure<CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme,
opt => {
//configure your other properties
opt.LoginPath = "/Login";
});

Authenticating an ASP.NET Core WebAPI using an ASP.NET Core MVC with Azure AD

I have two web applications: one ASP.NET Core MVC Website and one ASP.NET Core Web API (using ASP.NET Core 2.1).
I authenticate the users in the website using Azure AD. When I pass the access_token from the website to the API (using the Authorization header with "Bearer access_token"); I have this error:
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException:
IDX10503: Signature validation failed. Keys tried:
'Microsoft.IdentityModel.Tokens.X509SecurityKey , KeyId: ... '.
I don't understand why.
Here is the configuration of the Website:
services.AddAuthentication(o =>
{
o.DefaultChallengeScheme = "aad";
o.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o =>
{
o.Authority = azureAdsettings.Authority;
o.Audience = azureAdsettings.ClientId;
})
.AddCookie()
.AddOpenIdConnect("aad", o =>
{
o.Authority = azureAdsettings.Authority;
o.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
o.ClientId = azureAdsettings.ClientId;
o.ClientSecret = azureAdsettings.ClientSecret;
o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
o.SaveTokens = true;
o.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = azureAdsettings.Authority
};
o.Events = new OpenIdConnectEvents
{
OnTicketReceived = ctx =>
{
return Task.CompletedTask;
},
OnAuthorizationCodeReceived = async ctx =>
{
TokenProvider tokenProvider = (TokenProvider)ctx.HttpContext.RequestServices.GetRequiredService<ITokenProvider>();
await tokenProvider.AcquireTokenByAuthorizationCodeAsync(ctx);
},
OnAuthenticationFailed = context =>
{
context.Response.Redirect("/Error");
context.HandleResponse(); // Suppress the exception
return Task.CompletedTask;
},
};
});
And here is the configuration of the API:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = this.Configuration["AzureAd:Authority"];
options.Audience = this.Configuration["AzureAd:ClientId"];
options.TokenValidationParameters.ValidateIssuer = true;
options.TokenValidationParameters.IssuerValidator = ValidateIssuer;
});
The azureAdsettings object is exaclty the same in both appsettings.json.
The authentication on the website seems to work nicely. I can get the authorization code and retreive access token.

Categories

Resources