Blazor Template and Passing ss-tok via querystring

Can you provide some general guidance on how to use the jwtprovider only to receive a ss-tok externally. I thought perhaps I could update the GetAuthenticationStateAsync and pass into the Authenticate call something like:

var authApi = await client.ApiAsync(new Authenticate() { provider="jwt", AccessToken/oauth_token = "eyJpc3MiOiJzc2p3dCIsInN1YiI6M---token" });

but that doesn’t work. Any help or pointers would be appreciated. Just trying to authenticate the user with an external token as they’ll be redirected to the blazor app from an authenticated link like: 'https://app.domain.com?ss-tok=thetoken` or if there are other options, I’m open to them.

The blazor-wasm template is already configured to authenticate with JWT using the JWT Cookies default which is important for SPAs like Blazor WASM to avoid the app having to maintain the token in memory which is vulnerable to XSS attacks, where as by using the recommended Secure HttpOnly Cookies the Blazor App never needs to maintain JWT Tokens in App whilst still making authenticated API Requests using JWT Cookies.

I don’t recommend it for Blazor WASM Apps but you can allow JWTs in HTTP Params with:

new JwtAuthProvider {
    AllowInQueryString = true,
    AllowInFormData = true
}

But to configure a Service Client with JWT you would use the BearerToken property, e.g:

var client = new JsonApiClient(baseUrl) {
    BearerToken = jwtToken
};

Note: JWT Is an IAuthWithRequest Auth Provider meaning there’s no explicit Authentication Step as each API request is authenticated with the JWT, so you would call protected services directly, i.e. not try to call Authenticate API first.

I did a test to set the cookie in the app.razor but it never worked and always shows unauthenticated but you are saying I may need to change the GetAuthenticationStateAsync to remove the authenticate call and just call some custom authenticated endpoint instead and the i guess the session will hydrate. I’ll review that.

I’m having some issues getting these to work and it seems to be related to validating the token. The following code returns false (6.0.3):

This line always returns false so I’m guessing the services will never authenticate correctly: var isValid = jwtProvider.IsJwtValid(token);

What am I doing wrong here?

        var jwtProvider = new JwtAuthProvider(appSettings)
        {
            AuthKeyBase64 = Parameters.ApiAuthKeyBase64,
            AllowInQueryString = true,
            AllowInFormData = true,
            UseTokenCookie = true,
        };

        var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm);
        var body = JwtAuthProvider.CreateJwtPayload(new AuthUserSession
        {
            UserAuthId = "1",
            DisplayName = "Test",
            Email = "as@if.com",
            IsAuthenticated = true,
        },
            issuer: jwtProvider.Issuer,
            expireIn: jwtProvider.ExpireTokensIn,
            //audience: new[] { jwtProvider.Audience },
            roles: new[] { "TheRole" },
            permissions: new[] { "ThePermission" });

        var token = JwtAuthProvider.CreateJwt(header, body, jwtProvider.GetHashAlgorithm());

        var isValid = jwtProvider.IsJwtValid(token);    //

Other than most ServiceStack Integration Tests requiring an initialized AppHost, this test passes as expected:

using var appHost = new BasicAppHost().Init();

var jwtProvider = new JwtAuthProvider {
    AuthKeyBase64 = AesUtils.CreateBase64Key(),
    // Ignore meaningless options outside of a HTTP API
    // AllowInQueryString = true,
    // AllowInFormData = true,
    // UseTokenCookie = true,
};
var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm);
var body = JwtAuthProvider.CreateJwtPayload(new AuthUserSession {
        UserAuthId = "1",
        DisplayName = "Test",
        Email = "as@if.com",
        IsAuthenticated = true,
    },
    issuer: jwtProvider.Issuer,
    expireIn: jwtProvider.ExpireTokensIn,
    roles: new[] { "TheRole" },
    permissions: new[] { "ThePermission" });

var jwt = JwtAuthProvider.CreateJwt(header,body,jwtProvider.GetHashAlgorithm());
Assert.That(jwtProvider.IsJwtValid(jwt));

Does the app host have to be initialized for this to work correctly?

Most ServiceStack Integration Tests requires an initialized AppHost, yes.