Skip to content

Commit 1283423

Browse files
committed
Add ME External ID guidance
1 parent af8896f commit 1283423

File tree

4 files changed

+218
-40
lines changed

4 files changed

+218
-40
lines changed

aspnetcore/blazor/security/additional-scenarios.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ Alternatively, the setting can be made in the app settings (`appsettings.json`)
551551
```json
552552
{
553553
"AzureAd": {
554-
"Authority": "https://login.microsoftonline.com/common/oauth2/v2.0/",
554+
"Authority": "https://login.microsoftonline.com/common/oauth2/v2.0",
555555
...
556556
}
557557
}

aspnetcore/blazor/security/blazor-web-app-with-entra.md

Lines changed: 197 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,33 @@ For the web API app's registration, the `Weather.Get` scope is configured in the
109109
jwtOptions.Authority = "{AUTHORITY}";
110110
```
111111

112-
The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee`.
112+
The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` and a directory name of `contoso`.
113113

114114
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:
115115

116116
```csharp
117-
jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/";
117+
jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee";
118+
```
119+
120+
If the app is registered in a Microsoft Entra External ID tenant:
121+
122+
```csharp
123+
jwtOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";
118124
```
119125

120126
If the app is registered in an AAD B2C tenant:
121127

122128
```csharp
123-
jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";
129+
jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";
124130
```
125131

132+
<!-- UPDATE 15.0 - Remove the following NOTE when .NET 15 releases in
133+
2030, which is when B2C support will end for existing
134+
customers prior to 5/1/25. -->
135+
136+
> [!NOTE]
137+
> 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).
138+
126139
<xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions.Audience%2A> sets the Audience for any received JWT access token.
127140

128141
```csharp
@@ -131,14 +144,20 @@ jwtOptions.Audience = "{AUDIENCE}";
131144

132145
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.
133146

134-
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`.
147+
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`.
135148

136149
ME-ID tenant example:
137150

138151
```csharp
139152
jwtOptions.Audience = "api://11112222-bbbb-3333-cccc-4444dddd5555";
140153
```
141154

155+
Microsoft Entra External ID tenant:
156+
157+
```csharp
158+
jwtOptions.Audience = "11112222-bbbb-3333-cccc-4444dddd5555";
159+
```
160+
142161
AAD B2C tenant example:
143162

144163
```csharp
@@ -151,6 +170,15 @@ jwtOptions.Audience = "https://contoso.onmicrosoft.com/11112222-bbbb-3333-cccc-4
151170

152171
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.
153172

173+
The authentication configuration depends on the type of tenant:
174+
175+
* [ME-ID tenant configuration](#me-id-tenant-configuration)
176+
* [Microsoft Entra External ID configuration](#microsoft-entra-external-id-configuration)
177+
178+
### ME-ID tenant configuration
179+
180+
*This section applies to an app registered in a Microsoft Entra ID or Azure AAD B2C tenant.*
181+
154182
In the `BlazorWebAppEntra` project's `Program` file, provide the values for the following placeholders in Microsoft Identity Web configuration:
155183

156184
```csharp
@@ -168,7 +196,7 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
168196
.AddDownstreamApi("DownstreamApi", configOptions =>
169197
{
170198
configOptions.BaseUrl = "{BASE ADDRESS}";
171-
configOptions.Scopes = [ "{APP ID URI}/Weather.Get" ];
199+
configOptions.Scopes = ["{APP ID URI}/Weather.Get"];
172200
})
173201
.AddDistributedTokenCaches();
174202
```
@@ -200,7 +228,60 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
200228
.AddDownstreamApi("DownstreamApi", configOptions =>
201229
{
202230
configOptions.BaseUrl = "https://localhost:7277";
203-
configOptions.Scopes = [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ];
231+
configOptions.Scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];
232+
})
233+
.AddDistributedTokenCaches();
234+
```
235+
236+
### Microsoft Entra External ID configuration
237+
238+
*This section applies to an app registered in a Microsoft Entra External ID tenant.*
239+
240+
In the `BlazorWebAppEntra` project's `Program` file, provide the values for the following placeholders in Microsoft Identity Web configuration:
241+
242+
```csharp
243+
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
244+
.AddMicrosoftIdentityWebApp(msIdentityOptions =>
245+
{
246+
msIdentityOptions.CallbackPath = "/signin-oidc";
247+
msIdentityOptions.Authority = "https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0";
248+
msIdentityOptions.ClientId = "{CLIENT ID (BLAZOR APP)}";
249+
msIdentityOptions.ResponseType = "code";
250+
})
251+
.EnableTokenAcquisitionToCallDownstreamApi()
252+
.AddDownstreamApi("DownstreamApi", configOptions =>
253+
{
254+
configOptions.BaseUrl = "{BASE ADDRESS}";
255+
configOptions.Scopes = ["{APP ID URI}/Weather.Get"];
256+
})
257+
.AddDistributedTokenCaches();
258+
```
259+
260+
Placeholders in the preceding configuration:
261+
262+
* `{DIRECTORY NAME}`: The directory name of the tenant (publisher) domain.
263+
* `{CLIENT ID (BLAZOR APP)}`: The application (client) ID.
264+
* `{BASE ADDRESS}`: The web API's base address.
265+
* `{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`).
266+
* ME-ID or Microsoft Entra External ID tenant format: `api://{CLIENT ID (WEB API)}`
267+
* B2C tenant format: `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}`
268+
269+
Example:
270+
271+
```csharp
272+
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
273+
.AddMicrosoftIdentityWebApp(msIdentityOptions =>
274+
{
275+
msIdentityOptions.CallbackPath = "/signin-oidc";
276+
msIdentityOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";
277+
msIdentityOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
278+
msIdentityOptions.ResponseType = "code";
279+
})
280+
.EnableTokenAcquisitionToCallDownstreamApi()
281+
.AddDownstreamApi("DownstreamApi", configOptions =>
282+
{
283+
configOptions.BaseUrl = "https://localhost:7277";
284+
configOptions.Scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];
204285
})
205286
.AddDistributedTokenCaches();
206287
```
@@ -317,20 +398,33 @@ For the web API app's registration, the `Weather.Get` scope is configured in the
317398
jwtOptions.Authority = "{AUTHORITY}";
318399
```
319400

320-
The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee`.
401+
The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` and a directory name of `contoso`.
321402

322403
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:
323404

324405
```csharp
325-
jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/";
406+
jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee";
407+
```
408+
409+
If the app is registered in a Microsoft Entra External ID tenant:
410+
411+
```csharp
412+
jwtOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";
326413
```
327414

328415
If the app is registered in an AAD B2C tenant:
329416

330417
```csharp
331-
jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";
418+
jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";
332419
```
333420

421+
<!-- UPDATE 15.0 - Remove the following NOTE when .NET 15 releases in
422+
2030, which is when B2C support will end for existing
423+
customers prior to 5/1/25. -->
424+
425+
> [!NOTE]
426+
> 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).
427+
334428
<xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions.Audience%2A> sets the Audience for any received JWT access token.
335429

336430
```csharp
@@ -339,14 +433,20 @@ jwtOptions.Audience = "{AUDIENCE}";
339433

340434
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.
341435

342-
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`.
436+
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`.
343437

344438
ME-ID tenant example:
345439

346440
```csharp
347441
jwtOptions.Audience = "api://11112222-bbbb-3333-cccc-4444dddd5555";
348442
```
349443

444+
Microsoft Entra External ID tenant:
445+
446+
```csharp
447+
jwtOptions.Audience = "11112222-bbbb-3333-cccc-4444dddd5555";
448+
```
449+
350450
AAD B2C tenant example:
351451

352452
```csharp
@@ -359,6 +459,15 @@ jwtOptions.Audience = "https://contoso.onmicrosoft.com/11112222-bbbb-3333-cccc-4
359459

360460
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.
361461

462+
The authentication configuration depends on the type of tenant:
463+
464+
* [ME-ID tenant configuration](#me-id-tenant-configuration)
465+
* [Microsoft Entra External ID configuration](#microsoft-entra-external-id-configuration)
466+
467+
### ME-ID tenant configuration
468+
469+
*This section applies to an app registered in a Microsoft Entra ID or Azure AAD B2C tenant.*
470+
362471
In the `BlazorWebAppEntra` project's `Program` file, provide the values for the following placeholders in Microsoft Identity Web configuration:
363472

364473
```csharp
@@ -376,15 +485,15 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
376485
.AddDownstreamApi("DownstreamApi", configOptions =>
377486
{
378487
configOptions.BaseUrl = "{BASE ADDRESS}";
379-
configOptions.Scopes = [ "{APP ID URI}/Weather.Get" ];
488+
configOptions.Scopes = ["{APP ID URI}/Weather.Get"];
380489
})
381490
.AddDistributedTokenCaches();
382491
```
383492

384493
Provide the same downstream API scope to the request transformer:
385494

386495
```csharp
387-
List<string> scopes = [ "{APP ID URI}/Weather.Get" ];
496+
List<string> scopes = ["{APP ID URI}/Weather.Get"];
388497
```
389498

390499
Placeholders in the preceding configuration:
@@ -415,15 +524,80 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
415524
{
416525
configOptions.BaseUrl = "https://localhost:7277";
417526
configOptions.Scopes =
418-
[ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ];
527+
["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];
528+
})
529+
.AddDistributedTokenCaches();
530+
```
531+
532+
Example:
533+
534+
```csharp
535+
List<string> scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];
536+
```
537+
538+
### Microsoft Entra External ID configuration
539+
540+
*This section applies to an app registered in a Microsoft Entra External ID tenant.*
541+
542+
In the `BlazorWebAppEntra` project's `Program` file, provide the values for the following placeholders in Microsoft Identity Web configuration:
543+
544+
```csharp
545+
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
546+
.AddMicrosoftIdentityWebApp(msIdentityOptions =>
547+
{
548+
msIdentityOptions.CallbackPath = "/signin-oidc";
549+
msIdentityOptions.Authority = "https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0";
550+
msIdentityOptions.ClientId = "{CLIENT ID (BLAZOR APP)}";
551+
msIdentityOptions.ResponseType = "code";
552+
})
553+
.EnableTokenAcquisitionToCallDownstreamApi()
554+
.AddDownstreamApi("DownstreamApi", configOptions =>
555+
{
556+
configOptions.BaseUrl = "{BASE ADDRESS}";
557+
configOptions.Scopes = ["{APP ID URI}/Weather.Get"];
558+
})
559+
.AddDistributedTokenCaches();
560+
```
561+
562+
Provide the same downstream API scope to the request transformer:
563+
564+
```csharp
565+
List<string> scopes = ["{APP ID URI}/Weather.Get"];
566+
```
567+
568+
Placeholders in the preceding configuration:
569+
570+
* `{DIRECTORY NAME}`: The directory name of the tenant (publisher) domain.
571+
* `{CLIENT ID (BLAZOR APP)}`: The application (client) ID.
572+
* `{BASE ADDRESS}`: The web API's base address.
573+
* `{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`).
574+
* ME-ID or Microsoft Entra External ID tenant format: `api://{CLIENT ID (WEB API)}`
575+
* B2C tenant format: `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}`
576+
577+
Example:
578+
579+
```csharp
580+
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
581+
.AddMicrosoftIdentityWebApp(msIdentityOptions =>
582+
{
583+
msIdentityOptions.CallbackPath = "/signin-oidc";
584+
msIdentityOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";
585+
msIdentityOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
586+
msIdentityOptions.ResponseType = "code";
587+
})
588+
.EnableTokenAcquisitionToCallDownstreamApi()
589+
.AddDownstreamApi("DownstreamApi", configOptions =>
590+
{
591+
configOptions.BaseUrl = "https://localhost:7277";
592+
configOptions.Scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];
419593
})
420594
.AddDistributedTokenCaches();
421595
```
422596

423597
Example:
424598

425599
```csharp
426-
List<string> scopes = [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ];
600+
List<string> scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];
427601
```
428602

429603
:::zone-end
@@ -591,7 +765,7 @@ In the app settings file (`appsettings.json`) of the `BlazorWebAppEntra` project
591765
},
592766
"DownstreamApi": {
593767
"BaseUrl": "{BASE ADDRESS}",
594-
"Scopes": [ "{APP ID URI}/Weather.Get" ]
768+
"Scopes": ["{APP ID URI}/Weather.Get"]
595769
}
596770
}
597771
```
@@ -619,7 +793,7 @@ Example:
619793
},
620794
"DownstreamApi": {
621795
"BaseUrl": "https://localhost:7277",
622-
"Scopes": [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ]
796+
"Scopes": ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]
623797
}
624798
```
625799

@@ -645,7 +819,7 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
645819
- .AddDownstreamApi("DownstreamApi", configOptions =>
646820
- {
647821
- configOptions.BaseUrl = "...";
648-
- configOptions.Scopes = [ "..." ];
822+
- configOptions.Scopes = ["..."];
649823
- })
650824
+ .AddDownstreamApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
651825
.AddDistributedTokenCaches();
@@ -669,8 +843,8 @@ In the `MinimalApiJwt` project, add the following app settings configuration to
669843
"Authentication": {
670844
"Schemes": {
671845
"Bearer": {
672-
"Authority": "https://sts.windows.net/{TENANT ID (WEB API)}/",
673-
"ValidAudiences": [ "{APP ID URI (WEB API)}" ]
846+
"Authority": "https://sts.windows.net/{TENANT ID (WEB API)}",
847+
"ValidAudiences": ["{APP ID URI (WEB API)}"]
674848
}
675849
}
676850
},
@@ -683,12 +857,14 @@ Update the placeholders in the preceding configuration to match the values that
683857

684858
Authority formats adopt the following patterns:
685859

686-
* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}/`
687-
* B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0/`
860+
* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}`
861+
* Microsoft Entra External ID: `https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0`
862+
* B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0`
688863

689864
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`):
690865

691866
* ME-ID tenant type: `api://{CLIENT ID}`
867+
* Microsoft Entra External ID: `{CLIENT ID}`
692868
* B2C tenant type: `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}`
693869

694870
The configuration is automatically picked up by the JWT bearer authentication builder.

0 commit comments

Comments
 (0)