Quantcast
Channel: Active questions tagged blazor - Stack Overflow
Viewing all articles
Browse latest Browse all 4839

Blazor Server with Azure AD B2C and PunchOut flow

$
0
0

We have a Blazor Server app and an ASP.NET API secured with Azure AD B2C. For implementing the authentication flow in the Blazor app, we use Microsoft.Identity.Web.

services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAdB2C").EnableTokenAcquisitionToCallDownstreamApi(new[] { Configuration["API:Scope"] }).AddSessionTokenCaches();

This is working well and is already in production. However, our client also wants to allow customers to connect using their SAP system via the PunchOut mechanism.

My idea is to implement a controller in the API that returns a token, which can be used to retrieve an access token using the same API.

    /// <summary>    /// Acquire token by username and password    /// </summary>    /// <param name="username"></param>    /// <param name="password"></param>    /// <returns></returns>    public async Task<string> AcquireAccessTokenByUsernamePasswordAsync(string username, string password)    {        var tenantId = configuration["PunchOut:TenantId"];        var clientId = configuration["PunchOut:ClientId"];        var clientSecret = configuration["PunchOut:ClientSecret"];        var tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";        var parameters = new Dictionary<string, string>        {            { "client_id", clientId },            { "client_secret", clientSecret },            { "grant_type", "password" },            { "scope", configuration["PunchOut:Scope"] },            { "username", username },            { "password", $"{password}_pwd" }        };        var content = new FormUrlEncodedContent(parameters);        var response = await httpClient.PostAsync(tokenEndpoint, content);        response.EnsureSuccessStatusCode();        var responseBody = await response.Content.ReadAsStringAsync();        var tokenResponse = JsonSerializer.Deserialize<JsonElement>(responseBody);        return tokenResponse.GetProperty("access_token").GetString();    }    /// <summary>    /// Aquire token by punchout token    /// </summary>    /// <param name="token"></param>    /// <returns></returns>    public async Task<(string Username, string Token)> AcquireAccessTokenByPunchOutToken(string token)    {        User user = DataContext.Users.FirstOrDefault(l => l.AutoLoginToken == token && l.AutoLoginTokenValidUntil > DateTime.Now);        if (user == null)        {            return (string.Empty, string.Empty);        }        return (user.DisplayName, await AcquireAccessTokenByUsernamePasswordAsync(user.DisplayName, user.Password));    }

This is working on the API side, but I can't find a good way to implement it in the Blazor app. I've added a page to the Blazor app that accepts the custom-generated token and then communicates with my API to retrieve the access token. After that, I try to sign in the user using:

var jwtToken = handler.ReadJwtToken(token);  var claims = new List<Claim>  {      new Claim(ClaimTypes.NameIdentifier, jwtToken.Claims.First(c => c.Type == "sub").Value),      new Claim(ClaimTypes.Name, jwtToken.Claims.First(c => c.Type == "name").Value)  };  var claimsIdentity = new ClaimsIdentity(claims, "apiauth_type");  var user = new ClaimsPrincipal(claimsIdentity);  ((CustomAuthenticationStateProvider)AuthenticationStateProvider).SignIn(user);

And

public class CustomAuthenticationStateProvider  : AuthenticationStateProvider{    private ClaimsPrincipal _user = new ClaimsPrincipal(new ClaimsIdentity());    public override Task<AuthenticationState> GetAuthenticationStateAsync()    {        return Task.FromResult(new AuthenticationState(_user));    }    public void SignIn(ClaimsPrincipal user)    {        _user = user;        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());    }    public void SignOut()    {        _user = new ClaimsPrincipal(new ClaimsIdentity());        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());    }}

But the user isn't signed in after doing this.


Viewing all articles
Browse latest Browse all 4839

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>