I have a Blazor Server Side app configured with B2C auth. This app will call a webapi to do any of the data exchanges with my service. B2C auth works fine, and straight from template the config B2C auth is:
services.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
.AddAzureADB2C(options => { Configuration.Bind("AzureAdB2C", options); });
The claims only has the claims I'm returning from my signin policy, without any access tokens I can use for auth on behalf to my Web api (Also secured with same B2C tenant).
I've read about 100 different docs, but it seems that nothing makes sense in the context of blazor. Is there anyone that has done this before that could shed some light?
First prize would be to request an access token once the user auths to B2C the first time, and then keep the token in cache to use in the blazor app for any api calls while the session / browser is open or the access token is valid.
It seems that this is the right path: https://github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi/blob/master/TaskWebApp/Controllers/TasksController.cs but what I'm not understanding is:
Thanks!
I have created a sample application with OpenId Connect and Blazor (Server) for you here https://github.com/yberstad/BlazorAuth. It is uses a SameSiteCookie and OpenId Connect.
How to get access and refresh token:
var accessToken = await HttpContext.GetTokenAsync("access_token");
var refreshToken = await HttpContext.GetTokenAsync("refresh_token");
SameSiteCookie Info: https://brockallen.com/2019/01/11/same-site-cookies-asp-net-core-and-external-authentication-providers/
Getting Access Token: http://docs.identityserver.io/en/latest/quickstarts/5_hybrid_and_api_access.html#using-the-access-token
Having the tokens stored in a SameSiteCookie makes it only visible for the server, hence not saving and exposing it in an unsafe environment on the client. A SameSiteCookie is also safe for XSS.
Hope this helps.
I was able to solve this myself. My AcquireTokenSilent call was failling because there was no users in the cache when I call it, so I had to make sure to add first entry to the cache when my user logs in. I was able to achieve this by configuring my auth as follows:
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = AzureADB2CDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = AzureADB2CDefaults.OpenIdScheme;
})
.AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options))
.AddCookie();
services.Configure<OpenIdConnectOptions>(AzureADB2CDefaults.OpenIdScheme, options =>
{
//Configuration.Bind("AzureAdB2C", options);
options.ResponseType = Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectResponseType.CodeIdToken;
options.Scope.Add("offline_access");
options.Scope.Add("https://mytenant.onmicrosoft.com/api/api.read.write");
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Events.OnAuthorizationCodeReceived = async context =>
{
AzureADB2COptions opt = new AzureADB2COptions();
Configuration.Bind("AzureAdB2C", opt);
// As AcquireTokenByAuthorizationCodeAsync is asynchronous we want to tell ASP.NET core that we are handing the code
// even if it's not done yet, so that it does not concurrently call the Token endpoint. (otherwise there will be a
// race condition ending-up in an error from Azure AD telling "code already redeemed")
context.HandleCodeRedemption();
var code = context.ProtocolMessage.Code;
string signedInUserID = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;
IConfidentialClientApplication cca = ConfidentialClientApplicationBuilder.Create(opt.ClientId)
.WithB2CAuthority(opt.Authority)
.WithRedirectUri(opt.RedirectUri)
.WithClientSecret(opt.ClientSecret)
.WithClientName("myWebapp")
.WithClientVersion("0.0.0.1")
.Build();
new MSALStaticCache(signedInUserID, context.HttpContext).EnablePersistence(cca.UserTokenCache);
try
{
AuthenticationResult result = await cca.AcquireTokenByAuthorizationCode(opt.ApiScopes.Split(' '), code)
.ExecuteAsync();
context.HandleCodeRedemption(result.AccessToken, result.IdToken);
}
catch (Exception)
{
}
};
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With