diff --git a/.github/workflows/blazor-hybrid-issue-processing.yml b/.github/workflows/blazor-hybrid-issue-processing.yml index 78a03d84159c..673359eb3446 100644 --- a/.github/workflows/blazor-hybrid-issue-processing.yml +++ b/.github/workflows/blazor-hybrid-issue-processing.yml @@ -17,7 +17,7 @@ jobs: issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: `### 🦃 ***Happy Thanksgiving!*** 🍽️ + body: `### 🥳 ***Happy Holidays!*** 🍽️ *Stand-by!* A green dinosaur 🦖 will be along shortly to assist.` }) diff --git a/.github/workflows/blazor-issue-processing.yml b/.github/workflows/blazor-issue-processing.yml index 53a33ac93788..1d32d00740b4 100644 --- a/.github/workflows/blazor-issue-processing.yml +++ b/.github/workflows/blazor-issue-processing.yml @@ -23,21 +23,9 @@ jobs: issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: `### 🦃 ***Happy Thanksgiving!*** 🍽️ + body: `### 🥳 ***Happy Holidays!*** 🍽️ - This issue has been marked for triage on the Blazor Docs GitHub project, and I'll respond after the Thanksgiving holiday during the first week of December. - - We only work on documentation on this repo. If you need product support, close this issue and seek assistance through one or more of the following support channels: - - * [Stack Overflow (tagged: 'blazor')](https://stackoverflow.com/questions/tagged/blazor) - * [General ASP.NET Core Slack Team](https://aspnetcore.slack.com/join/shared_invite/zt-1mv5487zb-EOZxJ1iqb0A0ajowEbxByQ#/shared-invite/email) - * [Blazor Gitter](https://gitter.im/aspnet/Blazor) - - If you think that you found a potential bug in the framework or have product feedback, close this issue and open a new issue for the ASP.NET Core product unit at [dotnet/aspnetcore issues](https://github.com/dotnet/aspnetcore/issues). Bug reports require a clear explanation of the problem, usually including a minimal repro project placed on GitHub for the product unit engineers to download and run. If you determine with the product unit that it isn't a bug but merely requires documentation, please re-open this docs issue and place a cross-link to your engineering issue discussion. - - For problems or feedback on Visual Studio, close this issue and use the [**Report a Problem**](https://docs.microsoft.com/visualstudio/ide/how-to-report-a-problem-with-visual-studio) or [**Suggest a Feature**](https://docs.microsoft.com/visualstudio/ide/suggest-a-feature) processes from within VS, which open internal issues for the VS product unit. For more information, see [Visual Studio Feedback](https://developercommunity.visualstudio.com/home). - - For problems with Visual Studio Code, close this issue and ask for support on community support forums. For bug reports and product feedback, open an issue on the [microsoft/vscode GitHub repo](https://github.com/microsoft/vscode/issues).` + *Stand-by!* A green dinosaur 🦖 will be along shortly to assist.` }) await github.rest.issues.addLabels({ issue_number: context.issue.number, diff --git a/aspnetcore/blazor/components/integration.md b/aspnetcore/blazor/components/integration.md index 15830b17f28f..2dad9cc2c506 100644 --- a/aspnetcore/blazor/components/integration.md +++ b/aspnetcore/blazor/components/integration.md @@ -179,6 +179,12 @@ To support routable Razor components in Razor Pages apps: > [!NOTE] > The preceding example assumes that the component and Blazor script (`_framework/blazor.server.js`) are rendered by the app's layout. For more information, see the [Configuration](#configuration) section. + > + > In .NET 10 or later, the Blazor script is included by the framework if the project contains at least one Razor component file (`.razor`). If your app requires the Blazor script but doesn't contain at least one component, add the following MSBuild property to the app's project file to force unconditional script inclusion: + > + > ```xml + > true + > ``` configures whether the `App` component: @@ -260,6 +266,12 @@ To support routable Razor components in MVC apps: > [!NOTE] > The preceding example assumes that the component and Blazor script (`_framework/blazor.server.js`) are rendered by the app's layout. For more information, see the [Configuration](#configuration) section. + > + > In .NET 10 or later, the Blazor script is included by the framework if the project contains at least one Razor component file (`.razor`). If your app requires the Blazor script but doesn't contain at least one component, add the following MSBuild property to the app's project file to force unconditional script inclusion: + > + > ```xml + > true + > ``` configures whether the `App` component: diff --git a/aspnetcore/blazor/project-structure.md b/aspnetcore/blazor/project-structure.md index 41502429aa01..67524e3d2d5b 100644 --- a/aspnetcore/blazor/project-structure.md +++ b/aspnetcore/blazor/project-structure.md @@ -70,11 +70,11 @@ The `Components/Pages` folder of the server project contains the app's routable Add the angle brackets around the cross-link when activating. -:::moniker range=">= aspnetcore-10.0" +moniker range=">= aspnetcore-10.0" The `NotFound` component (`NotFound.razor`) implements a Not Found page to display when content isn't found for a request path. For more information, see xref:blazor/fundamentals/navigation#not-found-responses. -:::moniker-end +moniker-end --> @@ -332,9 +332,9 @@ Project structure: Add the angle brackets around the cross-link when activating. -:::moniker-end +moniker-end -:::moniker range=">= aspnetcore-10.0" +moniker range=">= aspnetcore-10.0" * `Pages` folder: Contains the Blazor app's routable Razor components (`.razor`). The route for each page is specified using the [`@page`](xref:mvc/views/razor#page) directive. The template includes the following components: * `Counter` component (`Counter.razor`): Implements the Counter page. @@ -342,9 +342,9 @@ Project structure: * `Weather` component (`Weather.razor`): Implements the Weather page. * `NotFound` component (`NotFound.razor`) Implements a Not Found page to display when content isn't found for a request path. For more information, see xref:blazor/fundamentals/navigation#not-found-responses. -:::moniker-end +moniker-end -:::moniker range=">= aspnetcore-8.0 < aspnetcore-10.0" +moniker range=">= aspnetcore-8.0 < aspnetcore-10.0" --> @@ -357,9 +357,9 @@ Project structure: https://github.com/dotnet/AspNetCore.Docs/pull/36145 is merged. -:::moniker-end +moniker-end -:::moniker range=">= aspnetcore-8.0" +moniker range=">= aspnetcore-8.0" --> diff --git a/aspnetcore/blazor/security/additional-scenarios.md b/aspnetcore/blazor/security/additional-scenarios.md index 864e9adf78b7..23740c25252e 100644 --- a/aspnetcore/blazor/security/additional-scenarios.md +++ b/aspnetcore/blazor/security/additional-scenarios.md @@ -551,7 +551,7 @@ Alternatively, the setting can be made in the app settings (`appsettings.json`) ```json { "AzureAd": { - "Authority": "https://login.microsoftonline.com/common/oauth2/v2.0/", + "Authority": "https://login.microsoftonline.com/common/oauth2/v2.0", ... } } diff --git a/aspnetcore/blazor/security/blazor-web-app-with-entra.md b/aspnetcore/blazor/security/blazor-web-app-with-entra.md index 7b512b64a3f6..0d2b6c47d532 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-entra.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-entra.md @@ -109,20 +109,33 @@ For the web API app's registration, the `Weather.Get` scope is configured in the jwtOptions.Authority = "{AUTHORITY}"; ``` -The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee`. +The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` and a directory name of `contoso`. If the app is registered in an ME-ID tenant, the authority should match the issurer (`iss`) of the JWT returned by the identity provider: ```csharp -jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; +jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; +``` + +If the app is registered in a Microsoft Entra External ID tenant: + +```csharp +jwtOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; ``` If the app is registered in an AAD B2C tenant: ```csharp -jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/"; +jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; ``` + + +> [!NOTE] +> Azure Active Directory B2C is no longer available as a service to new customers as of May 1, 2025. AAD B2C tenants are supported for customers with accounts established prior to May 1, 2025 until 2030. For more information, see [Azure AD B2C: Frequently asked questions (FAQ)](/azure/active-directory-b2c/faq). + sets the Audience for any received JWT access token. ```csharp @@ -131,7 +144,7 @@ jwtOptions.Audience = "{AUDIENCE}"; Match the value to just the path of the **Application ID URI** configured when adding the `Weather.Get` scope under **Expose an API** in the Entra or Azure portal. Don't include the scope name, "`Weather.Get`," in the value. -The following examples use an Application (Client) Id of `11112222-bbbb-3333-cccc-4444dddd5555`. The second example uses a tenant domain of `contoso.onmicrosoft.com`. +The following examples use an Application (Client) Id of `11112222-bbbb-3333-cccc-4444dddd5555`. The third example uses a tenant domain of `contoso.onmicrosoft.com`. ME-ID tenant example: @@ -139,6 +152,12 @@ ME-ID tenant example: jwtOptions.Audience = "api://11112222-bbbb-3333-cccc-4444dddd5555"; ``` +Microsoft Entra External ID tenant: + +```csharp +jwtOptions.Audience = "11112222-bbbb-3333-cccc-4444dddd5555"; +``` + AAD B2C tenant example: ```csharp @@ -151,6 +170,15 @@ jwtOptions.Audience = "https://contoso.onmicrosoft.com/11112222-bbbb-3333-cccc-4 Obtain the application (client) ID, tenant (publisher) domain, and directory (tenant) ID from the app's registration in the Entra or Azure portal. The App ID URI is obtained for the `Weather.Get` scope from the web API's registration. Don't include the scope name when taking the App ID URI from the portal. +The authentication configuration depends on the type of tenant: + +* [ME-ID tenant configuration](#me-id-tenant-configuration) +* [Microsoft Entra External ID configuration](#microsoft-entra-external-id-configuration) + +### ME-ID tenant configuration + +*This section applies to an app registered in a Microsoft Entra ID or Azure AAD B2C tenant.* + In the `BlazorWebAppEntra` project's `Program` file, provide the values for the following placeholders in Microsoft Identity Web configuration: ```csharp @@ -168,7 +196,7 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddDownstreamApi("DownstreamApi", configOptions => { configOptions.BaseUrl = "{BASE ADDRESS}"; - configOptions.Scopes = [ "{APP ID URI}/Weather.Get" ]; + configOptions.Scopes = ["{APP ID URI}/Weather.Get"]; }) .AddDistributedTokenCaches(); ``` @@ -200,7 +228,60 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddDownstreamApi("DownstreamApi", configOptions => { configOptions.BaseUrl = "https://localhost:7277"; - configOptions.Scopes = [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ]; + configOptions.Scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; + }) + .AddDistributedTokenCaches(); +``` + +### Microsoft Entra External ID configuration + +*This section applies to an app registered in a Microsoft Entra External ID tenant.* + +In the `BlazorWebAppEntra` project's `Program` file, provide the values for the following placeholders in Microsoft Identity Web configuration: + +```csharp +builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) + .AddMicrosoftIdentityWebApp(msIdentityOptions => + { + msIdentityOptions.CallbackPath = "/signin-oidc"; + msIdentityOptions.Authority = "https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0"; + msIdentityOptions.ClientId = "{CLIENT ID (BLAZOR APP)}"; + msIdentityOptions.ResponseType = "code"; + }) + .EnableTokenAcquisitionToCallDownstreamApi() + .AddDownstreamApi("DownstreamApi", configOptions => + { + configOptions.BaseUrl = "{BASE ADDRESS}"; + configOptions.Scopes = ["{APP ID URI}/Weather.Get"]; + }) + .AddDistributedTokenCaches(); +``` + +Placeholders in the preceding configuration: + +* `{DIRECTORY NAME}`: The directory name of the tenant (publisher) domain. +* `{CLIENT ID (BLAZOR APP)}`: The application (client) ID. +* `{BASE ADDRESS}`: The web API's base address. +* `{APP ID URI}`: The App ID URI for web API scopes. Either of the following formats are used, where the `{CLIENT ID (WEB API)}` placeholder is the Client Id of the web API's Entra registration, and the `{DIRECTORY NAME}` placeholder is the directory name of the tenant (publisher) domain (example: `contoso`). + * ME-ID or Microsoft Entra External ID tenant format: `api://{CLIENT ID (WEB API)}` + * B2C tenant format: `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}` + +Example: + +```csharp +builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) + .AddMicrosoftIdentityWebApp(msIdentityOptions => + { + msIdentityOptions.CallbackPath = "/signin-oidc"; + msIdentityOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; + msIdentityOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444"; + msIdentityOptions.ResponseType = "code"; + }) + .EnableTokenAcquisitionToCallDownstreamApi() + .AddDownstreamApi("DownstreamApi", configOptions => + { + configOptions.BaseUrl = "https://localhost:7277"; + configOptions.Scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; }) .AddDistributedTokenCaches(); ``` @@ -323,20 +404,33 @@ For the web API app's registration, the `Weather.Get` scope is configured in the jwtOptions.Authority = "{AUTHORITY}"; ``` -The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee`. +The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` and a directory name of `contoso`. If the app is registered in an ME-ID tenant, the authority should match the issurer (`iss`) of the JWT returned by the identity provider: ```csharp -jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; +jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; +``` + +If the app is registered in a Microsoft Entra External ID tenant: + +```csharp +jwtOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; ``` If the app is registered in an AAD B2C tenant: ```csharp -jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/"; +jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; ``` + + +> [!NOTE] +> Azure Active Directory B2C is no longer available as a service to new customers as of May 1, 2025. AAD B2C tenants are supported for customers with accounts established prior to May 1, 2025 until 2030. For more information, see [Azure AD B2C: Frequently asked questions (FAQ)](/azure/active-directory-b2c/faq). + sets the Audience for any received JWT access token. ```csharp @@ -345,7 +439,7 @@ jwtOptions.Audience = "{AUDIENCE}"; Match the value to just the path of the **Application ID URI** configured when adding the `Weather.Get` scope under **Expose an API** in the Entra or Azure portal. Don't include the scope name, "`Weather.Get`," in the value. -The following examples use an Application (Client) Id of `11112222-bbbb-3333-cccc-4444dddd5555`. The second example uses a tenant domain of `contoso.onmicrosoft.com`. +The following examples use an Application (Client) Id of `11112222-bbbb-3333-cccc-4444dddd5555`. The third example uses a tenant domain of `contoso.onmicrosoft.com`. ME-ID tenant example: @@ -353,6 +447,12 @@ ME-ID tenant example: jwtOptions.Audience = "api://11112222-bbbb-3333-cccc-4444dddd5555"; ``` +Microsoft Entra External ID tenant: + +```csharp +jwtOptions.Audience = "11112222-bbbb-3333-cccc-4444dddd5555"; +``` + AAD B2C tenant example: ```csharp @@ -365,6 +465,15 @@ jwtOptions.Audience = "https://contoso.onmicrosoft.com/11112222-bbbb-3333-cccc-4 Obtain the application (client) ID, tenant (publisher) domain, and directory (tenant) ID from the app's registration in the Entra or Azure portal. The App ID URI is obtained for the `Weather.Get` scope from the web API's registration. Don't include the scope name when taking the App ID URI from the portal. +The authentication configuration depends on the type of tenant: + +* [ME-ID tenant configuration](#me-id-tenant-configuration) +* [Microsoft Entra External ID configuration](#microsoft-entra-external-id-configuration) + +### ME-ID tenant configuration + +*This section applies to an app registered in a Microsoft Entra ID or Azure AAD B2C tenant.* + In the `BlazorWebAppEntra` project's `Program` file, provide the values for the following placeholders in Microsoft Identity Web configuration: ```csharp @@ -382,7 +491,7 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddDownstreamApi("DownstreamApi", configOptions => { configOptions.BaseUrl = "{BASE ADDRESS}"; - configOptions.Scopes = [ "{APP ID URI}/Weather.Get" ]; + configOptions.Scopes = ["{APP ID URI}/Weather.Get"]; }) .AddDistributedTokenCaches(); ``` @@ -390,7 +499,7 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) Provide the same downstream API scope to the request transformer: ```csharp -List scopes = [ "{APP ID URI}/Weather.Get" ]; +List scopes = ["{APP ID URI}/Weather.Get"]; ``` Placeholders in the preceding configuration: @@ -421,7 +530,72 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) { configOptions.BaseUrl = "https://localhost:7277"; configOptions.Scopes = - [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ]; + ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; + }) + .AddDistributedTokenCaches(); +``` + +Example: + +```csharp +List scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; +``` + +### Microsoft Entra External ID configuration + +*This section applies to an app registered in a Microsoft Entra External ID tenant.* + +In the `BlazorWebAppEntra` project's `Program` file, provide the values for the following placeholders in Microsoft Identity Web configuration: + +```csharp +builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) + .AddMicrosoftIdentityWebApp(msIdentityOptions => + { + msIdentityOptions.CallbackPath = "/signin-oidc"; + msIdentityOptions.Authority = "https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0"; + msIdentityOptions.ClientId = "{CLIENT ID (BLAZOR APP)}"; + msIdentityOptions.ResponseType = "code"; + }) + .EnableTokenAcquisitionToCallDownstreamApi() + .AddDownstreamApi("DownstreamApi", configOptions => + { + configOptions.BaseUrl = "{BASE ADDRESS}"; + configOptions.Scopes = ["{APP ID URI}/Weather.Get"]; + }) + .AddDistributedTokenCaches(); +``` + +Provide the same downstream API scope to the request transformer: + +```csharp +List scopes = ["{APP ID URI}/Weather.Get"]; +``` + +Placeholders in the preceding configuration: + +* `{DIRECTORY NAME}`: The directory name of the tenant (publisher) domain. +* `{CLIENT ID (BLAZOR APP)}`: The application (client) ID. +* `{BASE ADDRESS}`: The web API's base address. +* `{APP ID URI}`: The App ID URI for web API scopes. Either of the following formats are used, where the `{CLIENT ID (WEB API)}` placeholder is the Client Id of the web API's Entra registration, and the `{DIRECTORY NAME}` placeholder is the directory name of the tenant (publishers) domain (example: `contoso`). + * ME-ID or Microsoft Entra External ID tenant format: `api://{CLIENT ID (WEB API)}` + * B2C tenant format: `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}` + +Example: + +```csharp +builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) + .AddMicrosoftIdentityWebApp(msIdentityOptions => + { + msIdentityOptions.CallbackPath = "/signin-oidc"; + msIdentityOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; + msIdentityOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444"; + msIdentityOptions.ResponseType = "code"; + }) + .EnableTokenAcquisitionToCallDownstreamApi() + .AddDownstreamApi("DownstreamApi", configOptions => + { + configOptions.BaseUrl = "https://localhost:7277"; + configOptions.Scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; }) .AddDistributedTokenCaches(); ``` @@ -429,7 +603,7 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) Example: ```csharp -List scopes = [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ]; +List scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]; ``` :::zone-end @@ -581,7 +755,7 @@ In the app settings file (`appsettings.json`) of the `BlazorWebAppEntra` project }, "DownstreamApi": { "BaseUrl": "{BASE ADDRESS}", - "Scopes": [ "{APP ID URI}/Weather.Get" ] + "Scopes": ["{APP ID URI}/Weather.Get"] } } ``` @@ -609,7 +783,7 @@ Example: }, "DownstreamApi": { "BaseUrl": "https://localhost:7277", - "Scopes": [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ] + "Scopes": ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"] } ``` @@ -635,7 +809,7 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) - .AddDownstreamApi("DownstreamApi", configOptions => - { - configOptions.BaseUrl = "..."; -- configOptions.Scopes = [ "..." ]; +- configOptions.Scopes = ["..."]; - }) + .AddDownstreamApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi")) .AddDistributedTokenCaches(); @@ -659,8 +833,8 @@ In the `MinimalApiJwt` project, add the following app settings configuration to "Authentication": { "Schemes": { "Bearer": { - "Authority": "https://sts.windows.net/{TENANT ID (WEB API)}/", - "ValidAudiences": [ "{APP ID URI (WEB API)}" ] + "Authority": "https://sts.windows.net/{TENANT ID (WEB API)}", + "ValidAudiences": ["{APP ID URI (WEB API)}"] } } }, @@ -673,12 +847,14 @@ Update the placeholders in the preceding configuration to match the values that Authority formats adopt the following patterns: -* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}/` -* B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0/` +* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}` +* Microsoft Entra External ID: `https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0` +* B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0` Audience formats adopt the following patterns (`{CLIENT ID}` is the Client Id of the web API; `{DIRECTORY NAME}` is the directory name, for example, `contoso`): * ME-ID tenant type: `api://{CLIENT ID}` +* Microsoft Entra External ID: `{CLIENT ID}` * B2C tenant type: `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}` The configuration is automatically picked up by the JWT bearer authentication builder. diff --git a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md index a1a2485fbe3d..6ff58d6df700 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md @@ -164,13 +164,13 @@ The format of the Authority depends on the type of tenant in use. The following ME-ID tenant Authority example: ```csharp -jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; +jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; ``` AAD B2C tenant Authority example: ```csharp -jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/"; +jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; ``` The sets the Audience for any received OIDC token. @@ -296,14 +296,14 @@ oidcOptions.ClientId = "{CLIENT ID}"; The following example uses a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` and a Client ID of `00001111-aaaa-2222-bbbb-3333cccc4444`: ```csharp -oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/"; +oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; oidcOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444"; ``` For multi-tenant apps, the "common" authority should be used. You can also use the "common" authority for single-tenant apps, but a custom is required, as shown later in this section. ```csharp -oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/"; +oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0"; ``` : Configures the OIDC handler to only perform authorization code flow. Implicit grants and hybrid flows are unnecessary in this mode. The OIDC handler automatically requests the appropriate tokens using the code returned from the authorization endpoint. @@ -511,13 +511,13 @@ The format of the Authority depends on the type of tenant in use. The following ME-ID tenant Authority example: ```csharp -jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; +jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; ``` AAD B2C tenant Authority example: ```csharp -jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/"; +jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; ``` The sets the Audience for any received OIDC token. @@ -677,14 +677,14 @@ oidcOptions.ClientId = "{CLIENT ID}"; The following example uses a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` and a Client ID of `00001111-aaaa-2222-bbbb-3333cccc4444`: ```csharp -oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/"; +oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; oidcOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444"; ``` For multi-tenant apps, the "common" authority should be used. You can also use the "common" authority for single-tenant apps, but a custom is required, as shown later in this section. ```csharp -oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/"; +oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0"; ``` : Configures the OIDC handler to only perform authorization code flow. Implicit grants and hybrid flows are unnecessary in this mode. The OIDC handler automatically requests the appropriate tokens using the code returned from the authorization endpoint. @@ -914,13 +914,13 @@ The format of the Authority depends on the type of tenant in use. The following ME-ID tenant Authority example: ```csharp -jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; +jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; ``` AAD B2C tenant Authority example: ```csharp -jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/"; +jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; ``` The sets the Audience for any received OIDC token. @@ -1016,14 +1016,14 @@ oidcOptions.ClientId = "{CLIENT ID}"; The following example uses a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` and a Client ID of `00001111-aaaa-2222-bbbb-3333cccc4444`: ```csharp -oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/"; +oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; oidcOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444"; ``` For multi-tenant apps, the "common" authority should be used. You can also use the "common" authority for single-tenant apps, but a custom is required, as shown later in this section. ```csharp -oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/"; +oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0"; ``` : Configures the OIDC handler to only perform authorization code flow. Implicit grants and hybrid flows are unnecessary in this mode. The OIDC handler automatically requests the appropriate tokens using the code returned from the authorization endpoint. @@ -1135,7 +1135,7 @@ In the app settings file (`appsettings.json`) of the `BlazorWebAppOidc` or `Blaz "Authentication": { "Schemes": { "MicrosoftOidc": { - "Authority": "https://login.microsoftonline.com/{TENANT ID (BLAZOR APP)}/v2.0/", + "Authority": "https://login.microsoftonline.com/{TENANT ID (BLAZOR APP)}/v2.0", "ClientId": "{CLIENT ID (BLAZOR APP)}", "CallbackPath": "/signin-oidc", "SignedOutCallbackPath": "/signout-callback-oidc", @@ -1158,7 +1158,7 @@ Update the placeholders in the preceding configuration to match the values that * `{CLIENT ID (BLAZOR APP)}`: The Client Id of the Blazor app. * `{APP ID URI (WEB API)}`: The App ID URI of the web API. -The "common" Authority (`https://login.microsoftonline.com/common/v2.0/`) should be used for multi-tenant apps. To use the "common" Authority for single-tenant apps, see the [Use the "common" Authority for single-tenant apps](#use-the-common-authority-for-single-tenant-apps) section. +The "common" Authority (`https://login.microsoftonline.com/common/v2.0`) should be used for multi-tenant apps. To use the "common" Authority for single-tenant apps, see the [Use the "common" Authority for single-tenant apps](#use-the-common-authority-for-single-tenant-apps) section. Update any other values in the preceding configuration to match custom/non-default values used in the `Program` file. @@ -1188,7 +1188,7 @@ In the `MinimalApiJwt` project, add the following app settings configuration to "Authentication": { "Schemes": { "Bearer": { - "Authority": "https://sts.windows.net/{TENANT ID (WEB API)}/", + "Authority": "https://sts.windows.net/{TENANT ID (WEB API)}", "ValidAudiences": [ "{APP ID URI (WEB API)}" ] } } @@ -1202,12 +1202,14 @@ Update the placeholders in the preceding configuration to match the values that Authority formats adopt the following patterns: -* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}/` -* B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0/` +* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}` +* Microsoft Entra External ID: `https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0` +* B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0` Audience formats adopt the following patterns (`{CLIENT ID}` is the Client Id of the web API; `{DIRECTORY NAME}` is the directory name, for example, `contoso`): * ME-ID tenant type: `api://{CLIENT ID}` +* Microsoft Entra External ID: `{CLIENT ID}` * B2C tenant type: `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}` The configuration is automatically picked up by the JWT bearer authentication builder. diff --git a/aspnetcore/blazor/security/webassembly/additional-scenarios.md b/aspnetcore/blazor/security/webassembly/additional-scenarios.md index be072a5cd516..08304606a178 100644 --- a/aspnetcore/blazor/security/webassembly/additional-scenarios.md +++ b/aspnetcore/blazor/security/webassembly/additional-scenarios.md @@ -1341,7 +1341,7 @@ Alternatively, the setting can be made in the app settings (`appsettings.json`) ```json { "Local": { - "Authority": "https://login.microsoftonline.com/common/oauth2/v2.0/", + "Authority": "https://login.microsoftonline.com/common/oauth2/v2.0", ... } } diff --git a/aspnetcore/blazor/tutorials/movie-database-app/index.md b/aspnetcore/blazor/tutorials/movie-database-app/index.md index a842b32b1204..3a4d4b4ddbc0 100644 --- a/aspnetcore/blazor/tutorials/movie-database-app/index.md +++ b/aspnetcore/blazor/tutorials/movie-database-app/index.md @@ -29,10 +29,8 @@ At the end of the tutorial, you'll have a Blazor Web App that can display and ma ## Secure authentication flow required for production apps -This tutorial uses a local database that doesn't require user authentication. Production apps should use the most secure authentication flow available. For more information on authentication for deployed test and production Blazor Web Apps, see the following resources: +This tutorial uses a local database that doesn't require user authentication. Production apps should use the most secure authentication flow available. For more information on authentication for deployed test and production Blazor Web Apps, see and the following articles in the *Server* security node: -* -* and the following articles in the *Server* security node * * diff --git a/aspnetcore/blazor/tutorials/movie-database-app/part-1.md b/aspnetcore/blazor/tutorials/movie-database-app/part-1.md index 62a5f6964374..5e6bceef82aa 100644 --- a/aspnetcore/blazor/tutorials/movie-database-app/part-1.md +++ b/aspnetcore/blazor/tutorials/movie-database-app/part-1.md @@ -286,9 +286,9 @@ var app = builder.Build(); Next, the HTTP request pipeline is configured. -In the development environment: +When the app isn't running in the `Development` environment: -* Exception Handler Middleware () processes errors and displays a developer exception page during development app runs. +* Exception Handler Middleware () processes errors and displays a custom error page. * [HTTP Strict Transport Security Protocol (HSTS) Middleware](xref:security/enforcing-ssl#http-strict-transport-security-protocol-hsts) () processes [HSTS](https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Strict_Transport_Security_Cheat_Sheet.html). ```csharp diff --git a/aspnetcore/blazor/tutorials/movie-database-app/part-8/_static/filtered-to-road-warrior-sqlite.png b/aspnetcore/blazor/tutorials/movie-database-app/part-8/_static/filtered-to-road-warrior-sqlite.png index 440661fa12b5..11e2fd8e4c61 100644 Binary files a/aspnetcore/blazor/tutorials/movie-database-app/part-8/_static/filtered-to-road-warrior-sqlite.png and b/aspnetcore/blazor/tutorials/movie-database-app/part-8/_static/filtered-to-road-warrior-sqlite.png differ diff --git a/aspnetcore/blazor/tutorials/movie-database-app/part-8/_static/filtered-to-road-warrior.png b/aspnetcore/blazor/tutorials/movie-database-app/part-8/_static/filtered-to-road-warrior.png index ad2bc99eac44..8739ed862c56 100644 Binary files a/aspnetcore/blazor/tutorials/movie-database-app/part-8/_static/filtered-to-road-warrior.png and b/aspnetcore/blazor/tutorials/movie-database-app/part-8/_static/filtered-to-road-warrior.png differ diff --git a/aspnetcore/docfx.json b/aspnetcore/docfx.json index 255d04df7c41..ab5180b2da12 100644 --- a/aspnetcore/docfx.json +++ b/aspnetcore/docfx.json @@ -44,7 +44,7 @@ "social_image_url": "/dotnet/media/dotnet-logo.png", "feedback_product_url": "https://github.com/dotnet/aspnetcore/blob/main/CONTRIBUTING.md", "ms.service": "aspnet-core", - "ms.topic": "conceptual", + "ms.topic": "article", "uhfHeaderId": "MSDocsHeader-AspNet", "searchScope": [ "ASP.NET Core" ], "zone_pivot_group_filename": "core/zone-pivot-groups.json" diff --git a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md index 65a17c54b44a..1ef80c1dd8b9 100644 --- a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md +++ b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md @@ -36,6 +36,12 @@ For more information, see true +``` + For more information, see the following resources: * diff --git a/aspnetcore/tutorials/first-mvc-app/working-with-sql.md b/aspnetcore/tutorials/first-mvc-app/working-with-sql.md index 33f044248127..3a6d59528de9 100644 --- a/aspnetcore/tutorials/first-mvc-app/working-with-sql.md +++ b/aspnetcore/tutorials/first-mvc-app/working-with-sql.md @@ -1,11 +1,12 @@ --- title: Part 5, work with a database in an ASP.NET Core MVC app +ai-usage: ai-assisted author: wadepickett description: Part 5 of tutorial series on ASP.NET Core MVC. +monikerRange: '>= aspnetcore-3.1' ms.author: wpickett -ms.date: 03/02/2025 ms.custom: sfi-ropc-nochange -monikerRange: '>= aspnetcore-3.1' +ms.date: 12/01/2025 uid: tutorials/first-mvc-app/working-with-sql --- @@ -17,6 +18,23 @@ By [Rick Anderson](https://twitter.com/RickAndMSFT) and [Jon P Smith](https://tw :::moniker range=">= aspnetcore-9.0" +## Introduction + +This part of the tutorial series focuses on working with a SQL database in your ASP.NET Core MVC application. + +You’ll learn how to: + +- Register and configure the Entity Framework Core database context for your ASP.NET Core MVC app. +- Work with database connection strings for local development. +- Use SQL Server Express LocalDB for development and examine your database and data using SQL Server Object Explorer. +- Seed your database with initial sample data. + +## Prerequisite + +This tutorial uses a database you set up in the previous step: . + +## Working with the database context + The `MvcMovieContext` object handles the task of connecting to the database and mapping `Movie` objects to database records. The database context is registered with the [Dependency Injection](xref:fundamentals/dependency-injection) container in the `Program.cs` file: # [Visual Studio](#tab/visual-studio) diff --git a/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql3-5.md b/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql3-5.md index 2db4f4217cc6..19cd7ea1280a 100644 --- a/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql3-5.md +++ b/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql3-5.md @@ -1,5 +1,22 @@ :::moniker range=">= aspnetcore-3.1 < aspnetcore-6.0" +## Introduction + +This part of the tutorial series focuses on working with a SQL database in your ASP.NET Core MVC application. + +You’ll learn how to: + +- Register and configure the Entity Framework Core database context for your ASP.NET Core MVC app. +- Work with database connection strings for local development. +- Use SQL Server Express LocalDB for development and examine your database and data using SQL Server Object Explorer. +- Seed your database with initial sample data. + +## Prerequisite + +This tutorial uses a database you set up in the previous step: . + +## Working with the database context + The `MvcMovieContext` object handles the task of connecting to the database and mapping `Movie` objects to database records. The database context is registered with the [Dependency Injection](xref:fundamentals/dependency-injection) container in the `ConfigureServices` method in the `Startup.cs` file: # [Visual Studio](#tab/visual-studio) diff --git a/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql6.md b/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql6.md index 391a8abaa999..abaafcd339f6 100644 --- a/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql6.md +++ b/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql6.md @@ -1,5 +1,22 @@ :::moniker range="= aspnetcore-6.0" +## Introduction + +This part of the tutorial series focuses on working with a SQL database in your ASP.NET Core MVC application. + +You’ll learn how to: + +- Register and configure the Entity Framework Core database context for your ASP.NET Core MVC app. +- Work with database connection strings for local development. +- Use SQL Server Express LocalDB for development and examine your database and data using SQL Server Object Explorer. +- Seed your database with initial sample data. + +## Prerequisite + +This tutorial uses a database you set up in the previous step: . + +## Working with the database context + The `MvcMovieContext` object handles the task of connecting to the database and mapping `Movie` objects to database records. The database context is registered with the [Dependency Injection](xref:fundamentals/dependency-injection) container in the `Program.cs` file: # [Visual Studio](#tab/visual-studio) diff --git a/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql7.md b/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql7.md index dee0e27fe7a4..7277bfc2f4d7 100644 --- a/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql7.md +++ b/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql7.md @@ -1,5 +1,22 @@ :::moniker range="= aspnetcore-7.0" +## Introduction + +This part of the tutorial series focuses on working with a SQL database in your ASP.NET Core MVC application. + +You’ll learn how to: + +- Register and configure the Entity Framework Core database context for your ASP.NET Core MVC app. +- Work with database connection strings for local development. +- Use SQL Server Express LocalDB for development and examine your database and data using SQL Server Object Explorer. +- Seed your database with initial sample data. + +## Prerequisite + +This tutorial uses a database you set up in the previous step: . + +## Working with the database context + The `MvcMovieContext` object handles the task of connecting to the database and mapping `Movie` objects to database records. The database context is registered with the [Dependency Injection](xref:fundamentals/dependency-injection) container in the `Program.cs` file: # [Visual Studio](#tab/visual-studio) diff --git a/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql8.md b/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql8.md index 1fe00bb52b98..b00fe4d4f9ef 100644 --- a/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql8.md +++ b/aspnetcore/tutorials/first-mvc-app/working-with-sql/includes/working-with-sql8.md @@ -1,5 +1,22 @@ :::moniker range="= aspnetcore-8.0" +## Introduction + +This part of the tutorial series focuses on working with a SQL database in your ASP.NET Core MVC application. + +You’ll learn how to: + +- Register and configure the Entity Framework Core database context for your ASP.NET Core MVC app. +- Work with database connection strings for local development. +- Use SQL Server Express LocalDB for development and examine your database and data using SQL Server Object Explorer. +- Seed your database with initial sample data. + +## Prerequisite + +This tutorial uses a database you set up in the previous step: . + +## Working with the database context + The `MvcMovieContext` object handles the task of connecting to the database and mapping `Movie` objects to database records. The database context is registered with the [Dependency Injection](xref:fundamentals/dependency-injection) container in the `Program.cs` file: # [Visual Studio](#tab/visual-studio) @@ -109,4 +126,4 @@ The app shows the seeded data. > [Previous: Adding a model](~/tutorials/first-mvc-app/adding-model.md) > [Next: Adding controller methods and views](~/tutorials/first-mvc-app/controller-methods-views.md) -:::moniker-end \ No newline at end of file +:::moniker-end