Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// NOTE: This file is included in Microsoft.Identity.Web package (v3.3.0+).
// This copy is maintained for AI skill reference and documentation purposes.
// For production use, reference the NuGet package directly.

using System.Security.Claims;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// NOTE: This file is included in Microsoft.Identity.Web package (v3.3.0+).
// This copy is maintained for AI skill reference and documentation purposes.
// For production use, reference the NuGet package directly.

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
Expand Down
32 changes: 12 additions & 20 deletions .github/skills/entra-id-aspire-authentication/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,12 @@ Get-ChildItem -Recurse -Filter "Program.cs" | ForEach-Object {
- [ ] Step 2.1: Add Microsoft.Identity.Web package
- [ ] Step 2.2: Update appsettings.json with AzureAd and scopes
- [ ] Step 2.3: Update Program.cs with OIDC, token acquisition, and **BlazorAuthenticationChallengeHandler**
- [ ] Step 2.4: Copy LoginLogoutEndpointRouteBuilderExtensions.cs from skill folder (adds incremental consent support)
- [ ] Step 2.5: Copy BlazorAuthenticationChallengeHandler.cs from skill folder
- [ ] Step 2.6: Create UserInfo.razor component (LOGIN BUTTON)
- [ ] Step 2.7: Update MainLayout.razor to include UserInfo
- [ ] Step 2.8: Update Routes.razor with AuthorizeRouteView
- [ ] Step 2.9: Store client secret in user-secrets
- [ ] Step 2.10: Add try/catch with ChallengeHandler on **every page calling APIs**
- [ ] Step 2.4: Verify Microsoft.Identity.Web version includes Blazor helpers (v3.3.0+)
- [ ] Step 2.5: Create UserInfo.razor component (LOGIN BUTTON)
- [ ] Step 2.6: Update MainLayout.razor to include UserInfo
- [ ] Step 2.7: Update Routes.razor with AuthorizeRouteView
- [ ] Step 2.8: Store client secret in user-secrets
- [ ] Step 2.9: Add try/catch with ChallengeHandler on **every page calling APIs**

---

Expand Down Expand Up @@ -241,17 +240,11 @@ app.MapGroup("/authentication").MapLoginAndLogout();
app.Run();
```

**2.4 Copy `LoginLogoutEndpointRouteBuilderExtensions.cs` from skill folder:**
**2.4 Blazor authentication helpers:**

Copy the `LoginLogoutEndpointRouteBuilderExtensions.cs` file from this skill's folder to the Web project root.
These helpers ship in the `Microsoft.Identity.Web` NuGet package (version 3.3.0+). Simply add `using Microsoft.Identity.Web;` — no file copying required.

> **AGENT:** The file is located at `./LoginLogoutEndpointRouteBuilderExtensions.cs`. The namespace is `Microsoft.Identity.Web` so no changes are needed — it provides the `MapLoginAndLogout()` extension method with support for incremental consent and Conditional Access.
**2.5 Copy `BlazorAuthenticationChallengeHandler.cs` from skill folder:**

Copy the `BlazorAuthenticationChallengeHandler.cs` file from this skill's folder to the Web project root.

> **AGENT:** The file is located at `./BlazorAuthenticationChallengeHandler.cs`. The namespace is `Microsoft.Identity.Web` so no changes are needed — it will be available once Microsoft.Identity.Web is referenced.
> **AGENT:** The `LoginLogoutEndpointRouteBuilderExtensions` class provides the `MapLoginAndLogout()` extension method with support for incremental consent and Conditional Access. The `BlazorAuthenticationChallengeHandler` class handles authentication challenges in Blazor Server components. Both are now included in Microsoft.Identity.Web and are automatically available once you reference the package.
**2.6 Create UserInfo Component (`Components/UserInfo.razor`) — THE LOGIN BUTTON:**

Expand Down Expand Up @@ -499,12 +492,12 @@ else
| ApiService | `appsettings.json` | AzureAd config (ClientId, TenantId) |
| Web | `Program.cs` | OIDC + token acquisition + challenge handler registration |
| Web | `appsettings.json` | AzureAd config + downstream API scopes |
| Web | `LoginLogoutEndpointRouteBuilderExtensions.cs` | Login/logout with incremental consent support (**copy from skill**) |
| Web | `BlazorAuthenticationChallengeHandler.cs` | Reusable auth challenge handler (**copy from skill**) |
| Web | `Components/UserInfo.razor` | **Login/logout button UI** |
| Web | `Components/Layout/MainLayout.razor` | Include UserInfo in layout |
| Web | `Components/Routes.razor` | AuthorizeRouteView for protected pages |

> **Note:** `LoginLogoutEndpointRouteBuilderExtensions` and `BlazorAuthenticationChallengeHandler` are now included in the Microsoft.Identity.Web NuGet package (v3.3.0+). Simply reference the package and use `using Microsoft.Identity.Web;` — no file copying required.
---

## Post-Implementation Verification
Expand All @@ -522,12 +515,11 @@ else
- [ ] Web `Program.cs` has `AddMicrosoftIdentityWebApp` and `AddMicrosoftIdentityMessageHandler`
- [ ] Web `Program.cs` has `AddScoped<BlazorAuthenticationChallengeHandler>()`
- [ ] Web `appsettings.json` has `AzureAd` and scope configuration
- [ ] Web has `LoginLogoutEndpointRouteBuilderExtensions.cs` (with incremental consent params)
- [ ] Web has `BlazorAuthenticationChallengeHandler.cs`
- [ ] Web has `Components/UserInfo.razor` (**LOGIN BUTTON**)
- [ ] Web `MainLayout.razor` includes `<UserInfo />`
- [ ] Web `Routes.razor` uses `AuthorizeRouteView`
- [ ] **Every page calling protected APIs** has try/catch with `ChallengeHandler.HandleExceptionAsync(ex)`
- [ ] Microsoft.Identity.Web package version is 3.3.0 or higher

3. **AGENT: Inform user of next step:**
> "✅ **Phase 1 complete!** Authentication code is in place. The app will **build** but **won't run** until app registrations are configured.
Expand Down
43 changes: 21 additions & 22 deletions docs/frameworks/aspire.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,9 @@ app.UseAuthorization();
app.MapGroup("/authentication").MapLoginAndLogout();
```

> ⚠️ **Don't forget:** Copy the helper files (`BlazorAuthenticationChallengeHandler.cs`, `LoginLogoutEndpointRouteBuilderExtensions.cs`) and create `UserInfo.razor`. See [Part 2](#part-2-configure-blazor-frontend-for-authentication) for details.
> ⚠️ **Don't forget:** Create `UserInfo.razor` for the login button. See [Part 2](#part-2-configure-blazor-frontend-for-authentication) for details.
>
> **Note:** `BlazorAuthenticationChallengeHandler` and `LoginLogoutEndpointRouteBuilderExtensions` ship in Microsoft.Identity.Web (v3.3.0+) — no file copying required.

**That's it!** The `MicrosoftIdentityMessageHandler` automatically acquires and attaches tokens, and `BlazorAuthenticationChallengeHandler` handles consent/Conditional Access challenges.

Expand All @@ -298,14 +300,14 @@ app.MapGroup("/authentication").MapLoginAndLogout();
| | `.csproj` | Add `Microsoft.Identity.Web` |
| **Web** | `Program.cs` | OIDC auth, token acquisition, BlazorAuthenticationChallengeHandler |
| | `appsettings.json` | Azure AD config, downstream API scopes |
| | `.csproj` | Add `Microsoft.Identity.Web` |
| | `LoginLogoutEndpointRouteBuilderExtensions.cs` | Login/logout with incremental consent *(copy from skill)* |
| | `BlazorAuthenticationChallengeHandler.cs` | Auth challenge handler *(copy from skill)* |
| | `.csproj` | Add `Microsoft.Identity.Web` (v3.3.0+) |
| | `Components/UserInfo.razor` | **Login button UI** *(new file)* |
| | `Components/Layout/MainLayout.razor` | Include UserInfo component |
| | `Components/Routes.razor` | AuthorizeRouteView for protected pages |
| | Pages calling APIs | Try/catch with ChallengeHandler |

> **Note:** `LoginLogoutEndpointRouteBuilderExtensions` and `BlazorAuthenticationChallengeHandler` are included in Microsoft.Identity.Web (v3.3.0+) — no file copying required.

---

## What you'll build & how it works
Expand Down Expand Up @@ -528,7 +530,7 @@ curl -H "Authorization: Bearer <TOKEN>" https://localhost:<PORT>/weatherforecast

## Part 2: Configure Blazor frontend for authentication

> 📍 **Still in Phase 1** — This part completes the code implementation. You'll need the helper files from the skill folder.
> 📍 **Still in Phase 1** — This part completes the code implementation. The Blazor helpers are included in Microsoft.Identity.Web (v3.3.0+).

The Blazor Server app uses **Microsoft.Identity.Web** to:
- Sign users in with OIDC
Expand Down Expand Up @@ -726,22 +728,16 @@ builder.Services.AddHttpClient<WeatherApiClient>(client =>

</details>

### 2.4: Copy helper files from skill folder

The authentication implementation requires two helper files. **Copy these from the skill folder** rather than creating them manually:
### 2.4: Blazor authentication helpers

```powershell
# From your solution root, copy the helper files
$skillPath = ".github/skills/entra-id-aspire-authentication"
Copy-Item "$skillPath/LoginLogoutEndpointRouteBuilderExtensions.cs" "MyService.Web/"
Copy-Item "$skillPath/BlazorAuthenticationChallengeHandler.cs" "MyService.Web/"
```
These helpers ship in the **Microsoft.Identity.Web** NuGet package (version **3.3.0+**). Simply add `using Microsoft.Identity.Web;` — no file copying required.

> 💡 **Tip:** These files are in the `Microsoft.Identity.Web` namespace, so they're available once you reference the package. Eventually they will
> ship in the Microsoft.Identity.Web NuGet packge.
> 💡 **Note:** `LoginLogoutEndpointRouteBuilderExtensions` provides the `MapLoginAndLogout()` extension method, and `BlazorAuthenticationChallengeHandler` handles authentication challenges. Both are now included in the package and are automatically available once you reference it.

<details>
<summary><strong>📄 View LoginLogoutEndpointRouteBuilderExtensions.cs</strong></summary>
<summary><strong>📄 View LoginLogoutEndpointRouteBuilderExtensions.cs (Reference)</strong></summary>

> **Note:** This implementation ships in **Microsoft.Identity.Web v3.3.0+**. The code below is shown for reference only — use the NuGet package in production.

This enhanced version supports **incremental consent** and **Conditional Access** via query parameters:

Expand Down Expand Up @@ -844,7 +840,9 @@ public static class LoginLogoutEndpointRouteBuilderExtensions
</details>

<details>
<summary><strong>📄 View BlazorAuthenticationChallengeHandler.cs</strong></summary>
<summary><strong>📄 View BlazorAuthenticationChallengeHandler.cs (Reference)</strong></summary>

> **Note:** This implementation ships in **Microsoft.Identity.Web v3.3.0+**. The code below is shown for reference only — use the NuGet package in production.

This handler manages authentication challenges in Blazor Server components:

Expand Down Expand Up @@ -1194,12 +1192,11 @@ Use this checklist to verify all steps are complete:
- [ ] Added `.RequireAuthorization()` to protected endpoints

### Web/Blazor project
- [ ] Added `Microsoft.Identity.Web` package
- [ ] Added `Microsoft.Identity.Web` package (v3.3.0+)
- [ ] Updated `appsettings.json` with `AzureAd` and `WeatherApi` sections
- [ ] Updated `Program.cs` with OIDC, token acquisition
- [ ] Added `AddScoped<BlazorAuthenticationChallengeHandler>()`
- [ ] Copied `LoginLogoutEndpointRouteBuilderExtensions.cs` from skill folder
- [ ] Copied `BlazorAuthenticationChallengeHandler.cs` from skill folder
- [ ] Verified Blazor helpers are available (included in package v3.3.0+)
- [ ] Created `Components/UserInfo.razor` (**THE LOGIN BUTTON**)
- [ ] Updated `MainLayout.razor` to include `<UserInfo />`
- [ ] Updated `Routes.razor` with `AuthorizeRouteView`
Expand Down Expand Up @@ -1574,10 +1571,12 @@ This guide has companion **AI Skills** for GitHub Copilot, Claude, and other AI
| **entra-id-aspire-authentication** | Phase 1: Add authentication code | [SKILL.md](../../.github/skills/entra-id-aspire-authentication/SKILL.md) |
| **entra-id-aspire-provisioning** | Phase 2: Create app registrations | [SKILL.md](../../.github/skills/entra-id-aspire-provisioning/SKILL.md) |

The authentication skill folder also contains **ready-to-copy helper files**:
The authentication skill folder also contains **reference implementations of helper files**:
- `BlazorAuthenticationChallengeHandler.cs` - Handles incremental consent and Conditional Access
- `LoginLogoutEndpointRouteBuilderExtensions.cs` - Enhanced login/logout endpoints

> **Note:** These helpers are included in Microsoft.Identity.Web (v3.3.0+). The skill folder copies are maintained for AI skill reference and documentation purposes.

See the [Skills README](../../.github/skills/README.md) for installation instructions.

---
Expand Down
Loading