asp.net-corejwtopenid-connectblazor-webassemblyauth0

JWT token location in Blazor WASM


I've just started my first Blazor WASM project which requires authentication. We use Auth0 for user identity management.

Following this article on Auth0 website, I was able to get authentication working: https://auth0.com/blog/securing-blazor-webassembly-apps/

My question is about where the actual access and refresh tokens are stored. Typically, they're stored in local or session storage in the browser but when I checked both, I didn't see the actual tokens. I can see that some settings such as my client Id, etc are stored in session storage but I don't see the actual tokens -- see image.

enter image description here

Where does Blazor (WASM) store JWT tokens? Or is there a way to access and inspect them through a method?


Solution

  • This screenshot isn't a successful login. There should be a key named "oidc.user:https://xxxxxx" which store all the tokens. Below is my screenshot after login: ``

    You could try following sample:

    1. In Auth0 dashboard, create a "SPA" application. do following settings. enter image description here enter image description here enter image description here

    2. Create "Blazor WebAssembly Standalone" template. (I use .net8) Install package Microsoft.AspNetCore.Components.WebAssembly.Authentication.

    3. Create "appsettings.json" in "wwwroot" folder with content:

    {
      "Auth0": {
        "Authority": "https://dev-unrb5hhiwnqovxba.us.auth0.com",
        "ClientId": "65DBttLLDUfN0GA3NwIC38J5xufv36Oe",
        "DefaultScopes": [
          "openid",
          "profile",
          "offline_access"
        ],
        "PostLogoutRedirectUri": "https://localhost:7028/authentication/logout-callback",
        "RedirectUri": "https://localhost:7028/authentication/login-callback",
        "ResponseType": "code"
      }
    }
    
    1. Create RedirectToLogin.razor
    @using Microsoft.AspNetCore.Components.WebAssembly.Authentication
    @inject NavigationManager Navigation
    
    @code {
        protected override void OnInitialized()
        {
            Navigation.NavigateToLogin("authentication/login");
        }
    }
    
    1. Create Authentication.razor
    @page "/authentication/{action}"
    @using Microsoft.AspNetCore.Components.WebAssembly.Authentication
    <RemoteAuthenticatorView Action="@Action" />
    @code{
        [Parameter] public string? Action { get; set; }
    }
    
    1. In program.cs add
    builder.Services.AddCascadingAuthenticationState();
    
    builder.Services.AddOidcAuthentication(options =>
    {
        builder.Configuration.Bind("Auth0", options.ProviderOptions);
    });
    
    1. Modify App.razor
         <Router AppAssembly="@typeof(App).Assembly">
            <Found Context="routeData">
                <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                    <NotAuthorized>
                        @if (context.User.Identity?.IsAuthenticated != true)
                        {
                            <RedirectToLogin />
                        }
                        else
                        {
                            <p role="alert">You are not authorized to access this resource.</p>
                        }
                    </NotAuthorized>
                </AuthorizeRouteView>
                <FocusOnNavigate RouteData="@routeData" Selector="h1" />
            </Found>
            <NotFound>
                <PageTitle>Not found</PageTitle>
                <LayoutView Layout="@typeof(MainLayout)">
                    <p role="alert">Sorry, there's nothing at this address.</p>
                </LayoutView>
            </NotFound>
        </Router>
    
    1. Home.razor (login and logout)
    @page "/"
    @using Microsoft.AspNetCore.Components.WebAssembly.Authentication
    @inject NavigationManager Navigation
    
    <AuthorizeView>
        <Authorized>
            Hello, @context.User.Identity?.Name!
            <button @onclick="BeginLogOut">Log out</button>
        </Authorized>
        <NotAuthorized>
            <button @onclick="BeginLogIn">Log In</button>
        </NotAuthorized>
    </AuthorizeView>
    
    @code{
        public void BeginLogIn()
        {
            Navigation.NavigateTo("authentication/login");
        }
        public void BeginLogOut()
        {
            Navigation.NavigateToLogout("authentication/logout");
        }
    }
    
    1. Counter.razor (Use IAccessTokenProvider to get AccessToken)
    @page "/counter"
    @using Microsoft.AspNetCore.Authorization
    @using Microsoft.AspNetCore.Components.Authorization
    @using Microsoft.AspNetCore.Components.WebAssembly.Authentication
    @inject IAccessTokenProvider _tokenProvider
    
    @attribute [Authorize]
    
    <button @onclick="ShowAccessToken">Show Access Token</button>
    <p/>
    access token :@accessToken
    
    @code {
        private string accessToken { get; set; } = "";
    
        private async Task ShowAccessToken()
        {
            var result=await _tokenProvider.RequestAccessToken();                     
        }  
    }
    

    Just note that there's a built-in IAccessTokenProvider to get access token directly. But unfortunately, I didn't see a similar "refreshtokenprovider" method. But as we know that the refresh token is in the browser session storage, it is not hard to get it using Blazored.SessionStorage.

    Reference :
    https://auth0.com/docs/secure/tokens/refresh-tokens/get-refresh-tokens
    https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/standalone-with-authentication-library?view=aspnetcore-8.0&tabs=visual-studio#redirecttologin-component