Skip to content

Commit bce9940

Browse files
authored
Add ME External ID guidance (#36367)
1 parent aae9740 commit bce9940

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 (publisher) 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
```
@@ -323,20 +404,33 @@ For the web API app's registration, the `Weather.Get` scope is configured in the
323404
jwtOptions.Authority = "{AUTHORITY}";
324405
```
325406

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

328409
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:
329410

330411
```csharp
331-
jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/";
412+
jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee";
413+
```
414+
415+
If the app is registered in a Microsoft Entra External ID tenant:
416+
417+
```csharp
418+
jwtOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";
332419
```
333420

334421
If the app is registered in an AAD B2C tenant:
335422

336423
```csharp
337-
jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";
424+
jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";
338425
```
339426

427+
<!-- UPDATE 15.0 - Remove the following NOTE when .NET 15 releases in
428+
2030, which is when B2C support will end for existing
429+
customers prior to 5/1/25. -->
430+
431+
> [!NOTE]
432+
> 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).
433+
340434
<xref:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions.Audience%2A> sets the Audience for any received JWT access token.
341435

342436
```csharp
@@ -345,14 +439,20 @@ jwtOptions.Audience = "{AUDIENCE}";
345439

346440
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.
347441

348-
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`.
442+
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`.
349443

350444
ME-ID tenant example:
351445

352446
```csharp
353447
jwtOptions.Audience = "api://11112222-bbbb-3333-cccc-4444dddd5555";
354448
```
355449

450+
Microsoft Entra External ID tenant:
451+
452+
```csharp
453+
jwtOptions.Audience = "11112222-bbbb-3333-cccc-4444dddd5555";
454+
```
455+
356456
AAD B2C tenant example:
357457

358458
```csharp
@@ -365,6 +465,15 @@ jwtOptions.Audience = "https://contoso.onmicrosoft.com/11112222-bbbb-3333-cccc-4
365465

366466
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.
367467

468+
The authentication configuration depends on the type of tenant:
469+
470+
* [ME-ID tenant configuration](#me-id-tenant-configuration)
471+
* [Microsoft Entra External ID configuration](#microsoft-entra-external-id-configuration)
472+
473+
### ME-ID tenant configuration
474+
475+
*This section applies to an app registered in a Microsoft Entra ID or Azure AAD B2C tenant.*
476+
368477
In the `BlazorWebAppEntra` project's `Program` file, provide the values for the following placeholders in Microsoft Identity Web configuration:
369478

370479
```csharp
@@ -382,15 +491,15 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
382491
.AddDownstreamApi("DownstreamApi", configOptions =>
383492
{
384493
configOptions.BaseUrl = "{BASE ADDRESS}";
385-
configOptions.Scopes = [ "{APP ID URI}/Weather.Get" ];
494+
configOptions.Scopes = ["{APP ID URI}/Weather.Get"];
386495
})
387496
.AddDistributedTokenCaches();
388497
```
389498

390499
Provide the same downstream API scope to the request transformer:
391500

392501
```csharp
393-
List<string> scopes = [ "{APP ID URI}/Weather.Get" ];
502+
List<string> scopes = ["{APP ID URI}/Weather.Get"];
394503
```
395504

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

429603
Example:
430604

431605
```csharp
432-
List<string> scopes = [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ];
606+
List<string> scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];
433607
```
434608

435609
:::zone-end
@@ -581,7 +755,7 @@ In the app settings file (`appsettings.json`) of the `BlazorWebAppEntra` project
581755
},
582756
"DownstreamApi": {
583757
"BaseUrl": "{BASE ADDRESS}",
584-
"Scopes": [ "{APP ID URI}/Weather.Get" ]
758+
"Scopes": ["{APP ID URI}/Weather.Get"]
585759
}
586760
}
587761
```
@@ -609,7 +783,7 @@ Example:
609783
},
610784
"DownstreamApi": {
611785
"BaseUrl": "https://localhost:7277",
612-
"Scopes": [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ]
786+
"Scopes": ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]
613787
}
614788
```
615789

@@ -635,7 +809,7 @@ builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
635809
- .AddDownstreamApi("DownstreamApi", configOptions =>
636810
- {
637811
- configOptions.BaseUrl = "...";
638-
- configOptions.Scopes = [ "..." ];
812+
- configOptions.Scopes = ["..."];
639813
- })
640814
+ .AddDownstreamApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
641815
.AddDistributedTokenCaches();
@@ -659,8 +833,8 @@ In the `MinimalApiJwt` project, add the following app settings configuration to
659833
"Authentication": {
660834
"Schemes": {
661835
"Bearer": {
662-
"Authority": "https://sts.windows.net/{TENANT ID (WEB API)}/",
663-
"ValidAudiences": [ "{APP ID URI (WEB API)}" ]
836+
"Authority": "https://sts.windows.net/{TENANT ID (WEB API)}",
837+
"ValidAudiences": ["{APP ID URI (WEB API)}"]
664838
}
665839
}
666840
},
@@ -673,12 +847,14 @@ Update the placeholders in the preceding configuration to match the values that
673847

674848
Authority formats adopt the following patterns:
675849

676-
* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}/`
677-
* B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0/`
850+
* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}`
851+
* Microsoft Entra External ID: `https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0`
852+
* B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0`
678853

679854
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`):
680855

681856
* ME-ID tenant type: `api://{CLIENT ID}`
857+
* Microsoft Entra External ID: `{CLIENT ID}`
682858
* B2C tenant type: `https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}`
683859

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

0 commit comments

Comments
 (0)