AddOpenIdConnect with an External Configuration Service - c#

I am adding OpenIdConnect to my app like so:
.AddOpenIdConnect("oidc", options =>
{
var clientSecret = Configuration.GetValue<string>("clientSecret");
options.ClientSecret = clientSecret;
});
I'd like to be able to use another service to get the secret like this:
.AddOpenIdConnect("oidc", (services, options) =>
{
var secretService = services.GetService<ISecretService>();
var clientSecret = secretService.Get("clientSecret");
options.ClientSecret = clientSecret;
});
I saw there is use of app.UseOpenIdConnectAuthentication but I don't see it in the nuget package.
I have the following installed:
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="3.1.0" />
How can I do this?

It is possible to execute a post configuration class that can inject services.
Like so:
public class OpenIdConnectPostConfigureOptions : IPostConfigureOptions<OpenIdConnectOptions>
{
private readonly ISecretsService _secretsService;
public OpenIdConnectPostConfigureOptions(ISecretsService secretsService)
{
_secretsService = secretsService;
}
public async void PostConfigure(string name, OpenIdConnectOptions options)
{
options.ClientSecret = await _secretsService.Get("clientSecret");
}
}

In the described case I'd recommend extending Configuration rather than using DI in the Action.
To access secrets you can add Configuration providers and continue to use Configuration.GetValue in ConfigureServices method.
For Azure Key-Vault it is under Microsoft.Extensions.Configuration.AzureKeyVault nuget package.
public static void Main(string[] args)
{
CreateWebHostBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
if (env.IsLocal())
{
...
}
else
{
config.AddAzureKeyVault(keyVaultUri);
}
})
.Build()
.Run();
}
For AWS - Amazon.Extensions.Configuration.SystemsManager

Related

How to configure HealthCheck with IHost?

In our current implementation of healthcheck's in worker service we do like this (simplified)
var options = new WebApplicationOptions {
Args = args,
ContentRootPath = WindowsServiceHelpers.IsWindowsService()
? AppContext.BaseDirectory
: default
};
var builder = WebApplication.CreateBuilder(options);
builder.Host.UseWindowsService();
builder.Services.AddHealthChecks().AddCheck<ServiceIsOnlineCheck>(nameof(ServiceIsOnlineCheck));
builder.Services.AddHostedService<Worker>();
var healthcheckoptions = new HealthCheckOptions
{
ResponseWriter = ResponseWriters.WriteDetailedStatus,
ResultStatusCodes =
{
[HealthStatus.Healthy] = StatusCodes.Status200OK,
[HealthStatus.Degraded] = StatusCodes.Status200OK,
[HealthStatus.Unhealthy] = StatusCodes.Status200OK
}
};
var app = builder.Build();
app.UseHealthChecks("/health", healthcheckoptions);
app.Run();
When I create a new worker service in .NET 7, the setup in program.cs is completely different and I can not understand how we can set up health checks in them.
How do you implement it when program.cs looks like this? (we need to set our own response writer and other custom options)
IHost host = Host.CreateDefaultBuilder(args)
.UseWindowsService(options =>
{
options.ServiceName = "Service Name";
})
.ConfigureWebHost(host =>
{
// ???
})
.ConfigureServices(services =>
{
services.AddHostedService<RunOnScheduleWorker>();
})
.Build();
host.Run();
This template uses the generic hosting (which was used in pre .NET 6 templates), so you can setup it with Startup. Here is a small working snippet which you can draw inspiration from:
IHost host = Host.CreateDefaultBuilder(args)
.UseConsoleLifetime()
.ConfigureWebHostDefaults(builder =>
{
builder.UseStartup<Startup>();
})
.ConfigureServices(services => { services.AddHostedService<Worker>(); })
.Build();
host.Run();
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHealthChecks("/health");
}
}
But you are not limited to using it, you can:
Switch to the one previously used, just copy-paste everything from the one you used.
Since you want to expose ASP.NET Core endpoint(s) - use corresponding project type and add just hosted service to it.
Read more:
.NET Generic Host
.NET Generic Host in ASP.NET Core
The Startup class

Activity is null when using Microsoft Hosting Extensions and net472

I am trying to use OpenTelemetry with my net472 app that uses Microsoft.Extensions.Hosting.
I create my host like this:
Host.CreateDefaultBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddOpenTelemetry().WithTracing(tracerProviderBuilder =>
{
tracerProviderBuilder
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample"))
.AddConsoleExporter()
.AddSource(serviceName);
}).StartWithHost();
})
.Build();
If I then try to create a new activity like this, it is null:
var activitySource = new ActivitySource(serviceName);
using var activity = activitySource.StartActivity("Hello");
If instead I register OpenTelemetry like this, it works just fine:
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample"))
.AddSource(serviceName)
.AddConsoleExporter()
.Build();
How can I get an ActivitySource that has the configured listener using the first approach of creating a Host?
The solution that worked for me is to resolve the TracerProvider using the ServiceCollection. That way the listener gets subscribed and ActivitySource is able to start activities.
This is how I register the services.
Host.CreateDefaultBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton(new ActivitySource(serviceName));
services.AddOpenTelemetry().WithTracing(tracerProviderBuilder =>
{
tracerProviderBuilder
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MySample"))
.AddConsoleExporter()
.AddSource(serviceName);
});
})
.Build();
And then when TracerProvider is resolved, it's build using the configured TracerProvider:
using var tracerProvider = ServiceLocator.GetService<TracerProvider>();
var activitySource = ServiceLocator.GetService<ActivitySource>();
// Now this doesn't provide a null object
using var activity = activitySource.StartActivity("Hello");
Just for reference, this is ServiceLocator:
public static class ServiceLocator
{
internal static IHost Host { get; set; }
public static T GetService<T>() where T : class
{
return (T)Host.Services.GetService(typeof(T));
}
}
Thanks for the hint, i tried to adopt this on my .net core 7 application.
The following code seems to fix the bug for me too.
var app = builder.Build();
...
app.UseTelemetry();
...
app.Run();
public static void UseTelemetry(this IApplicationBuilder app)
{
_ = app.ApplicationServices.GetRequiredService<TracerProvider>();
}

Getting Null from value using IOptionSnapshot<T>

I'm trying to implement Azure App Configuration to my Application that uses the ASP.NET Boilerplate Framework. I'm following this tutorial but when I try to access my settings everything comes null. When the Startup.cs get executed I can see the values in the constructor but when I try to get them else where I get the null.
Program.cs:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((config) =>
{
// Retrieve the connection string
IConfiguration settings = config.Build();
string connectionString = settings.GetConnectionString("AppConfig");
// Load configuration from Azure App Configuration
config.AddAzureAppConfiguration(options =>
{
options.Connect(connectionString)
// Load all keys that start with `TestApp:` and have no label
.Select("TestApp:*", LabelFilter.Null)
// Configure to reload configuration if the registered sentinel key is modified
.ConfigureRefresh(refreshOptions => refreshOptions.Register("TestApp:Settings:Sentinel", refreshAll: true));
}).Build();
})
.UseStartup<Startup>()
.Build();
}
}
Startup.cs:
public class Startup
{
private const string _defaultCorsPolicyName = "localhost";
private const string _apiVersion = "v1";
public IConfigurationRoot _appConfiguration;
public IConfiguration Configuration { get; }
public Startup(IWebHostEnvironment env, IConfiguration configuration)
{
_appConfiguration = env.GetAppConfiguration();
Configuration = configuration; //Azure App Configuration
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//MVC
services.AddControllersWithViews(
options =>
{
options.Filters.Add(new AbpAutoValidateAntiforgeryTokenAttribute());
}
).AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new AbpMvcContractResolver(IocManager.Instance)
{
NamingStrategy = new CamelCaseNamingStrategy()
};
});
IdentityRegistrar.Register(services);
AuthConfigurer.Configure(services, _appConfiguration);
services.AddSignalR();
// Configure CORS for angular2 UI
services.AddCors(
options => options.AddPolicy(
_defaultCorsPolicyName,
builder => builder
.WithOrigins(
// App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
_appConfiguration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.RemovePostFix("/"))
.ToArray()
)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
)
);
options.DocInclusionPredicate((docName, description) => true);
// Define the BearerAuth scheme that's in use
options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
});
services.AddAzureAppConfiguration();
// Bind configuration "TestApp:Settings" section to the Settings object
services.AddOptions();
services.Configure<Settings>(Configuration.GetSection("TestApp:Settings"));
// Configure Abp and Dependency Injection
return services.AddAbp<RptWebHostModule>(
// Configure Log4Net logging
options => options.IocManager.IocContainer.AddFacility<LoggingFacility>(
f => f.UseAbpLog4Net().WithConfig("log4net.config")
)
);
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseAbp(options => { options.UseAbpRequestLocalization = false; }); // Initializes ABP framework.
app.UseCors(_defaultCorsPolicyName); // Enable CORS!
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAbpRequestLocalization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<AbpCommonHub>("/signalr");
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute("defaultWithArea", "{area}/{controller=Home}/{action=Index}/{id?}");
});
options.IndexStream = () => Assembly.GetExecutingAssembly()
options.DisplayRequestDuration(); // Controls the display of the request duration (in milliseconds) for "Try it out" requests.
});
// Use Azure App Configuration middleware for dynamic configuration refresh.
app.UseAzureAppConfiguration();
}
}
Custom Controller where I get the null values:
[Route("api/[controller]/[action]")]
public class AzureAppConfigTest : AbpControllerBase
{
public Settings _settings { get; }
public AzureAppConfigTest(IOptionsSnapshot<Settings> options
)
{
_settings = options.Value;
}
[HttpPost]
public string Test()
{
return _settings.Message; // The Problem is here
}
}
I need to get the values else where in the Application, I tried changing IOptionsSnapshot for IOptions but I can't make it work, Iv'e been stuck with this about two week but since I'm new in the Microsoft world I can't see clearly where the problem is, Thanks in Advance
Update:
I am able to use the configuration at the Presentation Layer, but If I try to use it on the Application layer I don't get the values.

How can I read the appsettings.json in a .Net 6 console application?

I try to create a .Net 6 Console Application but having troubles reading my appsettings.json file. In a web application I could use this...
var builder = WebApplication.CreateBuilder(args);
But what would I use in a console application? I get this error when trying to add it to program.cs. "The name 'WebApplication' does not exist in the current context"
Add these two nuget packages in your application
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.Json
Then you can use ConfigurationBuilder to use appsettings.json file
var configuration = new ConfigurationBuilder()
.AddJsonFile($"appsettings.json");
var config = configuration.Build();
var connectionString = config.GetConnectionString("ConnectionString");
Getting Values from AppSettings in Console Application
Adding AppSettings in .net core app
Link to docs: https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration
Nuget packages are needed to do it:
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.0" />
using Microsoft.Extensions.Configuration;
// Build a config object, using env vars and JSON providers.
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();
// Get values from the config, given their key and their target type.
Settings settings = config.GetRequiredSection("Settings").Get<Settings>();
// Write the values to the console.
Console.WriteLine($"KeyOne = {settings.KeyOne}");
Console.WriteLine($"KeyTwo = {settings.KeyTwo}");
Console.WriteLine($"KeyThree:Message = {settings.KeyThree.Message}");
// Application code which might rely on the config could start here.
// This will output the following:
// KeyOne = 1
// KeyTwo = True
// KeyThree:Message = Oh, that's nice...
JSON File (appsettings.json)
{
"Settings": {
"KeyOne": 1,
"KeyTwo": true,
"KeyThree": {
"Message": "Oh, that's nice..."
}
}
}
UPD: I checked the approach, and it works;
My code:
// See https://aka.ms/new-console-template for more information
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
Console.WriteLine("Hello, World!");
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
IConfiguration c = configurationBuilder.AddJsonFile("appsettings.json").AddEnvironmentVariables().Build();
var k = c.GetRequiredSection("Settings").Get<Settings>().KeyOne;
var n = 1;
public class NestedSettings
{
public string Message { get; set; } = null!;
}
public class Settings
{
public int KeyOne { get; set; }
public bool KeyTwo { get; set; }
public NestedSettings KeyThree { get; set; } = null!;
}
Using .NET 6 Console app, try:
using IHost host = Host.CreateDefaultBuilder(args).Build();
IConfiguration config = host.Services.GetRequiredService<IConfiguration>();
string con= config.GetValue<string>("ConnectionStrings:conn1");
//OR
string connectionString = config["ConnectionStrings:conn1"];
Console.WriteLine($"Hello, World! {connectionString}");
appsettings.json (Properties): (CopyToOutputDirectory = Always):
"ConnectionStrings": {
"conn1": "Server=localhost;Database=MyDatabase;Trusted_Connection=True",
}
In a console app I add the appsettings.json and user secrets like this, you may also have a development json file as well.
internal class Program
{
internal static IConfigurationRoot Configuration;
public static void Main()
=> new Program().MainAsync().GetAwaiter().GetResult();
private async Task MainAsync()
{
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
configurationBuilder.AddUserSecrets(typeof(Program).GetTypeInfo().Assembly, optional: false);
Configuration = configurationBuilder.Build();
...
}
}
Then elsewhere in the console app in any class you can simply call it like this
var someSetting = Program.Configuration["SomeSetting"];
If you want a strongly typed class then see this answer .net core Console application strongly typed Configuration on SO
I would prefer the following code because it will automatically read the appsettings.json file from the project directory. Pay attention to _.Configuration I used during configuring DbContext to read the connection string.
var builder = Host.CreateDefaultBuilder(args)
.ConfigureServices(
(_, services) => services
.AddTransient<IService, Service>()
.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(
_.Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)))
);
var host = builder.Build();
var dbContext = host.Services.GetRequiredService<ApplicationDbContext>();
I put this together from this link: https://bjdejongblog.nl/net-core-6-dependency-injection-console-program/
Install the following packages
Install-Package Microsoft.Extensions.Configuration.Json
Install-Package Microsoft.Extensions.Hosting
create a file call appsettings.json
{
"AllowedHosts": "*",
"ConnectionStrings": {
"defaultConnection": "data source=.;initial catalog=ExchangeGatewayDb;integrated security=true;MultipleActiveResultSets=True;"
}
}
add this code to Programe.cs
var hostBuilder = new HostBuilder().ConfigureHostConfiguration(config =>
{
config.AddEnvironmentVariables();
if (args != null)
{
config.AddCommandLine(args);
}
}).ConfigureAppConfiguration((context, builder) =>
{
var env = context.HostingEnvironment;
builder.SetBasePath(AppContext.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true).AddEnvironmentVariables();
var configuration = builder.Build();
var connectionString = configuration["ConnectionStrings:defaultConnection"];
}).ConfigureServices(services =>
{
services.Configure<ConsoleLifetimeOptions>(opts => opts.SuppressStatusMessages = true);
//your code
});
var buildHost = hostBuilder.Build();
buildHost.Run();
You could use DI to get IConfiguration interface and with it you can access the appsettings.

ASP.NET Core 2.0 AzureAD Authentication not working

I have an ASP.NET Core 2.0 application setup that I want to use AzureAd for the authentication with my company's directory. I have setup the classes and startup method and have the authentication piece working, the problem that I'm having is that I'm trying to setup and event handler to the OnAuthorizationCodeReceived event, so that I can request a user token that will then be used for Microsoft graph calls.
In my Startup.cs I have the following code
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddAzureAd(options => Configuration.Bind("AzureAd", options))
.AddCookie();
services.AddMvc();
services.AddSingleton(Configuration);
services.AddSingleton<IGraphAuthProvider, GraphAuthProvider>();
services.AddTransient<IGraphSDKHelper, GraphSDKHelper>();
}
// 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();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
Then in the AzureAdAuthenticationBuilderExtensions.cs I have the following code.
public static class AzureAdAuthenticationBuilderExtensions
{
public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, IConfiguration configuration)
=> builder.AddAzureAd(_ => { }, configuration);
public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, Action<AzureAdOptions> configureOptions,
IConfiguration configuration)
{
builder.Services.Configure(configureOptions);
builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, ConfigureAzureOptions>();
builder.AddOpenIdConnect(opts =>
{
opts.ResponseType = "code id_token";
opts.ClientId = configuration["AzureAd:ClientId"];
opts.Authority = $"{configuration["AzureAd:Instance"]}{configuration["AzureAd:TenantId"]}";
opts.UseTokenLifetime = true;
opts.CallbackPath = configuration["AzureAd:CallbackPath"];
opts.ClientSecret = configuration["AzureAd:ClientSecret"];
opts.RequireHttpsMetadata = false;
opts.Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = async context =>
{
var credential = new ClientCredential(context.Options.ClientId, context.Options.ClientSecret);
var distributedCache = context.HttpContext.RequestServices.GetRequiredService<IDistributedCache>();
var userId = context.Principal
.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")
.Value;
var cache = new AdalDistributedTokenCache(distributedCache, userId);
var authContext = new AuthenticationContext(context.Options.Authority, cache);
await authContext.AcquireTokenByAuthorizationCodeAsync(context.TokenEndpointRequest.Code,
new Uri(context.TokenEndpointRequest.RedirectUri, UriKind.RelativeOrAbsolute), credential, context.Options.Resource);
context.HandleCodeRedemption();
}
};
});
return builder;
}
private class ConfigureAzureOptions: IConfigureNamedOptions<OpenIdConnectOptions>
{
private readonly AzureAdOptions _azureOptions;
public ConfigureAzureOptions(IOptions<AzureAdOptions> azureOptions)
{
if (azureOptions != null)
{
_azureOptions = azureOptions.Value;
}
}
public void Configure(string name, OpenIdConnectOptions options)
{
options.ClientId = _azureOptions.ClientId;
options.Authority = $"{_azureOptions.Instance}{_azureOptions.TenantId}";
options.UseTokenLifetime = true;
options.CallbackPath = _azureOptions.CallbackPath;
options.RequireHttpsMetadata = false;
options.ClientSecret = _azureOptions.ClientSecret;
}
public void Configure(OpenIdConnectOptions options)
{
Configure(Options.DefaultName, options);
}
}
}
Then AddAzureAd method is being called and I can see it walk through all of the code in this method, but when I put a breakpoint in the OnAuthorizationCodeReceived method that breakpoint never gets hit. I've done a bunch of reading and it looks like what I have is right, so I'm guessing that I must be missing something simple here, but can't find the problem.
Editted
I'm now hitting the OnAuthorizationCodeReceived event, but now the application is failing to continue to log in getting the following error
SecurityTokenException: Unable to validate the 'id_token', no suitable ISecurityTokenValidator was found for: ''."
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler+<HandleRequestAsync>d__12.MoveNext()
Stack Query Cookies Headers
SecurityTokenException: Unable to validate the 'id_token', no suitable ISecurityTokenValidator was found for: ''."
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler+<HandleRequestAsync>d__12.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+<Invoke>d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+<Invoke>d__7.MoveNext()
The OpenIdConnect component for Asp.net core 2.0 uses implicit flow(the value of response_type is id_token).
To fire the OnAuthorizationCodeReceived the event, we should use the hybrid flow which's 'response_type' parameter contains code value.(eg. id_token code). And we need set it through the OpenIdConnectOptions like code below:
.AddOpenIdConnect(options =>
{
options.Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAd:Tenant"]);
options.ClientId = Configuration["AzureAd:ClientId"];
options.ResponseType = "code id_token";
});
options.Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = async context =>
{
var credential = new ClientCredential(context.Options.ClientId, context.Options.ClientSecret);
var authContext = new AuthenticationContext(context.Options.Authority);
var authResult=await authContext.AcquireTokenByAuthorizationCodeAsync(context.TokenEndpointRequest.Code,
new Uri(context.TokenEndpointRequest.RedirectUri, UriKind.RelativeOrAbsolute), credential, context.Options.Resource);
context.HandleCodeRedemption(authResult.AccessToken, context.ProtocolMessage.IdToken);
},
};

Categories

Resources