Call protected controller from serverprerendered blazor component

I have a .net core MVC application that has a serverprerendered blazor component. It uses auth0’s refreshing tokens. Someone online suggests getting the token in razor view and pass it to blazor as a parameter. But how to update the token if using this method?

Hi @planyway

Welcome back to the Auth0 Community!

The advice to pass the token as a parameter via the Razor view is correct for initialization, but it fails for updating because Razor parameters are strictly evaluated once during the initial page load.

To handle updates without forcing the user to refresh the page, you must capture that initial parameter and store it inside a Scoped Dependency Injection (DI) Service. When the token expires, this Scoped Service will use the Refresh Token to manually request a new Access Token from Auth0 and hold it in memory for the remainder of the Blazor circuit’s life.

To solve this, you need an intermediary service to manage the token’s state dynamically during the lifetime of the SignalR circuit.

Here is the recommended pattern:

Step 1: Create a Scoped Token Service
Create a C# class that will live for the duration of the user’s Blazor circuit. This service will hold the tokens and contain the logic to refresh them.

public class BlazorTokenProvider
{
    public string AccessToken { get; private set; }
    public string RefreshToken { get; private set; }
    public DateTime ExpiresAt { get; private set; }

    public void Initialize(string access, string refresh, DateTime expiresAt)
    {
        AccessToken = access;
        RefreshToken = refresh;
        ExpiresAt = expiresAt;
    }

    public async Task<string> GetValidAccessTokenAsync(HttpClient httpClient, string auth0Domain, string clientId, string clientSecret)
    {
        if (DateTime.UtcNow < ExpiresAt.AddMinutes(-1))
        {
            return AccessToken;
        }

        var response = await httpClient.PostAsJsonAsync($"https://{auth0Domain}/oauth/token", new
        {
            grant_type = "refresh_token",
            client_id = clientId,
            client_secret = clientSecret,
            refresh_token = RefreshToken
        });

        if (response.IsSuccessStatusCode)
        {
            var tokenResponse = await response.Content.ReadFromJsonAsync<TokenResponse>();
            AccessToken = tokenResponse.access_token;
            ExpiresAt = DateTime.UtcNow.AddSeconds(tokenResponse.expires_in);
            
            if (!string.IsNullOrEmpty(tokenResponse.refresh_token)) 
            {
                RefreshToken = tokenResponse.refresh_token;
            }
            return AccessToken;
        }
        
        throw new Exception("Unable to refresh token.");
    }
}

(Register this as builder.Services.AddScoped<BlazorTokenProvider>(); in your Program.cs)

Step 2: Pass All Necessary Data via Razor
In your MVC Controller, extract the Access Token, Refresh Token, and Expiration time from the HttpContext and pass all of them to the view.

<component type="typeof(MyBlazorComponent)" 
           render-mode="ServerPrerendered" 
           param-InitialAccessToken="@ViewBag.AccessToken" 
           param-InitialRefreshToken="@ViewBag.RefreshToken" 
           param-ExpiresAt="@ViewBag.ExpiresAt" />

Step 3: Initialize the Service in the Component
In your Blazor component’s OnInitialized lifecycle method, inject the BlazorTokenProvider and feed it the parameters.

@inject BlazorTokenProvider TokenProvider
@inject HttpClient Http

@code {
    [Parameter] public string InitialAccessToken { get; set; }
    [Parameter] public string InitialRefreshToken { get; set; }
    [Parameter] public DateTime ExpiresAt { get; set; }

    protected override void OnInitialized()
    {
        TokenProvider.Initialize(InitialAccessToken, InitialRefreshToken, ExpiresAt);
    }

    private async Task CallApi()
    {
        string validToken = await TokenProvider.GetValidAccessTokenAsync(Http, "YOUR_DOMAIN", "YOUR_ID", "YOUR_SECRET");
        
        // Use validToken for your API call...
    }
}

Kind Regards,
Nik