AzureAD / microsoft-identity-web

Helps creating protected web apps and web APIs with Microsoft identity platform and Azure AD B2C
MIT License
671 stars 208 forks source link

Detailed reference doc for appsettings.json #2108

Open willfiddes opened 1 year ago

willfiddes commented 1 year ago

Documentation related to component

Doesn't exist however this is related to the appsettings.json

Please check all that apply

Description of the issue

We should document all of the available options that you can configure in appsettings in one central place. And which ones overwrite the other.

Just a couple of examples... If you use Authority, I believe this overwrites Instance and tenant and PolicyID? Audience can also be used to add additional accepted audience value? Can this support collection of audiences? RedirectUri modifies the redirect_uri that MSAL uses.

jmprieur commented 1 year ago

Thanks for the feedback. This is a fair request, @willfiddes and I've been wanting to do that for a while. There is a start of this here, but it needs more work and needs to be surfaced better. https://github.com/AzureAD/microsoft-identity-abstractions-for-dotnet/blob/main/src/Microsoft.Identity.Abstractions/ApplicationOptions/sample-configuration.json

electrocnic commented 1 month ago

Bumping this issue as I really need this right now and it is mind-boggling how such a basic Microsoft API is not thoroughly documented.

It took me hours to come across this open issue, while another person was asking the same question on stackoverflow.com/questions/78821945.

In this case: Please help me configure my appsettings.json correctly when I have a C# ASP.NET Core backend application but also a Vite React frontend SPA, and I would use appsettings.json for both.

How do I define the user scopes in appsettings.json so that the user can login to our registered AppServices app with msal in the frontend and Microsoft.Identity.Web in the backend? My current approach would be something like

"AzureAd": {
    "Domain": "our-domain.com",
    "ClientId": "our-client-id",
    "ClientSecret": "-",
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "our-tenant-id",
    "CallbackPath": "/signin-oidc",
    "ScopeDomain": "api://our-domain.com/",
    "ApiScopes": "api://our-domain.com/access_as_user api://external-api-client-id-or-scope-domain/access_as_user"
},
"GraphApi": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": "User.Read email openid profile offline_access User.Read.All Presence.Read.All"
},

(I think there is no ApiScopes for the kind of App I have, I only found ApiScopes in the context of B2C apps, but this is not the case here)

In my vite config for the frontend, to build the msal configuration, I would use:

const siteDomain = appsettings.AzureAd.ScopeDomain.replace('api://', 'https://')
const redirectUri = `${siteDomain}${appsettings.AzureAd.CallbackPath.substring(1)}`

// https://vitejs.dev/config/
export default defineConfig({
  define: {
    __TENANT_ID__: JSON.stringify(appsettings.AzureAd.TenantId),
    __CLIENT_ID__: JSON.stringify(appsettings.AzureAd.ClientId),
    __DOMAIN__: JSON.stringify(appsettings.AzureAd.Domain),
    __SCOPE_DOMAIN__: JSON.stringify(appsettings.AzureAd.ScopeDomain),
    __INSTANCE__: JSON.stringify(appsettings.AzureAd.Instance),
    __REDIRECT_URI__: JSON.stringify(redirectUri),
    __SCOPES__: JSON.stringify(appsettings.AzureAd.ApiScopes),
    __GRAPH_SCOPES__: JSON.stringify(appsettings.GraphApi.Scopes),
  },
})

This does not work at all and a solid reference manual with all possible key-value pairs for appsettings.json would certainly be very helpful. The linked https://github.com/AzureAD/microsoft-identity-abstractions-for-dotnet/blob/main/src/Microsoft.Identity.Abstractions/ApplicationOptions/sample-configuration.json from your previous answer is sadly also not whole and it confuses me at

// Downstream APIs
  "DownstreamApis": [
    {
      "GraphBeta": {
        "BaseUrl": "https://graph.microsoft.com/beta",
        "Scopes": "user.read"
      }
    }
  ],

This section looks somewhat promising, but still very unclear to how I would need to configure it in my usecase, where the frontend msal would use these scopes for login with on-behalf-flow, and not only login to the corresponding backend of our app, but also to login to another, externally hosted api, which has its own registration in App Services.

This would be my current approach of configuring msal in the frontend:

import type { Configuration } from '@azure/msal-browser'
import { LogLevel, PublicClientApplication } from '@azure/msal-browser'

export const msalConfig: Configuration = {
  auth: {
    clientId: __CLIENT_ID__,
    authority: `${__INSTANCE__}${__TENANT_ID__}`,
    redirectUri: __REDIRECT_URI__,
  },
  cache: {
    cacheLocation: 'sessionStorage',
    storeAuthStateInCookie: false,
  }
}

export const msalInstance = new PublicClientApplication(msalConfig)

export const loginRequest = {
  scopes: [...__SCOPES__.split(' '), ...__GRAPH_SCOPES__.split(' ')],
}

// Entrypoint:
<MsalProvider instance={msalInstance}>

// Actual login with redirect:
await msalInstance.initialize()
msalInstance.loginRedirect(loginRequest)

(I am handling the redirect comeback but left it out for simplicity)

I get this error:

AADSTS500011: The resource principal named api://our-domain.com was not found in the tenant named our-tenant-id. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.

Beware though, that our-domain.com is definitely registered in this tenant!

And if I remove the ApiScopes from appsettings.json alltogether, and for local development using

"AzureAd": {
    "ScopeDomain": "api://localhost:7021/"
},

I get

ServerError: invalid_request: Error(s): 9002326 - Timestamp: 2024-08-12 11:34:30Z - Description: AADSTS9002326: Cross-origin token redemption is permitted only for the 'Single-Page Application' client-type. Request origin: 'https://localhost:7021'.

(This is very likely due to a misconfiguration in the AppServices by us?)

Now my point is, I suppose that mine and many other lives could be so much easier if we had a good documentation on the appsettings.json, especially in context with Microsoft.Identity.Web and msal and AzureAd/EntraID scopes.

All I found was several difficult to read walls of text, but not clear reference manual similar to this one: https://learn.microsoft.com/en-us/entra/identity-platform/reference-app-manifest or this one: https://learn.microsoft.com/en-us/azure/app-service/reference-app-settings?tabs=kudu%2Cdotnet

I even found a 5 year old rant by another person about the underlying issues (in my opinion his statements hold true to a significant amount up to today) https://github.com/MicrosoftDocs/azure-docs/issues/43056

Last but not least, maybe I also additionaly misconfigured the ASP.NET Core backend as well?

IConfigurationSection azureAd = _configuration.GetSection("AzureAd");
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

// Set up JWT Bearer authentication for validating tokens from the frontend
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddMicrosoftIdentityWebApi(azureAd)
  .EnableTokenAcquisitionToCallDownstreamApi()
  .AddMicrosoftGraph(_configuration.GetSection("GraphApi"))
  .AddInMemoryTokenCaches();

services.AddAuthorization();