How to set up Custom Authentication State in Blazor Server .net 8 or 9

Prathamesh Shende 421 Reputation points
2025-03-31T16:12:15.5566667+00:00

Hi,
I set authentication settings in Blazor Server .NET 9.
After setting it, I put the [Authorize] attribute on the API call in the controller.

So it will fetch the authorization header of the access token, and the API will be authorized to show the result.

but on the Blazor server. Razor Pages: I never see a logged-in user.

I set a custom authentication state provider but am still facing an issue. Also there is another issue
Razor Pages does not show authorized attributes; they are not accessible and show 401.

Here is my code -
program.cs

builder.Services.AddAuthentication(options =>

{

   #region works but active user not showing

// Use JWT as the default authentication for APIs

options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;

options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

// Keep cookies for web-based authentication

options.DefaultScheme = IdentityConstants.ApplicationScheme;

options.DefaultSignInScheme = IdentityConstants.ExternalScheme;

options.DefaultForbidScheme = IdentityConstants.ApplicationScheme;

#endregion
```})

.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => //cookie autheticationscheme

{

```sql
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;

options.Cookie.SameSite = SameSiteMode.None;
```}) // Cookie authentication for web apps

.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => // JWT authentication for APIs

{

```typescript
options.TokenValidationParameters = new TokenValidationParameters

{

    ClockSkew = TimeSpan.Zero,

    SaveSigninToken = true,

    ValidateIssuer = true,

    ValidateAudience = true,

    ValidateLifetime = true,

    ValidateIssuerSigningKey = true,

    ValidIssuer = builder.Configuration["Jwt:Issuer"],

    ValidAudience = builder.Configuration["Jwt:Audience"],

    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"]) ?? throw new InvalidOperationException("Secret key not found"))

};

//options.Events = new JwtBearerEvents

//{

//    //OnMessageReceived = context =>

//    //{

//    //    Console.WriteLine($"Authorization Header: {context.Request.Headers["Authorization"]}");

//    //    return Task.CompletedTask;

//    //},

//    //OnTokenValidated = context =>

//    //{

//    //    Console.WriteLine("Token successfully validated!");

//    //    return Task.CompletedTask;

//    //},

//    //OnAuthenticationFailed = context =>

//    //{

//    //    Console.WriteLine($"Token validation failed: {context.Exception.Message}");

//    //    return Task.CompletedTask;

//    //}

//};

options.Events = new JwtBearerEvents

{

    OnTokenValidated = context =>

    {

        //context.Response.Cookies.Append("Program-cs", "Program.cs");

        Console.WriteLine("Token successfully validated!");

        return Task.CompletedTask;

    },

    OnAuthenticationFailed = context =>

    {

        Console.WriteLine($"Token validation failed: {context.Exception.Message}");

        return Task.CompletedTask;

    }

};
```})

.AddIdentityCookies();  
 

builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

builder.Services.AddScoped<AuthenticationStateProvider, JwtAuthenticationStateProvider>();  
  
JwtAuthenticationStateProvider.cs  
  
public class JwtAuthenticationStateProvider : AuthenticationStateProvider

{

```java
readonly IHttpContextAccessor _acc;

//private AuthenticationState authenticationState;

public JwtAuthenticationStateProvider(IHttpContextAccessor acc) //CustomAuthenticationService service

{

    _acc = acc;

    //service.UserChanged += (newUser) =>

    //{

    //    authenticationState = new AuthenticationState(newUser);

    //    NotifyAuthenticationStateChanged(Task.FromResult(authenticationState));

    //};

}

public async override Task<AuthenticationState> GetAuthenticationStateAsync()

{

    var httpContext = _acc.HttpContext;

    if (httpContext == null)

    {

        throw new InvalidOperationException("null");

    }

    var token = httpContext.Request.Cookies["access_token"]; // Replace with your cookie name

    if (string.IsNullOrEmpty(token))

    {

        return new AuthenticationState(new ClaimsPrincipal());

    }

    var handler = new JwtSecurityTokenHandler();

    var jwtToken = handler.ReadJwtToken(token);

    var identity = new ClaimsIdentity(jwtToken.Claims, "Bearer");

    var user = new ClaimsPrincipal(identity);

    var authState = new AuthenticationState(user);

    NotifyAuthenticationStateChanged(Task.FromResult(authState));

    return authState;

}

public void NotifyUserAuthentication(ClaimsPrincipal user)

{

    NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));

}

public void NotifyUserLogout()

{

    NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()))));

}
```}
Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,672 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Pradeep M 8,185 Reputation points Microsoft External Staff
    2025-04-01T05:53:21.3833333+00:00

    Hi Prathamesh Shende,

    Thank you for reaching out to Microsoft Q & A forum.   

    You are encountering two issues in your Blazor Server application the authenticated user is not appearing in components, and Razor Pages are returning a 401 error despite authentication being configured.  

    To address these problems, consider following these steps. 

    1.Use Cookie Authentication for Blazor Server  Blazor Server works best with cookies, not JWT. Update your authentication settings in Program.cs: 

    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
    

     2.Update JwtAuthenticationStateProvider to Read the Authenticated User  Modify GetAuthenticationStateAsync to retrieve the user from HttpContext: 

    public override Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var user = _acc.HttpContext?.User ?? new ClaimsPrincipal(new ClaimsIdentity());
        return Task.FromResult(new AuthenticationState(user));
    }
    
    

    This ensures Blazor Server correctly recognizes the logged-in user. 

    3.Ensure Razor Pages Have Proper Authorization  In Program.cs, enforce authorization on Razor Pages and API controllers: 

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers().RequireAuthorization();
        endpoints.MapRazorPages().RequireAuthorization();
    });
    
    

     Also, check HttpContext.User.Identity.IsAuthenticated within Razor Pages to verify authentication. 

    These changes should help resolve your issues. 

    Please feel free to contact us if you have any additional questions.     

    If you have found the answer provided to be helpful, please click on the "Accept answer/Upvote" button so that it is useful for other members in the Microsoft Q&A community.  

    0 comments No comments

  2. Bruce (SqlWork.com) 75,051 Reputation points
    2025-04-03T16:06:09.79+00:00

    your goal is not clear. blazor server only supports cookie authenication. even if you use oauth, its still cookie authentication.

    if for some reason, your blazor server app was also an api server for other clients (not the blazor app), then you would add jwt support. having two authentication schemes requires implementing policies to support the schemes. the default scheme would be cookie, used by blazor. the secondary policy would be used by the web api actions.

    see:

    https://learn.microsoft.com/en-us/aspnet/core/security/authentication/policyschemes?view=aspnetcore-9.0

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.