Blog

  • Authenticating with ITokenProvider/MSAL and Refit in ASP.NET Core

    In my Blazor app, I need to be able to send HTTP requests to my API service and I use Refit for this. That way I can use Refitter to generate my API class and save a lot of time, and I can also use the same class to make calls no matter if I am on Server or WebAssembly (very useful if you are using Auto render mode!)

    First, create an AuthBearerTokenFactory:

    public static class AuthBearerTokenFactory
    {
        private static Func<HttpRequestMessage, CancellationToken, Task<string>>? _getBearerTokenAsyncFunc;
    
        /// <summary>
        /// Provide a delegate that returns a bearer token to use for authorization
        /// </summary>
        public static void SetBearerTokenGetterFunc(Func<HttpRequestMessage, CancellationToken, Task<string>> getBearerTokenAsyncFunc)
          => _getBearerTokenAsyncFunc = getBearerTokenAsyncFunc;
    
        public static Task<string> GetBearerTokenAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (_getBearerTokenAsyncFunc is null)
                throw new InvalidOperationException("Must set Bearer Token Func before using it!");
            return _getBearerTokenAsyncFunc!(request, cancellationToken);
        }
    }

    Then register the SetBearerTokenGetterFunc in your program after app = builder.Build()

    AuthBearerTokenFactory.SetBearerTokenGetterFunc(async (request, cancellationToken) =>
    {
        var httpContextAccessor = app.Services.GetRequiredService<IHttpContextAccessor>();
        var configuration = app.Services.GetRequiredService<IConfiguration>();
        var scopedServices = httpContextAccessor.HttpContext?.RequestServices ?? throw new Exception("HttpContext not set!");
        var tokenAcquisition = scopedServices.GetRequiredService<ITokenAcquisition>();
        var scopes = configuration.GetSection("SCOPES_HERE").Get<IEnumerable<string>>() ?? throw new Exception("Scopes are not set in app config!");
        var httpContext = httpContextAccessor.HttpContext ?? throw new Exception("No HttpContext available!");
        return await tokenAcquisition.GetAccessTokenForUserAsync(scopes, user: httpContext.User);
    });

    Then when registering Refit, set the auth header getter to AuthBearerTokenFactory.GetBearerTokenAsync

    And now you should be able to authenticate!

    Note: I have had some issues with Hot Reload causing the HTTP context to not be set, but this only seems to occur when developing, and only sometimes, so I don’t consider it a big deal.

  • Publishing MAUI apps for iOS in TeamCity

    I want to publish iOS apps automatically on pushing to master but I couldn’t find another guide on how to do so. So, I’ve put one together.

    First, create a new .NET action with the command set to Publish. Under configuration, set Release and Framework to net9.0-ios (or whatever appropriate version for your use case).

    Next, we want to push the build to Apple using xcrun. Add a new command line step:

    xcrun altool --validate-app -f mobile/bin/Release/net9.0-ios/ios-arm64/publish/ParaMeter.ipa -t ios -u <email> -p <app-password>

    In my case, my project is stored under “mobile” and uses the default output folder; this may need to be adjusted if you specify a different output path for builds.

    Now we want to actually upload the app:

    xcrun altool --upload-app -f mobile/bin/Release/net9.0-ios/ios-arm64/publish/ParaMeter.ipa -t ios -u <username> -p <password>

    And that should be it!