microsoft / azure-container-apps

Roadmap and issues for Azure Container Apps
MIT License
365 stars 29 forks source link

Local Development Authentication #629

Open gt-downunder opened 1 year ago

gt-downunder commented 1 year ago

Issue:

Setting up the Azure Container App (ACA) with authentication against a specific provider is simple enough and I can see the http-auth container gets created automatically, handling all incoming requests. However, if my target environment is an ACA with a built-in http-auth container, how do I handle authentication when developing locally?

The documentation (https://learn.microsoft.com/en-us/azure/container-apps/authentication#authorization) mentions that authentication middleware is not necessary when using the container apps authentication setting. I imagine a lot of apps, like mine, need to integrate with another API (i.e., Graph), which when deployed is easy enough because you get the AccessToken, but locally there's no way for me to do that integration simply because I'm not logging in against any provider.

I have gone down the path of adding back the standard authentication middleware logic in my apps Program.cs and wrapped it inside an ASPNETCORE_ENVIRONMENT check to ensure it only executes under "local" environment conditions. This just feels clunky, and I feel there should be a more elegant solution.

Suggestions:

  1. Instructions on how to handle auth locally when using the ACA authentication provider
  2. Make available the http-auth container to a local dev environment (is this possible via a Docker container?)
  3. Open to suggestions.....
SophCarp commented 1 year ago

Hi @gt-downunder thanks for sharing! There's a How-to in the docs with instructions on how to use a custom authentication provider: https://learn.microsoft.com/en-us/azure/container-apps/authentication-openid

Is this what you're looking for? I know these instructions are how to make one that adheres to the OpenID Connect specification, so let me know if that's not what you want.

gt-downunder commented 1 year ago

@SophCarp that's for setting up the container's authentication provider, but what I need is independent of any container app. Imagine I'm building a web application on my local dev machine, and I intend on deploying it to ACA. In ACA, you set up the authentication provider and it just works, but now I have authentication working in ACA but not locally on my dev machine. Additionally, accessing the token under an ACA environment is different compared to a local middleware pipeline (see below).

The question is, how do we handle local dev environment authentication if the target environment is ACA where that's handled for us? In an ACA environment, my app doesn't need any of the middleware logic for authentication, but locally, I need to have some authentication process so I can obtain the AccessToken and call Graph.

The following is how I'm doing it today, using a local environment check, but it feels wrong and I'm wondering if there's a better way to leverage the ACA http-auth container somehow, or emulate the ACA auth in any way (Docker, Minikube, etc.)?

Program.cs


// add local authentication middleware since deploying to ACA provides its own http-auth container
if (builder.Environment.IsEnvironment("local"))
{
    JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
    builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
                .EnableTokenAcquisitionToCallDownstreamApi(new[] { "user.read", "user.readbasic.all" })
                .AddMicrosoftGraph(builder.Configuration.GetSection("Graph"))
                .AddInMemoryTokenCaches();

    builder.Services.AddAuthorization(options => options.FallbackPolicy = options.DefaultPolicy)
                .AddMicrosoftIdentityConsentHandler();
}
SophCarp commented 1 year ago

Ah, thanks for the clarification. I'll look into it and see if we have any guidance.

gt-downunder commented 1 year ago

I've also opened this question on Stack Overflow and will update this issue if I get any guidance. https://stackoverflow.com/questions/75513260/azure-container-apps-blazor-server-get-the-access-token

Azuredevmuc commented 1 year ago

I have the same question. It looks like pretty much the same on how Static Web Apps are using it. And with Static Web App CLI, u can mock the behavior and simulate an Azure AD for instance in the background. The Stack Overflow Link is broken @gt-downunder . I'd love to see a solution like it is done in SWA.

chriswue commented 1 year ago

@Azuredevmuc The SO link ain't broken but the question was deleted and you can only see that above a certain rep level on SO. It was closed as too broad.

scottjohnstone commented 1 year ago

@gt-downunder how are you able to execute AddMicrosoftIdentityConsentHandler():

    builder.Services.AddAuthorization(options => options.FallbackPolicy = options.DefaultPolicy)
                .AddMicrosoftIdentityConsentHandler();

Given the following open issue: https://github.com/AzureAD/microsoft-identity-web/issues/1198

Where the only known solution is to use

 services.AddServerSideBlazor()
         .AddMicrosoftIdentityConsentHandler();

per the previous reference and this one: https://github.com/AzureAD/microsoft-identity-web/wiki/Managing-incremental-consent-and-conditional-access

BTW, not sure if it's applicable as I'm not using ACA but only Web app, but I'm able to use same auth without checks for dev/prod when running locally or in Azure:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi() //initialScopes = none
        .AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
        .AddDownstreamApi("DownstreamAPI1", builder.Configuration.GetSection("DownstreamAPI1"))
        .AddDownstreamApi("DownstreamAPI2", builder.Configuration.GetSection("DownstreamAPI2"))
        .AddInMemoryTokenCaches();

// alternatively:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("DownstreamAPI1"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamAPI2", builder.Configuration.GetSection("DownstreamAPI2"))
    .AddInMemoryTokenCaches();