Reputation: 388
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?
Upvotes: 4
Views: 1590
Reputation: 388
Ugh, of course it was simple...
@inject HttpClient Http
@inject IAccessTokenProvider TokenProvider
...
HttpRequestMessage requestMessage = new HttpRequestMessage()
{
...
};
AccessTokenResult result = await TokenProvider.RequestAccessToken();
if (result.TryGetToken(out AccessToken token))
{
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token.Value);
}
HttpResponseMessage response = await Http.SendAsync(requestMessage);
EDIT: for anyone reading this, please refer to How do I get the id_token in Blazor WebAssembly after authenticating with OpenId (Cognito)? as well as you will need the id_token not the access_token if you are intending to use Identity Pools in Cognito to scope access for a user to a particular IAM Role.
Upvotes: 3
Reputation: 381
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);
}
}
Upvotes: 1