Technology Goal:
Backend:
Startup.cs:ConfigureServices
RegionEndpoint region = Configuration.GetAWSOptions().Region;
string CognitoMetadataAddress = $"https://cognito-idp.{region.SystemName}.amazonaws.com/{AppConfig.CognitoPoolId}/.well-known/openid-configuration";
//
// Ref: https://criticalhittech.com/2019/02/19/asp-net-core-with-aws-lambda-and-cognito/
//
services.Configure<OpenIdConnectOptions>(options =>
{
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
options.ClientId = AppConfig.CognitoClientId;
options.MetadataAddress = CognitoMetadataAddress;
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true
};
});
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.ClientId = AppConfig.CognitoClientId;
options.MetadataAddress = CognitoMetadataAddress;
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true
};
options.Events = new OpenIdConnectEvents()
{
OnRedirectToIdentityProvider = OnRedirectToIdentityProvider,
OnRedirectToIdentityProviderForSignOut = OnRedirectToIdentityProviderForSignOut,
OnAuthenticationFailed = OnAuthenticationFailed,
OnUserInformationReceived = OnUserInformationReceived
};
});
Client-Side:
Program.cs:Main
string CognitoPoolId = "ca-central-1_<REMOVED>";
string region = CognitoPoolId.Substring(0, CognitoPoolId.IndexOf('_', StringComparison.InvariantCultureIgnoreCase));
string CognitoAuthority = $"https://cognito-idp.{region}.amazonaws.com/{CognitoPoolId}";
string CognitoMetadataAddress = $"https://cognito-idp.{region}.amazonaws.com/{CognitoPoolId}/.well-known/openid-configuration";
builder.Services.AddOidcAuthentication(options =>
{
options.ProviderOptions.Authority = CognitoAuthority;
options.ProviderOptions.MetadataUrl = CognitoMetadataAddress;
options.ProviderOptions.ClientId = "<REMOVED>";
options.ProviderOptions.RedirectUri = $"{builder.HostEnvironment.BaseAddress.TrimEnd('/')}/authentication/login-callback";
options.ProviderOptions.ResponseType = "code";
});
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
Problem In my Blazor app, I want to call my back-end API (which requires Authentication) and use the authorization that the Blazor app already has since both the client and backend are using the same Cognito user pool. i.e.
HttpResponseMessage response = await Http.SendAsync(requestMessage);
How do I configure the HttpClient instance to send along the authorization the Blazor app has via authenticating with Cognito so that it can call the protected Apis?
In the Client projects Program.cs, you can add an HttpClient as follows that will add the neccessary tokens to your http requests. This can then by injected into code as required to make your http calls.
builder.Services.AddHttpClient("UniqueClientNameHere", client => client.BaseAddress = serverBaseAddress)
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("UniqueClientNameHere"));
for example inside a .razor file called Foobar.razor:
@page "/foobar"
@inject HttpClient Http
<h1>Hello Foobar</h1>
@code{
protected override async Task OnInitializedAsync()
{
HttpResponseMessage response = await Http.SendAsync(requestMessage);
}
}