Search code examples
asp.net-corecookiesblazorblazor-server-sidehttpcontext

I am trying to create cookie while login with a user in Blazor web server app but I am bit lost


I did check a lot of videos and tutorials on how to do in this days and now I am literally confused from how many options possible to achieve it, yet none really work well for me. I'm just trying to understand what is the best way for create a simple program structure where a user after login into admin page set creation of a cookie that could expire in 10 minute, but can get refreshed on every access to a page with authorize attribute. That's without the use of Entity Framework btw. In this days I was experimenting it and I did menage to create cookie using controllers, is that the correct way to create cookie calling the controller function and let it create cookie with await HttpContext.SignOutAsync ? Otherwise I am open to any other suggestion but not point me again to documentations because I did try to understand from there but I get only more and more confused. btw I am working on Net 6.0 at the moment. Thank you for anyone that will point me out on some good resource to understand better this process.

As explained up I did check documentation and tried with the controller method but I want to know if I am doing it right or is a better way in Blazor to menage the user authorization and authentication ? Like ProtectedSessionStorage?


Solution

  • You cannot set cookies from a Blazor server-side session. You do not have access to the HttpContext and there isn't the traditional request/response cycle that you can use to return cookies in the response headers.

    The approach I've has success with is to set up a login form in the usual Blazor way. If the login passes validation then I redirect to a traditional razor page (.cshtml file) that does have access to the HttpContext. After the cookie has been set I then redirect to the post-login page.

    The same approach can be taken with logging out.

    Below is a basic overview of the process.

    <Blazor>
      @page "/login"
      - Render login form
      - Validate user input
      - Failure?
        - Display error message    
      - Success?  
        - Navigate to /dologin
    </Blazor>
    
    <Razor>
      @page "/dologin"
      - validate request
      - set auth cookie
      - navigate to /post-login
    </Razor>
    
    <Blazor>
      @page "/post-login"
      - validate cookie
      - continue session
      - ...
      - navigate to /logout
    </Blazor>
    
    <Razor>
      @page "/logout"
      - unset cookie
      - navigate to post-logout page
    </Razor>
    
    <Blazor>
      @page "/post-logout"
      - continue session
    </Blazor>
    

    Obviously this is a simplified representation, and doesn't go into any detail about post-login/logout redirect logic. Nor does it cover what abstraction you are using for auth management. In my project I use SignInManager from Microsoft.AspNetCore.Identity, but that is simply my choice of implementation and not related to my choice of workflow.

    Edit

    As described above, after I have validated the username and password, I navigate to the page that sets the auth cookie. Now because this is just another URL, we need to have a trusted way of identifying the authenticated user. We don't want to pass the username and the password in the URL for security reasons. To work around this I create a one-time token in my database after the credentials are validated and associate it with the user and use that to identify the user. I set the token to expire after a short time to improve security.

    Relevant steps of the workflow:

    <Blazor>
      @page "/login"
      - Valid credentials?
        - Create token for user in database
        - Navigate to /dologin?token=ABC123
    </Blazor>
    
    <Razor>
      @page "/dologin"
      - Get token from query string
      - Retrieve token from database
      - Token valid?
        - Delete token from database
        - Set auth cookie
    </Razor>