diff --git a/README.md b/README.md
index 9ad88bb5..6ad17168 100644
--- a/README.md
+++ b/README.md
@@ -19,20 +19,26 @@
## 📑 Table of Contents
-- [🗺 Roadmap](#-roadmap)
-- [🌟 Why UltimateAuth](#-why-ultimateauth)
-- [🚀 Quick Start](#-quick-start)
-- [💡 Usage](#-usage)
-- [📘 Documentation](#-documentation)
-- [🤝 Contributing](#-contributing)
-- [⭐ Acknowledgements](#-acknowledgements)
+## Table of Contents
+
+
+## Table of Contents
+
+- [Roadmap](#roadmap)
+- [Why UltimateAuth](#why-ultimateauth)
+- [Quick Start](#quick-start)
+- [Usage](#usage)
+- [Documentation](#documentation)
+- [Upgrading & Breaking Changes](#upgrading--breaking-changes)
+- [Community & Contributing](#community--contributing)
+- [Acknowledgements](#acknowledgements)
---
UltimateAuth is an open-source auth framework with platform-level capabilities that unifies secure session, cookie and token based Auth, modern PKCE flows, Blazor/Maui-ready client experiences - eliminating the complexity of traditional Auth systems while providing a clean, lightweight, extensible and developer-first architecture.
---
-## 🗺 Roadmap
+## Roadmap
| Phase | Version | Scope | Status | Release Date |
| ----------------------- | ------------- | ----------------------------------------- | -------------- | ------------ |
@@ -67,7 +73,7 @@ Whether you're using UltimateAuth, exploring the project, or interested in contr
---
-## 🌟 Why UltimateAuth
+## Why UltimateAuth
The Six-Point Principles
### 1) Unified Authentication System
@@ -124,7 +130,7 @@ Traditional auth solutions struggle here — UltimateAuth embraces it.
---
-# 🚀 Quick Start
+# Quick Start
> ⏱ Get started in minutes
>
> **This Quick Start uses a Blazor Server application with in-memory persistence.**
@@ -251,7 +257,7 @@ For a **complete, step-by-step setup with all required configuration, components
---
-## 💡 Usage
+## Usage
**One Client. Your Auth Application API.**
@@ -324,7 +330,7 @@ Start with the simple API. Drop down to UltimateAuth's extensibility points when
---
-## 📘 Documentation
+## Documentation
Two documentation experiences are provided:
@@ -336,7 +342,19 @@ Create accounts, simulate devices, test auth flows, and observe UltimateAuth in
---
-## 🤝 Community & Contributing
+## Upgrading & Breaking Changes
+
+UltimateAuth aims to keep upgrades straightforward. When a release introduces breaking changes, we provide concise migration guides explaining what needs to be updated.
+
+**Upgrading from an earlier version?**
+
+Check the [Migration Guides](https://ultimateauth.com/docs/migration/index) for version-specific instructions.
+
+For new features and improvements, see the [GitHub Releases](https://github.com/CodeBeamOrg/UltimateAuth/releases).
+
+---
+
+## Community & Contributing
UltimateAuth is built by developers, for developers — and everyone is welcome to be part of its journey.
@@ -354,7 +372,7 @@ Every great open-source project starts with people willing to build something to
---
-## ⭐ Acknowledgements
+## Acknowledgements
UltimateAuth is built with love by CodeBeam and shaped by real-world .NET development —
for teams who want authentication to be secure, predictable, extensible, and a joy to use.
diff --git a/docs/content/_groups.json b/docs/content/_groups.json
index e702badb..d13c0b2e 100644
--- a/docs/content/_groups.json
+++ b/docs/content/_groups.json
@@ -6,5 +6,7 @@
"plugin-domains": 5,
"client": 6,
"configuration": 7,
- "security": 8
+ "security": 8,
+ "how-to-guides": 9,
+ "migration": 10
}
\ No newline at end of file
diff --git a/docs/content/how-to-guides/index.md b/docs/content/how-to-guides/index.md
new file mode 100644
index 00000000..2737c6dc
--- /dev/null
+++ b/docs/content/how-to-guides/index.md
@@ -0,0 +1,13 @@
+---
+title: How-to Guides
+order: 1
+group: how-to-guides
+---
+
+# How-to Guides
+
+Practical, task-oriented guides for building applications with UltimateAuth.
+
+## Available Guides
+
+- [Protect a Page](/docs/how-to-guides/protect-a-page) — Secure Blazor pages and UI sections using UltimateAuth and ASP.NET Core authorization.
diff --git a/docs/content/how-to-guides/protect-a-page.md b/docs/content/how-to-guides/protect-a-page.md
new file mode 100644
index 00000000..3dedd021
--- /dev/null
+++ b/docs/content/how-to-guides/protect-a-page.md
@@ -0,0 +1,850 @@
+---
+title: Protect a Page
+order: 2
+group: how-to-guides
+---
+
+# Protect a Page
+
+Learn how to protect Blazor pages and UI sections using UltimateAuth and ASP.NET Core authorization.
+
+UltimateAuth provides declarative authorization for routed Blazor pages through `[UAuthAuthorize]`, conditional rendering through `UAuthStateView`, and interoperability with ASP.NET Core's `[Authorize]` attribute.
+
+In this guide, you'll learn how to:
+
+- Require authentication before a page can be accessed.
+- Restrict access using roles and permissions.
+- Combine authorization requirements with different match modes.
+- Require an active session.
+- Protect individual UI sections.
+- Use ASP.NET Core authorization alongside UltimateAuth.
+- Configure authorization with built-in and custom routers.
+- Understand the role of `UAuthApp` and `UAuthComponentBase`.
+
+> **Security:** Blazor authorization controls which UI components are rendered. Protected API endpoints, data, and server operations must enforce authorization independently on the server. Client-side authorization must never be the only security boundary.
+
+## Prerequisites
+
+You should have a working UltimateAuth Blazor application with authentication configured.
+
+If you haven't created one yet, start with the [QuickStart](/docs/getting-started/quickstart).
+
+The examples in this guide use:
+
+```razor
+@using CodeBeam.UltimateAuth.Client
+@using CodeBeam.UltimateAuth.Client.Blazor
+@using CodeBeam.UltimateAuth.Core.Contracts
+@using Microsoft.AspNetCore.Authorization
+```
+
+You can add these namespaces to your application's `_Imports.razor` file to make them available across components.
+
+## 1. Protect a Page with UAuthAuthorize
+
+The simplest way to protect a routed Blazor page is to add the `[UAuthAuthorize]` attribute.
+
+Create `Pages/Dashboard.razor`:
+
+```razor
+@page "/dashboard"
+@attribute [UAuthAuthorize]
+
+
Dashboard
+
+
You are authenticated.
+```
+
+That's it.
+
+When a user navigates to `/dashboard`, UltimateAuth evaluates the page's authorization requirements before rendering the page component.
+
+- **Authenticated user with an acceptable session state:** The page can be rendered.
+- **Anonymous user:** Authorization is denied.
+- **Inactive session:** Authorization is denied when an inactive session state is available and `RequireActive` is enabled.
+
+By default, `[UAuthAuthorize]` requires an authenticated user and an active session where session-state information is present.
+
+No explicit role or permission is required.
+
+### Does the page need to inherit from UAuthComponentBase?
+
+**No.**
+
+The page above works without inheriting from any UltimateAuth base class.
+
+Authorization is enforced by `UAuthAuthorizeRouteView`, not by the page's base class.
+
+This also means an unauthorized routed page is not instantiated by UltimateAuth's route view.
+
+## 2. Require a Role
+
+Use the `Roles` property to restrict access to users with a specific role.
+
+```razor
+@page "/admin"
+@attribute [UAuthAuthorize(Roles = "Admin")]
+
+
Administration
+
+
Only administrators can access this page.
+```
+
+The user must be authenticated and have the `Admin` role.
+
+You can also declare multiple roles:
+
+```razor
+@page "/management"
+@attribute [UAuthAuthorize(Roles = "Admin,Manager")]
+
+
Management
+```
+
+With the default `Category` match mode, having **either `Admin` or `Manager`** is sufficient, provided the other configured authorization categories also succeed.
+
+Role names must correspond to the roles recognized by UltimateAuth's authentication state.
+
+## 3. Require a Permission
+
+For more granular authorization, use `Permissions`.
+
+```razor
+@page "/users"
+@attribute [UAuthAuthorize(Permissions = "users.read.self")]
+
+
Users
+
+
You have permission to view users.
+```
+
+UltimateAuth checks the requested permission against the current `UAuthState`.
+
+You can declare multiple permissions:
+
+```razor
+@page "/reports"
+@attribute [UAuthAuthorize(Permissions = "reports.read.self,reports.manage.admin")]
+
+
Reports
+```
+
+By default, the user needs at least one of these permissions.
+
+Permission strings must match the permissions represented in the authenticated user's UltimateAuth state.
+
+> **Tip:** Prefer permissions for operations such as reading reports, managing users, or editing records. Roles are useful for broader organizational responsibilities, while permissions can express specific capabilities.
+
+## 4. Combine Roles and Permissions
+
+You can specify both `Roles` and `Permissions`.
+
+```razor
+@page "/administration/users"
+@attribute [UAuthAuthorize(Roles = "Admin", Permissions = "users.manage.admin")]
+
+
User Management
+```
+
+With the default `MatchMode = Category`, the user must satisfy:
+
+**Admin role AND users.manage permission**
+
+This is because `Category` requires at least one match from each configured category.
+
+If multiple roles and permissions are provided:
+
+```razor
+@page "/management/users"
+@attribute [UAuthAuthorize(Roles = "Admin,Manager", Permissions = "users.read.self,users.manage.admin")]
+```
+
+The requirement becomes:
+
+**(Admin OR Manager) AND (users.read.self OR users.manage.admin)**
+
+This is the default authorization behavior.
+
+## 5. Understand Match Modes
+
+UltimateAuth supports three authorization matching modes:
+
+| Match Mode | Behavior |
+|---|---|
+| `Category` | At least one matching value in each configured category |
+| `Any` | At least one configured role or permission must match |
+| `All` | Every configured role and permission must match |
+
+The default is `AuthorizationMatchMode.Category`.
+
+### Category — the default
+
+```razor
+@page "/category-example"
+@attribute [UAuthAuthorize(Roles = "Admin,Manager", Permissions = "reports.read,reports.write", MatchMode = AuthorizationMatchMode.Category)]
+```
+
+The user must have:
+
+- `Admin` **or** `Manager`.
+- `reports.read` **or** `reports.write`.
+
+Both configured categories must succeed.
+
+Use `Category` when roles and permissions represent independent requirements but alternatives within each category are acceptable.
+
+### Any — one match is enough
+
+```razor
+@page "/any-example"
+@attribute [UAuthAuthorize(Roles = "Admin,Auditor", Permissions = "reports.read.admin", MatchMode = AuthorizationMatchMode.Any)]
+```
+
+The user needs at least one of:
+
+- `Admin` role.
+- `Auditor` role.
+- `reports.read.admin` permission.
+
+This is useful for pages with several alternative authorization paths.
+
+Be careful when combining high-privilege roles and lower-privilege permissions with `Any`: a single matching permission grants access.
+
+### All — every value is required
+
+```razor
+@page "/all-example"
+@attribute [UAuthAuthorize(Roles = "Admin,SecurityOfficer", Permissions = "audit.read.self,audit.export.admin", MatchMode = AuthorizationMatchMode.All)]
+```
+
+The user must have:
+
+- `Admin` role.
+- `SecurityOfficer` role.
+- `audit.read.self` permission.
+- `audit.export.admin` permission.
+
+Use `All` when every declared requirement is mandatory.
+
+### Choosing a match mode
+
+| Requirement | Recommended mode |
+|---|---|
+| Any authenticated user | Parameterless attribute |
+| One required role | Default `Category` |
+| Any of several roles | Default `Category` |
+| One role AND one permission | Default `Category` |
+| Role OR permission | `Any` |
+| All listed roles AND permissions | `All` |
+
+If roles and permissions are omitted entirely, an authenticated user satisfies the authorization requirement regardless of match mode, subject to the session-state requirement.
+
+## 6. Require an Active Session
+
+By default, `[UAuthAuthorize]` uses:
+
+```csharp
+RequireActive = true
+```
+
+The default configuration can be written explicitly:
+
+```razor
+@page "/account/settings"
+@attribute [UAuthAuthorize(RequireActive = true)]
+
+
Account Settings
+```
+
+When UltimateAuth has session-state information and the session is not active, authorization returns an inactive result.
+
+If your application needs to allow an authenticated user regardless of a reported non-active session state, you can disable this requirement:
+
+```razor
+@page "/session-information"
+@attribute [UAuthAuthorize(RequireActive = false)]
+
+
Session Information
+```
+
+This changes only the session-state condition. Authentication is still required.
+
+> **Important:** `RequireActive` evaluates the session state currently available to the Blazor client. It does not independently validate a session against the server for every render. Server-side session validation and revocation enforcement remain necessary.
+
+When no session-state value is available, the default evaluator does not reject the user solely because that value is absent.
+
+## 7. Protect Part of a Page with UAuthStateView
+
+Sometimes you want the page to remain publicly accessible while protecting only a specific section.
+
+Use `UAuthStateView` for conditional rendering.
+
+```razor
+@page "/products"
+
+
Products
+
+
Everyone can view this page.
+
+
+
+
+
+
+
Administrative tools are unavailable.
+
+
+```
+
+The page itself remains accessible to everyone.
+
+However, the administrative section is only rendered for an authorized user.
+
+`UAuthStateView` uses the same `IUAuthAuthorizationEvaluator` as `UAuthAuthorizeRouteView`, so matching roles, permissions, and match modes have consistent semantics.
+
+### Basic authentication-only section
+
+```razor
+
+
+
Welcome back!
+
+
+
Sign in to access your account features.
+
+
+```
+
+As with parameterless `[UAuthAuthorize]`, authentication is required, along with an acceptable session state when `RequireActive` is true.
+
+### Protect a section with permissions
+
+```razor
+
+
+
+
+
+
You cannot refund orders.
+
+
+```
+
+### Combine requirements in a section
+
+```razor
+
+
+
Order management tools are available.
+
+
+
Access denied.
+
+
+```
+
+This uses the same `Category` semantics as the routed page attribute.
+
+### Access the current authentication state
+
+The `Authorized` fragment receives the current `UAuthState` as its context.
+
+```razor
+
+
+
Hello, @state.Identity?.DisplayName!
+
+
+
Please sign in.
+
+
+```
+
+This allows authorized content to access identity information without requiring a custom base class.
+
+## 8. Handle Unauthorized, Inactive, and Authorizing States
+
+`UAuthStateView` supports multiple rendering states.
+
+```razor
+
+
+
Administrator access granted.
+
+
+
+
You do not have permission to access this section.
+
+
+
+
Your session is not active.
+
+
+
+
Checking your permissions...
+
+
+```
+
+| Fragment | When displayed |
+|---|---|
+| `Authorized` | Authorization succeeds |
+| `NotAuthorized` | Authorization is denied |
+| `Inactive` | A non-active session is detected and `RequireActive` is true |
+| `Authorizing` | Authorization evaluation is in progress |
+
+If `Inactive` is not supplied, the component falls back to the `NotAuthorized` fragment.
+
+If `Authorizing` is not supplied, unauthorized content is used while a new authorization result is pending.
+
+During reevaluation, previously authorized section content is removed before an asynchronous policy evaluation completes. This prevents stale authorized content from remaining visible during that pending evaluation.
+
+## 9. Use an ASP.NET Core Authorization Policy
+
+`UAuthStateView` supports the `Policy` parameter.
+
+First, register a policy using ASP.NET Core authorization:
+
+```csharp
+builder.Services.AddAuthorizationCore(options =>
+{
+ options.AddPolicy("CanViewReports", policy => policy.RequireClaim("reports_access", "granted"));
+});
+```
+
+Then use that policy in a UI section:
+
+```razor
+
+
+
Reports are available.
+
+
+
Reports access is restricted.
+
+
+```
+
+The policy is evaluated through ASP.NET Core's `IAuthorizationService`, using the claims principal produced from the current UltimateAuth state.
+
+You can also combine a policy with roles and permissions:
+
+```razor
+
+
+
All requirements passed.
+
+
+```
+
+For `All`, every configured requirement must succeed.
+
+For `Any`, the policy is another possible successful condition.
+
+For `Category`, the policy must succeed alongside the configured role and permission categories.
+
+> **Current API distinction:** `[UAuthAuthorize]` currently exposes `Roles`, `Permissions`, `MatchMode`, and `RequireActive`, but not `Policy`. Use `UAuthStateView` for policy-based section rendering, or ASP.NET Core `[Authorize(Policy = "...")]` for policy-protected routed pages.
+
+## 10. Protect a Page with ASP.NET Core Authorize
+
+UltimateAuth integrates with ASP.NET Core authorization.
+
+You can use the standard `[Authorize]` attribute on routed Blazor pages.
+
+```razor
+@page "/account"
+@attribute [Authorize]
+
+
+```
+
+These checks are performed through ASP.NET Core's `AuthorizeRouteView` and its authentication and authorization infrastructure.
+
+UltimateAuth provides a Blazor `AuthenticationStateProvider` that integrates UltimateAuth authentication state with ASP.NET Core.
+
+### Which attribute should I use?
+
+| Feature | `[UAuthAuthorize]` | `[Authorize]` |
+|---|---|---|
+| Requires authentication | Yes | Yes |
+| Roles | Yes | Yes |
+| UltimateAuth permissions | Yes | Via separately configured ASP.NET Core policies or handlers |
+| `AuthorizationMatchMode` | Yes | No direct equivalent property |
+| `RequireActive` | Yes | No direct equivalent property |
+| Named ASP.NET Core policy | Not currently | Yes |
+| Routed Blazor page | Yes | Yes |
+
+Use `[UAuthAuthorize]` when working directly with UltimateAuth roles, permissions, and session-aware requirements.
+
+Use `[Authorize]` when relying on ASP.NET Core authorization policies, requirements, or existing authorization infrastructure.
+
+### Combine both attributes
+
+You can declare both on the same routed page:
+
+```razor
+@page "/secure-reports"
+
+@attribute [UAuthAuthorize(Permissions = "reports.read")]
+@attribute [Authorize(Roles = "Admin")]
+
+
Secure Reports
+```
+
+The page is rendered only when **both authorization systems allow access**.
+
+UltimateAuth evaluates `[UAuthAuthorize]`, and the underlying ASP.NET Core `AuthorizeRouteView` evaluates `[Authorize]`.
+
+The requirements are effectively combined using AND semantics across the two mechanisms.
+
+> **Note:** ASP.NET Core `[Authorize]` uses the configured ASP.NET Core authentication state. `[UAuthAuthorize]` uses `UAuthState`. UltimateAuth integrates these models, but custom authentication providers must keep their states consistent.
+
+## 11. How UAuthApp Protects Routes
+
+`UAuthApp` is the root Blazor integration component for UltimateAuth.
+
+It provides:
+
+- Client runtime initialization.
+- The current `UAuthState` as a cascading parameter.
+- ASP.NET Core cascading authentication state.
+- Session lifecycle coordination.
+- Runtime initialization readiness.
+- Optional built-in routing.
+
+### Built-in router
+
+If you use:
+
+```razor
+
+```
+
+UltimateAuth automatically configures its router to use `UAuthAuthorizeRouteView`.
+
+You do not need to add a separate `AuthorizeRouteView` or `UAuthAuthorizeRouteView`.
+
+The built-in router supports both `[UAuthAuthorize]` and ASP.NET Core `[Authorize]`.
+
+It also supports an application-level `NotAuthorized` fragment:
+
+```razor
+
+
+
Access Denied
+
You are not authorized to access this page.
+
+
+```
+
+This fragment is displayed when route authorization fails.
+
+### Runtime initialization
+
+`UAuthApp` initializes the client authentication state before allowing UltimateAuth-protected routes to be rendered.
+
+This is important because authentication state may not be immediately available when a Blazor application first starts, particularly when restoring a session.
+
+During initialization or asynchronous authorization evaluation, `UAuthAuthorizeRouteView` can display an `Authorizing` fragment.
+
+If one is not supplied, the protected route content remains unrendered while authorization is pending.
+
+### Manual and Reactive render modes
+
+`UAuthApp` supports `UAuthRenderMode.Manual` and `UAuthRenderMode.Reactive`.
+
+These control how UltimateAuth state changes affect general component rendering.
+
+Route authorization itself subscribes to relevant authentication state changes, and `UAuthStateView` also reacts to such changes.
+
+You do not need to enable reactive rendering merely to make `[UAuthAuthorize]` work.
+
+## 12. Protect Pages with a Custom Router
+
+If your application uses its own Blazor `Router`, set `UseBuiltInRouter="false"` on `UAuthApp`.
+
+Then use `UAuthAuthorizeRouteView` inside the router's `Found` fragment.
+
+```razor
+
+
+
+
+
+
+
Access Denied
+
You cannot access this page.
+
+
+
+
Checking access...
+
+
+
+
+
+
+
+
+```
+
+`UAuthAuthorizeRouteView` wraps ASP.NET Core's `AuthorizeRouteView` internally.
+
+This means it supports both authorization systems, while checking UltimateAuth-specific requirements before the protected page component is instantiated.
+
+**Do not replace it with a plain `RouteView` or `AuthorizeRouteView` when your routed pages depend on `[UAuthAuthorize]`.**
+
+A plain ASP.NET Core `AuthorizeRouteView` does not evaluate the UltimateAuth-specific attribute by itself.
+
+If your custom router uses additional route assemblies, pass the appropriate `AdditionalAssemblies` to the `Router` as needed.
+
+## 13. Do I Need UAuthComponentBase?
+
+**Not for authorization.**
+
+Consider this page:
+
+```razor
+@page "/settings"
+@attribute [UAuthAuthorize]
+
+
Settings
+```
+
+It is protected when routed through `UAuthAuthorizeRouteView`, even though it doesn't inherit from `UAuthComponentBase`.
+
+You can still use `UAuthComponentBase` when you need access to the UltimateAuth state lifecycle.
+
+```razor
+@page "/profile"
+@attribute [UAuthAuthorize]
+@inherits UAuthComponentBase
+
+
Profile
+
+
User: @AuthState.Identity?.DisplayName
+
+@code {
+ protected override Task HandleAuthStateChangedAsync(
+ UAuthStateChangeReason reason)
+ {
+ // React to authentication state changes.
+ return Task.CompletedTask;
+ }
+}
+```
+
+`UAuthComponentBase` provides:
+
+- Access to cascading `UAuthState`.
+- Authentication state change notifications.
+- Automatic rerendering when the state changes, by default.
+- An asynchronous lifecycle hook.
+- Event subscription cleanup on disposal.
+
+However, it no longer performs page authorization itself.
+
+### Can I use UAuthAuthorize on a regular child component?
+
+The attribute only declares metadata. It does not enforce authorization on its own.
+
+For example:
+
+```razor
+@attribute [UAuthAuthorize(Roles = "Admin")]
+
+
Administrative tools
+```
+
+If this is an ordinary child component rendered directly inside another page, `[UAuthAuthorize]` is not automatically evaluated by `UAuthAuthorizeRouteView`.
+
+Route authorization is performed for routed page components.
+
+For conditional content inside a page, use `UAuthStateView` instead.
+
+## 14. Advanced: Customize Authorization Evaluation
+
+UltimateAuth uses the `IUAuthAuthorizationEvaluator` service for Blazor authorization.
+
+The default evaluator is registered by:
+
+```csharp
+builder.Services.AddUltimateAuthClientBlazor();
+```
+
+It evaluates:
+
+- Authentication status.
+- Session state when required.
+- Roles.
+- Permissions.
+- ASP.NET Core policies supplied through authorization requirements.
+- The configured match mode.
+
+The evaluator is registered with `TryAddScoped`, allowing applications to provide their own implementation through dependency injection.
+
+If you need custom application-specific authorization behavior, you can implement `IUAuthAuthorizationEvaluator`.
+
+A replacement evaluator receives the current `UAuthState` and a `UAuthAuthorizationRequirement` and returns a `UAuthAuthorizationResult`.
+
+A custom implementation should preserve secure defaults, especially for anonymous users, inactive sessions, and failed authorization checks.
+
+Keep authorization evaluation separate from component rendering and navigation logic.
+
+## 15. Important Security Considerations
+
+### Blazor UI authorization is not API authorization
+
+An unauthorized user should not see or instantiate a protected routed page. However, hiding UI does not secure the HTTP endpoint or underlying data source.
+
+For example:
+
+```razor
+@page "/users"
+@attribute [UAuthAuthorize(Roles = "Admin")]
+```
+
+This protects the Blazor page through UltimateAuth's router.
+
+It does **not** automatically protect an unrelated API endpoint such as:
+
+```text
+GET /api/users
+```
+
+That endpoint must independently validate the caller and enforce the required authorization.
+
+For Blazor Server, the same principle applies to sensitive server-side operations, even when they are invoked without an HTTP call from the component.
+
+### UAuthAuthorize is currently a Blazor attribute
+
+The current `[UAuthAuthorize]` attribute is interpreted by UltimateAuth's Blazor authorization pipeline.
+
+It does not, by itself, secure ASP.NET Core controllers or Minimal API endpoints.
+
+Use the server-side authorization mechanisms appropriate for those endpoints.
+
+### Revocation and role changes
+
+`UAuthAuthorizeRouteView` and `UAuthStateView` respond to authentication state changes.
+
+When the available `UAuthState` changes, authorization can be reevaluated.
+
+However, a remote role change or server-side session revocation is not necessarily observed immediately by the Blazor client.
+
+Server-side authorization must remain authoritative, even while a client retains stale state.
+
+### Authorization during navigation
+
+A protected routed page is not instantiated until UltimateAuth authorization succeeds.
+
+When authorization becomes invalid, the route view stops rendering the protected page.
+
+This is different from implementing a redirect inside the page's `OnInitialized` or `OnAfterRender` method, where the component may already have been instantiated.
+
+### Do not rely on hidden controls for security
+
+`UAuthStateView` is useful for showing or hiding buttons, navigation entries, and sections.
+
+Always authorize the underlying operation independently.
+
+For example, hiding a `Delete User` button does not remove the need to authorize the actual delete request.
+
+## 16. Troubleshooting
+
+### UAuthAuthorize does not prevent access
+
+First, make sure you're using **UltimateAuth v0.1.1 or later**.
+
+Earlier versions relied on `UAuthComponentBase` for authorization checks. Starting with v0.1.1, `[UAuthAuthorize]` is enforced at the routing level through `UAuthAuthorizeRouteView`.
+
+If authorization is not working as expected:
+
+1. Verify that `CodeBeam.UltimateAuth.Client.Blazor` is version `0.1.1` or later.
+2. If you're using the built-in router, make sure `UseBuiltInRouter="true"` is configured on `UAuthApp`.
+3. If you're using a custom router, replace `RouteView` or `AuthorizeRouteView` with `UAuthAuthorizeRouteView`.
+4. Make sure the page is routed within the `UAuthApp` context.
+5. Confirm that the user meets the authentication, role, permission, and session-state requirements.
+
+**Upgrading from v0.1.0?** See [Migrating to v0.1.1](/docs/migration/v0.1.1) for the required changes.
+
+### The protected page appears blank during startup
+
+UltimateAuth may still be initializing or evaluating authorization.
+
+With a custom router, provide an `Authorizing` fragment for a loading indicator.
+
+### UAuthStateView reports a missing cascading UAuthState
+
+Make sure the component is rendered inside `UAuthApp`, or another host that correctly provides the required cascading UltimateAuth state.
+
+### ASP.NET Core authorization reports a missing AuthenticationState
+
+Make sure ASP.NET Core's authentication state infrastructure is available.
+
+`UAuthApp` provides a `CascadingAuthenticationState` within its child content.
+
+If you create a custom host outside `UAuthApp`, you must provide the appropriate ASP.NET Core cascading authentication state yourself.
+
+### Roles or permissions are unexpectedly denied
+
+Confirm that:
+
+- The user is authenticated.
+- The state contains the expected role or permission.
+- The correct match mode is selected.
+- The user's session state satisfies `RequireActive`.
+- The client state has been updated after any server-side changes.
+
+### I need a policy directly on a routed page
+
+Use ASP.NET Core's `[Authorize(Policy = "...")]` attribute.
+
+The current `[UAuthAuthorize]` attribute does not expose a `Policy` property.
+
+## Summary
+
+| Scenario | Recommended approach |
+|---|---|
+| Protect an entire Blazor page | `[UAuthAuthorize]` |
+| Require an UltimateAuth role | `[UAuthAuthorize(Roles = "...")]` |
+| Require an UltimateAuth permission | `[UAuthAuthorize(Permissions = "...")]` |
+| Combine roles and permissions | `MatchMode` |
+| Require ASP.NET Core policy authorization | `[Authorize(Policy = "...")]` |
+| Combine ASP.NET Core and UltimateAuth | Use both attributes |
+| Protect an individual UI section | `UAuthStateView` |
+| Use built-in routing | `UAuthApp UseBuiltInRouter="true"` |
+| Use custom routing | `UAuthAuthorizeRouteView` |
+| React to authentication lifecycle changes | `UAuthComponentBase` |
+| Protect an API or server operation | Enforce authorization on the server |
+
+UltimateAuth's Blazor authorization model allows you to declare requirements at the page level, conditionally render protected sections, and integrate with ASP.NET Core authorization without coupling page protection to a specific base class.
+
+## Next Steps
+
+- [QuickStart](/docs/getting-started/quickstart) — Create a working UltimateAuth application.
+- [Authentication Model](/docs/fundamentals/auth-model) — Understand UltimateAuth authentication concepts.
+- [Migration to v0.1.1](/docs/migration/v0.1.1) — Update custom routers and existing Blazor authorization code.
diff --git a/docs/content/migration/index.md b/docs/content/migration/index.md
new file mode 100644
index 00000000..0cd8f9d0
--- /dev/null
+++ b/docs/content/migration/index.md
@@ -0,0 +1,15 @@
+---
+title: Migration Guides
+order: 1
+group: migration
+---
+
+# Migration Guides
+
+Version-specific instructions for upgrading UltimateAuth applications.
+
+Migration guides focus on breaking changes, behavior changes, and required application updates.
+
+## Available Guides
+
+- [Migrating to v0.1.1](/docs/migration/v0.1.1) — Blazor route authorization and component lifecycle changes.
diff --git a/docs/content/migration/v0.1.1.md b/docs/content/migration/v0.1.1.md
new file mode 100644
index 00000000..f53a3250
--- /dev/null
+++ b/docs/content/migration/v0.1.1.md
@@ -0,0 +1,76 @@
+---
+title: Migrating to v0.1.1
+order: 2
+group: migration
+---
+
+# Migrating to v0.1.1
+
+UltimateAuth v0.1.1 improves Blazor page authorization by moving `[UAuthAuthorize]` enforcement to the routing layer.
+
+**Most applications require no changes.** If you're using the built-in `UAuthApp` router, authorization works automatically.
+
+Only the following cases require attention.
+
+## 1. Custom Routers
+
+If you use a custom Blazor router, replace `AuthorizeRouteView` with `UAuthAuthorizeRouteView`.
+
+**Before:**
+
+```razor
+
+```
+
+**After:**
+
+```razor
+
+```
+
+This enables `[UAuthAuthorize]` enforcement while preserving ASP.NET Core `[Authorize]` support.
+
+Make sure your custom router is rendered inside `UAuthApp`.
+
+## 2. UAuthComponentBase Overrides
+
+`UAuthComponentBase` no longer handles authorization or automatic redirects.
+
+If you previously overrode `OnUnauthorized()` or `OnForbidden()`, replace that behavior with the `NotAuthorized` fragment on `UAuthApp` (built-in router) or `UAuthAuthorizeRouteView` (custom router).
+
+The authentication state change hook is now asynchronous.
+
+**Before:**
+
+```csharp
+protected override void HandleAuthStateChanged(UAuthStateChangeReason reason)
+{
+}
+```
+
+**After:**
+
+```csharp
+protected override Task HandleAuthStateChangedAsync(UAuthStateChangeReason reason)
+{
+ return Task.CompletedTask;
+}
+```
+
+Pages no longer need to inherit from `UAuthComponentBase` to use `[UAuthAuthorize]`.
+
+## 3. Session Requirement
+
+`[UAuthAuthorize]` now defaults to `RequireActive = true`.
+
+If your application intentionally allows authenticated users with a reported inactive session state, explicitly use:
+
+```razor
+@attribute [UAuthAuthorize(RequireActive = false)]
+```
+
+Otherwise, no change is needed.
+
+---
+
+For usage examples, see [Protect a Page](/docs/how-to-guides/protect-a-page).
diff --git a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/DocsContent.razor b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/DocsContent.razor
index 9650497f..d1c9fcfe 100644
--- a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/DocsContent.razor
+++ b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/DocsContent.razor
@@ -8,7 +8,7 @@
@if (_notFound)
{
-
+
Page not found
@@ -26,7 +26,7 @@
}
else if (_doc is not null)
{
-
+ @_doc.Title
diff --git a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/DocsLandingPage.razor b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/DocsLandingPage.razor
index 62ec35e3..79b76a4c 100644
--- a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/DocsLandingPage.razor
+++ b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/Pages/DocsLandingPage.razor
@@ -3,171 +3,173 @@
-
+
-
- UltimateAuth Docs
- The modern way to understand authentication — unified, simple and powerful.
+
+
+
+ ULTIMATEAUTH DOCUMENTATION
+
+
+
+ Authentication, unified.
+
-
- Learn the architecture, flows, client APIs, security model, and integration patterns of UltimateAuth:
+
+ Everything you need to build, integrate, and understand authentication with UltimateAuth.
+
-
-
- Start Here
-
+
+
+
+ New to UltimateAuth? Start here.
+
+
- If you are new to UltimateAuth, start with Getting Started and
- Fundamentals. If you care about usage, continue with Client & API.
- If you are evaluating architecture or enterprise adoption,
- continue with Auth Flows, Security, and Plugin Domains.
+ Build your first working authentication application with a guided Quick Start.
+ Get familiar with the framework before exploring its architecture.
+
+
+
+ Start Quick Start
+
+
+
+ Getting Started Guide
+
+
+
-
-
- Getting Started
+
+
+
+
+
+ Build & Integrate
+
- Set up UltimateAuth quickly, understand the first login flow,
- and move into real-world application setup.
+ Set up UltimateAuth for Blazor Server,
+ WebAssembly, Resource APIs, and real-world
+ application architectures.
-
- Open Getting Started
+
+ Explore Setup Guides
-
-
- Fundamentals
+
+
+
+ Understand the Architecture
- Understand the authentication model, flow-based execution,
- auth modes, client profiles, and runtime architecture.
+ Learn the unified authentication model, flows, authentication modes, client profiles,
+ and runtime behavior.
-
- Open Fundamentals
+
+ Explore Fundamentals
+
-
-
-
- Auth Flows
+
+
+ Explore by Topic
+
+
+ Looking for something specific? Go directly to the documentation section you need.
+
+
+
+
+
+
+
+ Authentication Flows
+
- Explore login, refresh, logout, session lifecycle,
- token behavior, and device-aware authentication flows.
+ Login, refresh, logout, and session lifecycle.
-
-
- Open Auth Flows
-
+
+ Explore Auth Flows →
+
-
-
-
- Client & API
-
+
+
+
+
+ Client & API
+
- Explore the usage, the service client layer of UltimateAuth.
- Everything from basic login/logout to advanced session management should call with client.
+ Client APIs, integration, and application usage.
-
-
- Open Client & API
-
+
+ Explore Client APIs →
+
-
-
-
- Plugin Domains
-
+
+
+
+
+ Plugin Domains
+
- Explore the user, credential, and authorization modules that not required for core Auth, but essential.
+ Users, credentials, authorization, and policies.
-
-
- Open Plugin Domains
-
+
+ Explore Plugin Domains →
+
-
-
-
-
+
+
+
+
Security
-
- Review the session security model, token behavior,
- refresh rotation, and the policy pipeline.
+ Session security, token protection, refresh rotation, and security policies.
-
-
- Open Security Docs
-
+
+ Explore Security →
+
-
-
-
- Coming Next
-
-
-
- The documentation experience will continue to expand with richer navigation,
- improved code rendering, and dedicated reference surfaces.
-
-
-
- API Reference
- Interactive authentication sandbox
- Sample-driven guides
- Integration recipes for Blazor, WASM, MAUI, MVC, and APIs
-
-
-
-
-
-
- Browse Documentation
-
-
-
- View Markdown Source
+
+
+ View Documentation Source
diff --git a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/docs-index.json b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/docs-index.json
index 12c6baeb..a326d4da 100644
--- a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/docs-index.json
+++ b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/docs-index.json
@@ -257,5 +257,33 @@
"Order": 4,
"Group": "security",
"GroupOrder": 8
+ },
+ {
+ "Title": "How-to Guides",
+ "Slug": "how-to-guides/index",
+ "Order": 1,
+ "Group": "how-to-guides",
+ "GroupOrder": 9
+ },
+ {
+ "Title": "Protect a Page",
+ "Slug": "how-to-guides/protect-a-page",
+ "Order": 2,
+ "Group": "how-to-guides",
+ "GroupOrder": 9
+ },
+ {
+ "Title": "Migration Guides",
+ "Slug": "migration/index",
+ "Order": 1,
+ "Group": "migration",
+ "GroupOrder": 10
+ },
+ {
+ "Title": "Migrating to v0.1.1",
+ "Slug": "migration/v0.1.1",
+ "Order": 2,
+ "Group": "migration",
+ "GroupOrder": 10
}
]
\ No newline at end of file
diff --git a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/how-to-guides/index.json b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/how-to-guides/index.json
new file mode 100644
index 00000000..faf0a0c4
--- /dev/null
+++ b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/how-to-guides/index.json
@@ -0,0 +1,14 @@
+{
+ "Slug": "how-to-guides/index",
+ "Title": "How-to Guides",
+ "Html": "\n\u003Cp\u003EPractical, task-oriented guides for building applications with UltimateAuth.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022available-guides\u0022\u003EAvailable Guides\u003C/h2\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ca href=\u0022/docs/how-to-guides/protect-a-page\u0022\u003EProtect a Page\u003C/a\u003E \u2014 Secure Blazor pages and UI sections using UltimateAuth and ASP.NET Core authorization.\u003C/li\u003E\n\u003C/ul\u003E\n",
+ "Headings": [
+ {
+ "Id": "available-guides",
+ "Text": "Available Guides",
+ "Level": 0
+ }
+ ],
+ "SourceHash": "D45E8C30B26AF54F802D9926DA15D933AA6342A064BE1D54F90087F8F64A49AA",
+ "BuilderVersion": "1"
+}
\ No newline at end of file
diff --git a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/how-to-guides/protect-a-page.json b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/how-to-guides/protect-a-page.json
new file mode 100644
index 00000000..2079660f
--- /dev/null
+++ b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/how-to-guides/protect-a-page.json
@@ -0,0 +1,234 @@
+{
+ "Slug": "how-to-guides/protect-a-page",
+ "Title": "Protect a Page",
+ "Html": "\n\u003Cp\u003ELearn how to protect Blazor pages and UI sections using UltimateAuth and ASP.NET Core authorization.\u003C/p\u003E\n\u003Cp\u003EUltimateAuth provides declarative authorization for routed Blazor pages through \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E, conditional rendering through \u003Ccode\u003EUAuthStateView\u003C/code\u003E, and interoperability with ASP.NET Core\u0027s \u003Ccode\u003E[Authorize]\u003C/code\u003E attribute.\u003C/p\u003E\n\u003Cp\u003EIn this guide, you\u0027ll learn how to:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003ERequire authentication before a page can be accessed.\u003C/li\u003E\n\u003Cli\u003ERestrict access using roles and permissions.\u003C/li\u003E\n\u003Cli\u003ECombine authorization requirements with different match modes.\u003C/li\u003E\n\u003Cli\u003ERequire an active session.\u003C/li\u003E\n\u003Cli\u003EProtect individual UI sections.\u003C/li\u003E\n\u003Cli\u003EUse ASP.NET Core authorization alongside UltimateAuth.\u003C/li\u003E\n\u003Cli\u003EConfigure authorization with built-in and custom routers.\u003C/li\u003E\n\u003Cli\u003EUnderstand the role of \u003Ccode\u003EUAuthApp\u003C/code\u003E and \u003Ccode\u003EUAuthComponentBase\u003C/code\u003E.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cblockquote\u003E\n\u003Cp\u003E\u003Cstrong\u003ESecurity:\u003C/strong\u003E Blazor authorization controls which UI components are rendered. Protected API endpoints, data, and server operations must enforce authorization independently on the server. Client-side authorization must never be the only security boundary.\u003C/p\u003E\n\u003C/blockquote\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022prerequisites\u0022\u003EPrerequisites\u003C/h2\u003E\n\u003Cp\u003EYou should have a working UltimateAuth Blazor application with authentication configured.\u003C/p\u003E\n\u003Cp\u003EIf you haven\u0027t created one yet, start with the \u003Ca href=\u0022/docs/getting-started/quickstart\u0022\u003EQuickStart\u003C/a\u003E.\u003C/p\u003E\n\u003Cp\u003EThe examples in this guide use:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@using CodeBeam.UltimateAuth.Client\n@using CodeBeam.UltimateAuth.Client.Blazor\n@using CodeBeam.UltimateAuth.Core.Contracts\n@using Microsoft.AspNetCore.Authorization\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EYou can add these namespaces to your application\u0027s \u003Ccode\u003E_Imports.razor\u003C/code\u003E file to make them available across components.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022protect-a-page-with-uauthauthorize\u0022\u003E1. Protect a Page with UAuthAuthorize\u003C/h2\u003E\n\u003Cp\u003EThe simplest way to protect a routed Blazor page is to add the \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E attribute.\u003C/p\u003E\n\u003Cp\u003ECreate \u003Ccode\u003EPages/Dashboard.razor\u003C/code\u003E:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/dashboard\u0026quot;\n@attribute [UAuthAuthorize]\n\n\u0026lt;h1\u0026gt;Dashboard\u0026lt;/h1\u0026gt;\n\n\u0026lt;p\u0026gt;You are authenticated.\u0026lt;/p\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThat\u0027s it.\u003C/p\u003E\n\u003Cp\u003EWhen a user navigates to \u003Ccode\u003E/dashboard\u003C/code\u003E, UltimateAuth evaluates the page\u0027s authorization requirements before rendering the page component.\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Cstrong\u003EAuthenticated user with an acceptable session state:\u003C/strong\u003E The page can be rendered.\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EAnonymous user:\u003C/strong\u003E Authorization is denied.\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EInactive session:\u003C/strong\u003E Authorization is denied when an inactive session state is available and \u003Ccode\u003ERequireActive\u003C/code\u003E is enabled.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EBy default, \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E requires an authenticated user and an active session where session-state information is present.\u003C/p\u003E\n\u003Cp\u003ENo explicit role or permission is required.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022does-the-page-need-to-inherit-from-uauthcomponentbase\u0022\u003EDoes the page need to inherit from UAuthComponentBase?\u003C/h3\u003E\n\u003Cp\u003E\u003Cstrong\u003ENo.\u003C/strong\u003E\u003C/p\u003E\n\u003Cp\u003EThe page above works without inheriting from any UltimateAuth base class.\u003C/p\u003E\n\u003Cp\u003EAuthorization is enforced by \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E, not by the page\u0027s base class.\u003C/p\u003E\n\u003Cp\u003EThis also means an unauthorized routed page is not instantiated by UltimateAuth\u0027s route view.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022require-a-role\u0022\u003E2. Require a Role\u003C/h2\u003E\n\u003Cp\u003EUse the \u003Ccode\u003ERoles\u003C/code\u003E property to restrict access to users with a specific role.\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/admin\u0026quot;\n@attribute [UAuthAuthorize(Roles = \u0026quot;Admin\u0026quot;)]\n\n\u0026lt;h1\u0026gt;Administration\u0026lt;/h1\u0026gt;\n\n\u0026lt;p\u0026gt;Only administrators can access this page.\u0026lt;/p\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThe user must be authenticated and have the \u003Ccode\u003EAdmin\u003C/code\u003E role.\u003C/p\u003E\n\u003Cp\u003EYou can also declare multiple roles:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/management\u0026quot;\n@attribute [UAuthAuthorize(Roles = \u0026quot;Admin,Manager\u0026quot;)]\n\n\u0026lt;h1\u0026gt;Management\u0026lt;/h1\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EWith the default \u003Ccode\u003ECategory\u003C/code\u003E match mode, having \u003Cstrong\u003Eeither \u003Ccode\u003EAdmin\u003C/code\u003E or \u003Ccode\u003EManager\u003C/code\u003E\u003C/strong\u003E is sufficient, provided the other configured authorization categories also succeed.\u003C/p\u003E\n\u003Cp\u003ERole names must correspond to the roles recognized by UltimateAuth\u0027s authentication state.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022require-a-permission\u0022\u003E3. Require a Permission\u003C/h2\u003E\n\u003Cp\u003EFor more granular authorization, use \u003Ccode\u003EPermissions\u003C/code\u003E.\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/users\u0026quot;\n@attribute [UAuthAuthorize(Permissions = \u0026quot;users.read.self\u0026quot;)]\n\n\u0026lt;h1\u0026gt;Users\u0026lt;/h1\u0026gt;\n\n\u0026lt;p\u0026gt;You have permission to view users.\u0026lt;/p\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EUltimateAuth checks the requested permission against the current \u003Ccode\u003EUAuthState\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EYou can declare multiple permissions:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/reports\u0026quot;\n@attribute [UAuthAuthorize(Permissions = \u0026quot;reports.read.self,reports.manage.admin\u0026quot;)]\n \n\u0026lt;h1\u0026gt;Reports\u0026lt;/h1\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EBy default, the user needs at least one of these permissions.\u003C/p\u003E\n\u003Cp\u003EPermission strings must match the permissions represented in the authenticated user\u0027s UltimateAuth state.\u003C/p\u003E\n\u003Cblockquote\u003E\n\u003Cp\u003E\u003Cstrong\u003ETip:\u003C/strong\u003E Prefer permissions for operations such as reading reports, managing users, or editing records. Roles are useful for broader organizational responsibilities, while permissions can express specific capabilities.\u003C/p\u003E\n\u003C/blockquote\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022combine-roles-and-permissions\u0022\u003E4. Combine Roles and Permissions\u003C/h2\u003E\n\u003Cp\u003EYou can specify both \u003Ccode\u003ERoles\u003C/code\u003E and \u003Ccode\u003EPermissions\u003C/code\u003E.\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/administration/users\u0026quot;\n@attribute [UAuthAuthorize(Roles = \u0026quot;Admin\u0026quot;, Permissions = \u0026quot;users.manage.admin\u0026quot;)]\n\n\u0026lt;h1\u0026gt;User Management\u0026lt;/h1\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EWith the default \u003Ccode\u003EMatchMode = Category\u003C/code\u003E, the user must satisfy:\u003C/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EAdmin role AND users.manage permission\u003C/strong\u003E\u003C/p\u003E\n\u003Cp\u003EThis is because \u003Ccode\u003ECategory\u003C/code\u003E requires at least one match from each configured category.\u003C/p\u003E\n\u003Cp\u003EIf multiple roles and permissions are provided:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/management/users\u0026quot;\n@attribute [UAuthAuthorize(Roles = \u0026quot;Admin,Manager\u0026quot;, Permissions = \u0026quot;users.read.self,users.manage.admin\u0026quot;)]\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThe requirement becomes:\u003C/p\u003E\n\u003Cp\u003E\u003Cstrong\u003E(Admin OR Manager) AND (users.read.self OR users.manage.admin)\u003C/strong\u003E\u003C/p\u003E\n\u003Cp\u003EThis is the default authorization behavior.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022understand-match-modes\u0022\u003E5. Understand Match Modes\u003C/h2\u003E\n\u003Cp\u003EUltimateAuth supports three authorization matching modes:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-table-wrapper\u0022\u003E\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EMatch Mode\u003C/th\u003E\n\u003Cth\u003EBehavior\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003ECategory\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EAt least one matching value in each configured category\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EAny\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EAt least one configured role or permission must match\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EAll\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EEvery configured role and permission must match\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\u003C/div\u003E\n\u003Cp\u003EThe default is \u003Ccode\u003EAuthorizationMatchMode.Category\u003C/code\u003E.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022category-the-default\u0022\u003ECategory \u2014 the default\u003C/h3\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/category-example\u0026quot;\n@attribute [UAuthAuthorize(Roles = \u0026quot;Admin,Manager\u0026quot;, Permissions = \u0026quot;reports.read,reports.write\u0026quot;, MatchMode = AuthorizationMatchMode.Category)]\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThe user must have:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003EAdmin\u003C/code\u003E \u003Cstrong\u003Eor\u003C/strong\u003E \u003Ccode\u003EManager\u003C/code\u003E.\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003Ereports.read\u003C/code\u003E \u003Cstrong\u003Eor\u003C/strong\u003E \u003Ccode\u003Ereports.write\u003C/code\u003E.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EBoth configured categories must succeed.\u003C/p\u003E\n\u003Cp\u003EUse \u003Ccode\u003ECategory\u003C/code\u003E when roles and permissions represent independent requirements but alternatives within each category are acceptable.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022any-one-match-is-enough\u0022\u003EAny \u2014 one match is enough\u003C/h3\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/any-example\u0026quot;\n@attribute [UAuthAuthorize(Roles = \u0026quot;Admin,Auditor\u0026quot;, Permissions = \u0026quot;reports.read.admin\u0026quot;, MatchMode = AuthorizationMatchMode.Any)]\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThe user needs at least one of:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003EAdmin\u003C/code\u003E role.\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003EAuditor\u003C/code\u003E role.\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003Ereports.read.admin\u003C/code\u003E permission.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EThis is useful for pages with several alternative authorization paths.\u003C/p\u003E\n\u003Cp\u003EBe careful when combining high-privilege roles and lower-privilege permissions with \u003Ccode\u003EAny\u003C/code\u003E: a single matching permission grants access.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022all-every-value-is-required\u0022\u003EAll \u2014 every value is required\u003C/h3\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/all-example\u0026quot;\n@attribute [UAuthAuthorize(Roles = \u0026quot;Admin,SecurityOfficer\u0026quot;, Permissions = \u0026quot;audit.read.self,audit.export.admin\u0026quot;, MatchMode = AuthorizationMatchMode.All)]\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThe user must have:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003EAdmin\u003C/code\u003E role.\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003ESecurityOfficer\u003C/code\u003E role.\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003Eaudit.read.self\u003C/code\u003E permission.\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003Eaudit.export.admin\u003C/code\u003E permission.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EUse \u003Ccode\u003EAll\u003C/code\u003E when every declared requirement is mandatory.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022choosing-a-match-mode\u0022\u003EChoosing a match mode\u003C/h3\u003E\n\u003Cdiv class=\u0022docs-table-wrapper\u0022\u003E\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003ERequirement\u003C/th\u003E\n\u003Cth\u003ERecommended mode\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EAny authenticated user\u003C/td\u003E\n\u003Ctd\u003EParameterless attribute\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EOne required role\u003C/td\u003E\n\u003Ctd\u003EDefault \u003Ccode\u003ECategory\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EAny of several roles\u003C/td\u003E\n\u003Ctd\u003EDefault \u003Ccode\u003ECategory\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EOne role AND one permission\u003C/td\u003E\n\u003Ctd\u003EDefault \u003Ccode\u003ECategory\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003ERole OR permission\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003EAny\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EAll listed roles AND permissions\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003EAll\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\u003C/div\u003E\n\u003Cp\u003EIf roles and permissions are omitted entirely, an authenticated user satisfies the authorization requirement regardless of match mode, subject to the session-state requirement.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022require-an-active-session\u0022\u003E6. Require an Active Session\u003C/h2\u003E\n\u003Cp\u003EBy default, \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E uses:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003EC#\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-csharp\u0022\u003ERequireActive = true\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThe default configuration can be written explicitly:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/account/settings\u0026quot;\n@attribute [UAuthAuthorize(RequireActive = true)]\n\n\u0026lt;h1\u0026gt;Account Settings\u0026lt;/h1\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EWhen UltimateAuth has session-state information and the session is not active, authorization returns an inactive result.\u003C/p\u003E\n\u003Cp\u003EIf your application needs to allow an authenticated user regardless of a reported non-active session state, you can disable this requirement:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/session-information\u0026quot;\n@attribute [UAuthAuthorize(RequireActive = false)]\n\n\u0026lt;h1\u0026gt;Session Information\u0026lt;/h1\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThis changes only the session-state condition. Authentication is still required.\u003C/p\u003E\n\u003Cblockquote\u003E\n\u003Cp\u003E\u003Cstrong\u003EImportant:\u003C/strong\u003E \u003Ccode\u003ERequireActive\u003C/code\u003E evaluates the session state currently available to the Blazor client. It does not independently validate a session against the server for every render. Server-side session validation and revocation enforcement remain necessary.\u003C/p\u003E\n\u003C/blockquote\u003E\n\u003Cp\u003EWhen no session-state value is available, the default evaluator does not reject the user solely because that value is absent.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022protect-part-of-a-page-with-uauthstateview\u0022\u003E7. Protect Part of a Page with UAuthStateView\u003C/h2\u003E\n\u003Cp\u003ESometimes you want the page to remain publicly accessible while protecting only a specific section.\u003C/p\u003E\n\u003Cp\u003EUse \u003Ccode\u003EUAuthStateView\u003C/code\u003E for conditional rendering.\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/products\u0026quot;\n\n\u0026lt;h1\u0026gt;Products\u0026lt;/h1\u0026gt;\n\n\u0026lt;p\u0026gt;Everyone can view this page.\u0026lt;/p\u0026gt;\n\n\u0026lt;UAuthStateView Roles=\u0026quot;Admin\u0026quot;\u0026gt;\n \u0026lt;Authorized\u0026gt;\n \u0026lt;button\u0026gt;Edit Products\u0026lt;/button\u0026gt;\n \u0026lt;/Authorized\u0026gt;\n \u0026lt;NotAuthorized\u0026gt;\n \u0026lt;p\u0026gt;Administrative tools are unavailable.\u0026lt;/p\u0026gt;\n \u0026lt;/NotAuthorized\u0026gt;\n\u0026lt;/UAuthStateView\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThe page itself remains accessible to everyone.\u003C/p\u003E\n\u003Cp\u003EHowever, the administrative section is only rendered for an authorized user.\u003C/p\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthStateView\u003C/code\u003E uses the same \u003Ccode\u003EIUAuthAuthorizationEvaluator\u003C/code\u003E as \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E, so matching roles, permissions, and match modes have consistent semantics.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022basic-authentication-only-section\u0022\u003EBasic authentication-only section\u003C/h3\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;UAuthStateView\u0026gt;\n \u0026lt;Authorized\u0026gt;\n \u0026lt;p\u0026gt;Welcome back!\u0026lt;/p\u0026gt;\n \u0026lt;/Authorized\u0026gt;\n \u0026lt;NotAuthorized\u0026gt;\n \u0026lt;p\u0026gt;Sign in to access your account features.\u0026lt;/p\u0026gt;\n \u0026lt;/NotAuthorized\u0026gt;\n\u0026lt;/UAuthStateView\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EAs with parameterless \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E, authentication is required, along with an acceptable session state when \u003Ccode\u003ERequireActive\u003C/code\u003E is true.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022protect-a-section-with-permissions\u0022\u003EProtect a section with permissions\u003C/h3\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;UAuthStateView Permissions=\u0026quot;orders.refund.self\u0026quot;\u0026gt;\n \u0026lt;Authorized\u0026gt;\n \u0026lt;button\u0026gt;Refund Order\u0026lt;/button\u0026gt;\n \u0026lt;/Authorized\u0026gt;\n \u0026lt;NotAuthorized\u0026gt;\n \u0026lt;p\u0026gt;You cannot refund orders.\u0026lt;/p\u0026gt;\n \u0026lt;/NotAuthorized\u0026gt;\n\u0026lt;/UAuthStateView\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022combine-requirements-in-a-section\u0022\u003ECombine requirements in a section\u003C/h3\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;UAuthStateView Roles=\u0026quot;Admin,Manager\u0026quot; Permissions=\u0026quot;orders.read.self,orders.manage.admin\u0026quot; MatchMode=\u0026quot;AuthorizationMatchMode.Category\u0026quot;\u0026gt;\n \u0026lt;Authorized\u0026gt;\n \u0026lt;p\u0026gt;Order management tools are available.\u0026lt;/p\u0026gt;\n \u0026lt;/Authorized\u0026gt;\n \u0026lt;NotAuthorized\u0026gt;\n \u0026lt;p\u0026gt;Access denied.\u0026lt;/p\u0026gt;\n \u0026lt;/NotAuthorized\u0026gt;\n\u0026lt;/UAuthStateView\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThis uses the same \u003Ccode\u003ECategory\u003C/code\u003E semantics as the routed page attribute.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022access-the-current-authentication-state\u0022\u003EAccess the current authentication state\u003C/h3\u003E\n\u003Cp\u003EThe \u003Ccode\u003EAuthorized\u003C/code\u003E fragment receives the current \u003Ccode\u003EUAuthState\u003C/code\u003E as its context.\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;UAuthStateView\u0026gt;\n \u0026lt;Authorized Context=\u0026quot;state\u0026quot;\u0026gt;\n \u0026lt;p\u0026gt;Hello, @state.Identity?.DisplayName!\u0026lt;/p\u0026gt;\n \u0026lt;/Authorized\u0026gt;\n \u0026lt;NotAuthorized\u0026gt;\n \u0026lt;p\u0026gt;Please sign in.\u0026lt;/p\u0026gt;\n \u0026lt;/NotAuthorized\u0026gt;\n\u0026lt;/UAuthStateView\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThis allows authorized content to access identity information without requiring a custom base class.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022handle-unauthorized-inactive-and-authorizing-states\u0022\u003E8. Handle Unauthorized, Inactive, and Authorizing States\u003C/h2\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthStateView\u003C/code\u003E supports multiple rendering states.\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;UAuthStateView Roles=\u0026quot;Admin\u0026quot;\n RequireActive=\u0026quot;true\u0026quot;\u0026gt;\n \u0026lt;Authorized\u0026gt;\n \u0026lt;p\u0026gt;Administrator access granted.\u0026lt;/p\u0026gt;\n \u0026lt;/Authorized\u0026gt;\n\n \u0026lt;NotAuthorized\u0026gt;\n \u0026lt;p\u0026gt;You do not have permission to access this section.\u0026lt;/p\u0026gt;\n \u0026lt;/NotAuthorized\u0026gt;\n\n \u0026lt;Inactive Context=\u0026quot;state\u0026quot;\u0026gt;\n \u0026lt;p\u0026gt;Your session is not active.\u0026lt;/p\u0026gt;\n \u0026lt;/Inactive\u0026gt;\n\n \u0026lt;Authorizing\u0026gt;\n \u0026lt;p\u0026gt;Checking your permissions...\u0026lt;/p\u0026gt;\n \u0026lt;/Authorizing\u0026gt;\n\u0026lt;/UAuthStateView\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cdiv class=\u0022docs-table-wrapper\u0022\u003E\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EFragment\u003C/th\u003E\n\u003Cth\u003EWhen displayed\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EAuthorized\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EAuthorization succeeds\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003ENotAuthorized\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EAuthorization is denied\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EInactive\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EA non-active session is detected and \u003Ccode\u003ERequireActive\u003C/code\u003E is true\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EAuthorizing\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EAuthorization evaluation is in progress\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\u003C/div\u003E\n\u003Cp\u003EIf \u003Ccode\u003EInactive\u003C/code\u003E is not supplied, the component falls back to the \u003Ccode\u003ENotAuthorized\u003C/code\u003E fragment.\u003C/p\u003E\n\u003Cp\u003EIf \u003Ccode\u003EAuthorizing\u003C/code\u003E is not supplied, unauthorized content is used while a new authorization result is pending.\u003C/p\u003E\n\u003Cp\u003EDuring reevaluation, previously authorized section content is removed before an asynchronous policy evaluation completes. This prevents stale authorized content from remaining visible during that pending evaluation.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022use-an-asp.net-core-authorization-policy\u0022\u003E9. Use an ASP.NET Core Authorization Policy\u003C/h2\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthStateView\u003C/code\u003E supports the \u003Ccode\u003EPolicy\u003C/code\u003E parameter.\u003C/p\u003E\n\u003Cp\u003EFirst, register a policy using ASP.NET Core authorization:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003EC#\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-csharp\u0022\u003Ebuilder.Services.AddAuthorizationCore(options =\u0026gt;\n{\n options.AddPolicy(\u0026quot;CanViewReports\u0026quot;, policy =\u0026gt; policy.RequireClaim(\u0026quot;reports_access\u0026quot;, \u0026quot;granted\u0026quot;));\n});\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThen use that policy in a UI section:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;UAuthStateView Policy=\u0026quot;CanViewReports\u0026quot;\u0026gt;\n \u0026lt;Authorized\u0026gt;\n \u0026lt;p\u0026gt;Reports are available.\u0026lt;/p\u0026gt;\n \u0026lt;/Authorized\u0026gt;\n \u0026lt;NotAuthorized\u0026gt;\n \u0026lt;p\u0026gt;Reports access is restricted.\u0026lt;/p\u0026gt;\n \u0026lt;/NotAuthorized\u0026gt;\n\u0026lt;/UAuthStateView\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThe policy is evaluated through ASP.NET Core\u0027s \u003Ccode\u003EIAuthorizationService\u003C/code\u003E, using the claims principal produced from the current UltimateAuth state.\u003C/p\u003E\n\u003Cp\u003EYou can also combine a policy with roles and permissions:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;UAuthStateView Roles=\u0026quot;Admin\u0026quot; Permissions=\u0026quot;reports.read\u0026quot; Policy=\u0026quot;CanViewReports\u0026quot; MatchMode=\u0026quot;AuthorizationMatchMode.All\u0026quot;\u0026gt;\n \u0026lt;Authorized\u0026gt;\n \u0026lt;p\u0026gt;All requirements passed.\u0026lt;/p\u0026gt;\n \u0026lt;/Authorized\u0026gt;\n\u0026lt;/UAuthStateView\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EFor \u003Ccode\u003EAll\u003C/code\u003E, every configured requirement must succeed.\u003C/p\u003E\n\u003Cp\u003EFor \u003Ccode\u003EAny\u003C/code\u003E, the policy is another possible successful condition.\u003C/p\u003E\n\u003Cp\u003EFor \u003Ccode\u003ECategory\u003C/code\u003E, the policy must succeed alongside the configured role and permission categories.\u003C/p\u003E\n\u003Cblockquote\u003E\n\u003Cp\u003E\u003Cstrong\u003ECurrent API distinction:\u003C/strong\u003E \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E currently exposes \u003Ccode\u003ERoles\u003C/code\u003E, \u003Ccode\u003EPermissions\u003C/code\u003E, \u003Ccode\u003EMatchMode\u003C/code\u003E, and \u003Ccode\u003ERequireActive\u003C/code\u003E, but not \u003Ccode\u003EPolicy\u003C/code\u003E. Use \u003Ccode\u003EUAuthStateView\u003C/code\u003E for policy-based section rendering, or ASP.NET Core \u003Ccode\u003E[Authorize(Policy = \u0026quot;...\u0026quot;)]\u003C/code\u003E for policy-protected routed pages.\u003C/p\u003E\n\u003C/blockquote\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022protect-a-page-with-asp.net-core-authorize\u0022\u003E10. Protect a Page with ASP.NET Core Authorize\u003C/h2\u003E\n\u003Cp\u003EUltimateAuth integrates with ASP.NET Core authorization.\u003C/p\u003E\n\u003Cp\u003EYou can use the standard \u003Ccode\u003E[Authorize]\u003C/code\u003E attribute on routed Blazor pages.\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/account\u0026quot;\n@attribute [Authorize]\n\n\u0026lt;h1\u0026gt;Account\u0026lt;/h1\u0026gt;\n\n\u0026lt;p\u0026gt;This page requires ASP.NET Core authorization.\u0026lt;/p\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EOr require a role:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/administration\u0026quot;\n@attribute [Authorize(Roles = \u0026quot;Admin\u0026quot;)]\n\n\u0026lt;h1\u0026gt;Administration\u0026lt;/h1\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EOr a registered policy:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/reports\u0026quot;\n@attribute [Authorize(Policy = \u0026quot;CanViewReports\u0026quot;)]\n\n\u0026lt;h1\u0026gt;Reports\u0026lt;/h1\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThese checks are performed through ASP.NET Core\u0027s \u003Ccode\u003EAuthorizeRouteView\u003C/code\u003E and its authentication and authorization infrastructure.\u003C/p\u003E\n\u003Cp\u003EUltimateAuth provides a Blazor \u003Ccode\u003EAuthenticationStateProvider\u003C/code\u003E that integrates UltimateAuth authentication state with ASP.NET Core.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022which-attribute-should-i-use\u0022\u003EWhich attribute should I use?\u003C/h3\u003E\n\u003Cdiv class=\u0022docs-table-wrapper\u0022\u003E\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EFeature\u003C/th\u003E\n\u003Cth\u003E\u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E\u003C/th\u003E\n\u003Cth\u003E\u003Ccode\u003E[Authorize]\u003C/code\u003E\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003ERequires authentication\u003C/td\u003E\n\u003Ctd\u003EYes\u003C/td\u003E\n\u003Ctd\u003EYes\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003ERoles\u003C/td\u003E\n\u003Ctd\u003EYes\u003C/td\u003E\n\u003Ctd\u003EYes\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EUltimateAuth permissions\u003C/td\u003E\n\u003Ctd\u003EYes\u003C/td\u003E\n\u003Ctd\u003EVia separately configured ASP.NET Core policies or handlers\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EAuthorizationMatchMode\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EYes\u003C/td\u003E\n\u003Ctd\u003ENo direct equivalent property\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003ERequireActive\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EYes\u003C/td\u003E\n\u003Ctd\u003ENo direct equivalent property\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003ENamed ASP.NET Core policy\u003C/td\u003E\n\u003Ctd\u003ENot currently\u003C/td\u003E\n\u003Ctd\u003EYes\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003ERouted Blazor page\u003C/td\u003E\n\u003Ctd\u003EYes\u003C/td\u003E\n\u003Ctd\u003EYes\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\u003C/div\u003E\n\u003Cp\u003EUse \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E when working directly with UltimateAuth roles, permissions, and session-aware requirements.\u003C/p\u003E\n\u003Cp\u003EUse \u003Ccode\u003E[Authorize]\u003C/code\u003E when relying on ASP.NET Core authorization policies, requirements, or existing authorization infrastructure.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022combine-both-attributes\u0022\u003ECombine both attributes\u003C/h3\u003E\n\u003Cp\u003EYou can declare both on the same routed page:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/secure-reports\u0026quot;\n\n@attribute [UAuthAuthorize(Permissions = \u0026quot;reports.read\u0026quot;)]\n@attribute [Authorize(Roles = \u0026quot;Admin\u0026quot;)]\n\n\u0026lt;h1\u0026gt;Secure Reports\u0026lt;/h1\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThe page is rendered only when \u003Cstrong\u003Eboth authorization systems allow access\u003C/strong\u003E.\u003C/p\u003E\n\u003Cp\u003EUltimateAuth evaluates \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E, and the underlying ASP.NET Core \u003Ccode\u003EAuthorizeRouteView\u003C/code\u003E evaluates \u003Ccode\u003E[Authorize]\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EThe requirements are effectively combined using AND semantics across the two mechanisms.\u003C/p\u003E\n\u003Cblockquote\u003E\n\u003Cp\u003E\u003Cstrong\u003ENote:\u003C/strong\u003E ASP.NET Core \u003Ccode\u003E[Authorize]\u003C/code\u003E uses the configured ASP.NET Core authentication state. \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E uses \u003Ccode\u003EUAuthState\u003C/code\u003E. UltimateAuth integrates these models, but custom authentication providers must keep their states consistent.\u003C/p\u003E\n\u003C/blockquote\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022how-uauthapp-protects-routes\u0022\u003E11. How UAuthApp Protects Routes\u003C/h2\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthApp\u003C/code\u003E is the root Blazor integration component for UltimateAuth.\u003C/p\u003E\n\u003Cp\u003EIt provides:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EClient runtime initialization.\u003C/li\u003E\n\u003Cli\u003EThe current \u003Ccode\u003EUAuthState\u003C/code\u003E as a cascading parameter.\u003C/li\u003E\n\u003Cli\u003EASP.NET Core cascading authentication state.\u003C/li\u003E\n\u003Cli\u003ESession lifecycle coordination.\u003C/li\u003E\n\u003Cli\u003ERuntime initialization readiness.\u003C/li\u003E\n\u003Cli\u003EOptional built-in routing.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022built-in-router\u0022\u003EBuilt-in router\u003C/h3\u003E\n\u003Cp\u003EIf you use:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;UAuthApp UseBuiltInRouter=\u0026quot;true\u0026quot; AppAssembly=\u0026quot;typeof(Program).Assembly\u0026quot; DefaultLayout=\u0026quot;typeof(Layout.MainLayout)\u0026quot; /\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EUltimateAuth automatically configures its router to use \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EYou do not need to add a separate \u003Ccode\u003EAuthorizeRouteView\u003C/code\u003E or \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EThe built-in router supports both \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E and ASP.NET Core \u003Ccode\u003E[Authorize]\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EIt also supports an application-level \u003Ccode\u003ENotAuthorized\u003C/code\u003E fragment:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;UAuthApp UseBuiltInRouter=\u0026quot;true\u0026quot;\n AppAssembly=\u0026quot;typeof(Program).Assembly\u0026quot;\n DefaultLayout=\u0026quot;typeof(Layout.MainLayout)\u0026quot;\u0026gt;\n \u0026lt;NotAuthorized\u0026gt;\n \u0026lt;h1\u0026gt;Access Denied\u0026lt;/h1\u0026gt;\n \u0026lt;p\u0026gt;You are not authorized to access this page.\u0026lt;/p\u0026gt;\n \u0026lt;/NotAuthorized\u0026gt;\n\u0026lt;/UAuthApp\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThis fragment is displayed when route authorization fails.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022runtime-initialization\u0022\u003ERuntime initialization\u003C/h3\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthApp\u003C/code\u003E initializes the client authentication state before allowing UltimateAuth-protected routes to be rendered.\u003C/p\u003E\n\u003Cp\u003EThis is important because authentication state may not be immediately available when a Blazor application first starts, particularly when restoring a session.\u003C/p\u003E\n\u003Cp\u003EDuring initialization or asynchronous authorization evaluation, \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E can display an \u003Ccode\u003EAuthorizing\u003C/code\u003E fragment.\u003C/p\u003E\n\u003Cp\u003EIf one is not supplied, the protected route content remains unrendered while authorization is pending.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022manual-and-reactive-render-modes\u0022\u003EManual and Reactive render modes\u003C/h3\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthApp\u003C/code\u003E supports \u003Ccode\u003EUAuthRenderMode.Manual\u003C/code\u003E and \u003Ccode\u003EUAuthRenderMode.Reactive\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EThese control how UltimateAuth state changes affect general component rendering.\u003C/p\u003E\n\u003Cp\u003ERoute authorization itself subscribes to relevant authentication state changes, and \u003Ccode\u003EUAuthStateView\u003C/code\u003E also reacts to such changes.\u003C/p\u003E\n\u003Cp\u003EYou do not need to enable reactive rendering merely to make \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E work.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022protect-pages-with-a-custom-router\u0022\u003E12. Protect Pages with a Custom Router\u003C/h2\u003E\n\u003Cp\u003EIf your application uses its own Blazor \u003Ccode\u003ERouter\u003C/code\u003E, set \u003Ccode\u003EUseBuiltInRouter=\u0026quot;false\u0026quot;\u003C/code\u003E on \u003Ccode\u003EUAuthApp\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EThen use \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E inside the router\u0027s \u003Ccode\u003EFound\u003C/code\u003E fragment.\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;UAuthApp UseBuiltInRouter=\u0026quot;false\u0026quot;\u0026gt;\n \u0026lt;Router AppAssembly=\u0026quot;typeof(Program).Assembly\u0026quot;\u0026gt;\n \u0026lt;Found Context=\u0026quot;routeData\u0026quot;\u0026gt;\n \u0026lt;UAuthAuthorizeRouteView RouteData=\u0026quot;routeData\u0026quot; DefaultLayout=\u0026quot;typeof(Layout.MainLayout)\u0026quot;\u0026gt;\n\n \u0026lt;NotAuthorized\u0026gt;\n \u0026lt;h1\u0026gt;Access Denied\u0026lt;/h1\u0026gt;\n \u0026lt;p\u0026gt;You cannot access this page.\u0026lt;/p\u0026gt;\n \u0026lt;/NotAuthorized\u0026gt;\n\n \u0026lt;Authorizing\u0026gt;\n \u0026lt;p\u0026gt;Checking access...\u0026lt;/p\u0026gt;\n \u0026lt;/Authorizing\u0026gt;\n\n \u0026lt;/UAuthAuthorizeRouteView\u0026gt;\n\n \u0026lt;FocusOnNavigate RouteData=\u0026quot;routeData\u0026quot; Selector=\u0026quot;h1\u0026quot; /\u0026gt;\n \u0026lt;/Found\u0026gt;\n \u0026lt;/Router\u0026gt;\n\u0026lt;/UAuthApp\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E wraps ASP.NET Core\u0027s \u003Ccode\u003EAuthorizeRouteView\u003C/code\u003E internally.\u003C/p\u003E\n\u003Cp\u003EThis means it supports both authorization systems, while checking UltimateAuth-specific requirements before the protected page component is instantiated.\u003C/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EDo not replace it with a plain \u003Ccode\u003ERouteView\u003C/code\u003E or \u003Ccode\u003EAuthorizeRouteView\u003C/code\u003E when your routed pages depend on \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E.\u003C/strong\u003E\u003C/p\u003E\n\u003Cp\u003EA plain ASP.NET Core \u003Ccode\u003EAuthorizeRouteView\u003C/code\u003E does not evaluate the UltimateAuth-specific attribute by itself.\u003C/p\u003E\n\u003Cp\u003EIf your custom router uses additional route assemblies, pass the appropriate \u003Ccode\u003EAdditionalAssemblies\u003C/code\u003E to the \u003Ccode\u003ERouter\u003C/code\u003E as needed.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022do-i-need-uauthcomponentbase\u0022\u003E13. Do I Need UAuthComponentBase?\u003C/h2\u003E\n\u003Cp\u003E\u003Cstrong\u003ENot for authorization.\u003C/strong\u003E\u003C/p\u003E\n\u003Cp\u003EConsider this page:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/settings\u0026quot;\n@attribute [UAuthAuthorize]\n\n\u0026lt;h1\u0026gt;Settings\u0026lt;/h1\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EIt is protected when routed through \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E, even though it doesn\u0027t inherit from \u003Ccode\u003EUAuthComponentBase\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EYou can still use \u003Ccode\u003EUAuthComponentBase\u003C/code\u003E when you need access to the UltimateAuth state lifecycle.\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/profile\u0026quot;\n@attribute [UAuthAuthorize]\n@inherits UAuthComponentBase\n\n\u0026lt;h1\u0026gt;Profile\u0026lt;/h1\u0026gt;\n\n\u0026lt;p\u0026gt;User: @AuthState.Identity?.DisplayName\u0026lt;/p\u0026gt;\n\n@code {\n protected override Task HandleAuthStateChangedAsync(\n UAuthStateChangeReason reason)\n {\n // React to authentication state changes.\n return Task.CompletedTask;\n }\n}\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthComponentBase\u003C/code\u003E provides:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EAccess to cascading \u003Ccode\u003EUAuthState\u003C/code\u003E.\u003C/li\u003E\n\u003Cli\u003EAuthentication state change notifications.\u003C/li\u003E\n\u003Cli\u003EAutomatic rerendering when the state changes, by default.\u003C/li\u003E\n\u003Cli\u003EAn asynchronous lifecycle hook.\u003C/li\u003E\n\u003Cli\u003EEvent subscription cleanup on disposal.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EHowever, it no longer performs page authorization itself.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022can-i-use-uauthauthorize-on-a-regular-child-component\u0022\u003ECan I use UAuthAuthorize on a regular child component?\u003C/h3\u003E\n\u003Cp\u003EThe attribute only declares metadata. It does not enforce authorization on its own.\u003C/p\u003E\n\u003Cp\u003EFor example:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@attribute [UAuthAuthorize(Roles = \u0026quot;Admin\u0026quot;)]\n\n\u0026lt;div\u0026gt;Administrative tools\u0026lt;/div\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EIf this is an ordinary child component rendered directly inside another page, \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E is not automatically evaluated by \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003ERoute authorization is performed for routed page components.\u003C/p\u003E\n\u003Cp\u003EFor conditional content inside a page, use \u003Ccode\u003EUAuthStateView\u003C/code\u003E instead.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022advanced-customize-authorization-evaluation\u0022\u003E14. Advanced: Customize Authorization Evaluation\u003C/h2\u003E\n\u003Cp\u003EUltimateAuth uses the \u003Ccode\u003EIUAuthAuthorizationEvaluator\u003C/code\u003E service for Blazor authorization.\u003C/p\u003E\n\u003Cp\u003EThe default evaluator is registered by:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003EC#\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-csharp\u0022\u003Ebuilder.Services.AddUltimateAuthClientBlazor();\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EIt evaluates:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EAuthentication status.\u003C/li\u003E\n\u003Cli\u003ESession state when required.\u003C/li\u003E\n\u003Cli\u003ERoles.\u003C/li\u003E\n\u003Cli\u003EPermissions.\u003C/li\u003E\n\u003Cli\u003EASP.NET Core policies supplied through authorization requirements.\u003C/li\u003E\n\u003Cli\u003EThe configured match mode.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EThe evaluator is registered with \u003Ccode\u003ETryAddScoped\u003C/code\u003E, allowing applications to provide their own implementation through dependency injection.\u003C/p\u003E\n\u003Cp\u003EIf you need custom application-specific authorization behavior, you can implement \u003Ccode\u003EIUAuthAuthorizationEvaluator\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EA replacement evaluator receives the current \u003Ccode\u003EUAuthState\u003C/code\u003E and a \u003Ccode\u003EUAuthAuthorizationRequirement\u003C/code\u003E and returns a \u003Ccode\u003EUAuthAuthorizationResult\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EA custom implementation should preserve secure defaults, especially for anonymous users, inactive sessions, and failed authorization checks.\u003C/p\u003E\n\u003Cp\u003EKeep authorization evaluation separate from component rendering and navigation logic.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022important-security-considerations\u0022\u003E15. Important Security Considerations\u003C/h2\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022blazor-ui-authorization-is-not-api-authorization\u0022\u003EBlazor UI authorization is not API authorization\u003C/h3\u003E\n\u003Cp\u003EAn unauthorized user should not see or instantiate a protected routed page. However, hiding UI does not secure the HTTP endpoint or underlying data source.\u003C/p\u003E\n\u003Cp\u003EFor example:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@page \u0026quot;/users\u0026quot;\n@attribute [UAuthAuthorize(Roles = \u0026quot;Admin\u0026quot;)]\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThis protects the Blazor page through UltimateAuth\u0027s router.\u003C/p\u003E\n\u003Cp\u003EIt does \u003Cstrong\u003Enot\u003C/strong\u003E automatically protect an unrelated API endpoint such as:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003EText\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-text\u0022\u003EGET /api/users\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThat endpoint must independently validate the caller and enforce the required authorization.\u003C/p\u003E\n\u003Cp\u003EFor Blazor Server, the same principle applies to sensitive server-side operations, even when they are invoked without an HTTP call from the component.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022uauthauthorize-is-currently-a-blazor-attribute\u0022\u003EUAuthAuthorize is currently a Blazor attribute\u003C/h3\u003E\n\u003Cp\u003EThe current \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E attribute is interpreted by UltimateAuth\u0027s Blazor authorization pipeline.\u003C/p\u003E\n\u003Cp\u003EIt does not, by itself, secure ASP.NET Core controllers or Minimal API endpoints.\u003C/p\u003E\n\u003Cp\u003EUse the server-side authorization mechanisms appropriate for those endpoints.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022revocation-and-role-changes\u0022\u003ERevocation and role changes\u003C/h3\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E and \u003Ccode\u003EUAuthStateView\u003C/code\u003E respond to authentication state changes.\u003C/p\u003E\n\u003Cp\u003EWhen the available \u003Ccode\u003EUAuthState\u003C/code\u003E changes, authorization can be reevaluated.\u003C/p\u003E\n\u003Cp\u003EHowever, a remote role change or server-side session revocation is not necessarily observed immediately by the Blazor client.\u003C/p\u003E\n\u003Cp\u003EServer-side authorization must remain authoritative, even while a client retains stale state.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022authorization-during-navigation\u0022\u003EAuthorization during navigation\u003C/h3\u003E\n\u003Cp\u003EA protected routed page is not instantiated until UltimateAuth authorization succeeds.\u003C/p\u003E\n\u003Cp\u003EWhen authorization becomes invalid, the route view stops rendering the protected page.\u003C/p\u003E\n\u003Cp\u003EThis is different from implementing a redirect inside the page\u0027s \u003Ccode\u003EOnInitialized\u003C/code\u003E or \u003Ccode\u003EOnAfterRender\u003C/code\u003E method, where the component may already have been instantiated.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022do-not-rely-on-hidden-controls-for-security\u0022\u003EDo not rely on hidden controls for security\u003C/h3\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthStateView\u003C/code\u003E is useful for showing or hiding buttons, navigation entries, and sections.\u003C/p\u003E\n\u003Cp\u003EAlways authorize the underlying operation independently.\u003C/p\u003E\n\u003Cp\u003EFor example, hiding a \u003Ccode\u003EDelete User\u003C/code\u003E button does not remove the need to authorize the actual delete request.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022troubleshooting\u0022\u003E16. Troubleshooting\u003C/h2\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022uauthauthorize-does-not-prevent-access\u0022\u003EUAuthAuthorize does not prevent access\u003C/h3\u003E\n\u003Cp\u003EFirst, make sure you\u0027re using \u003Cstrong\u003EUltimateAuth v0.1.1 or later\u003C/strong\u003E.\u003C/p\u003E\n\u003Cp\u003EEarlier versions relied on \u003Ccode\u003EUAuthComponentBase\u003C/code\u003E for authorization checks. Starting with v0.1.1, \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E is enforced at the routing level through \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EIf authorization is not working as expected:\u003C/p\u003E\n\u003Col\u003E\n\u003Cli\u003EVerify that \u003Ccode\u003ECodeBeam.UltimateAuth.Client.Blazor\u003C/code\u003E is version \u003Ccode\u003E0.1.1\u003C/code\u003E or later.\u003C/li\u003E\n\u003Cli\u003EIf you\u0027re using the built-in router, make sure \u003Ccode\u003EUseBuiltInRouter=\u0026quot;true\u0026quot;\u003C/code\u003E is configured on \u003Ccode\u003EUAuthApp\u003C/code\u003E.\u003C/li\u003E\n\u003Cli\u003EIf you\u0027re using a custom router, replace \u003Ccode\u003ERouteView\u003C/code\u003E or \u003Ccode\u003EAuthorizeRouteView\u003C/code\u003E with \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E.\u003C/li\u003E\n\u003Cli\u003EMake sure the page is routed within the \u003Ccode\u003EUAuthApp\u003C/code\u003E context.\u003C/li\u003E\n\u003Cli\u003EConfirm that the user meets the authentication, role, permission, and session-state requirements.\u003C/li\u003E\n\u003C/ol\u003E\n\u003Cp\u003E\u003Cstrong\u003EUpgrading from v0.1.0?\u003C/strong\u003E See \u003Ca href=\u0022/docs/migration/v0.1.1\u0022\u003EMigrating to v0.1.1\u003C/a\u003E for the required changes.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022the-protected-page-appears-blank-during-startup\u0022\u003EThe protected page appears blank during startup\u003C/h3\u003E\n\u003Cp\u003EUltimateAuth may still be initializing or evaluating authorization.\u003C/p\u003E\n\u003Cp\u003EWith a custom router, provide an \u003Ccode\u003EAuthorizing\u003C/code\u003E fragment for a loading indicator.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022uauthstateview-reports-a-missing-cascading-uauthstate\u0022\u003EUAuthStateView reports a missing cascading UAuthState\u003C/h3\u003E\n\u003Cp\u003EMake sure the component is rendered inside \u003Ccode\u003EUAuthApp\u003C/code\u003E, or another host that correctly provides the required cascading UltimateAuth state.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022asp.net-core-authorization-reports-a-missing-authenticationstate\u0022\u003EASP.NET Core authorization reports a missing AuthenticationState\u003C/h3\u003E\n\u003Cp\u003EMake sure ASP.NET Core\u0027s authentication state infrastructure is available.\u003C/p\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthApp\u003C/code\u003E provides a \u003Ccode\u003ECascadingAuthenticationState\u003C/code\u003E within its child content.\u003C/p\u003E\n\u003Cp\u003EIf you create a custom host outside \u003Ccode\u003EUAuthApp\u003C/code\u003E, you must provide the appropriate ASP.NET Core cascading authentication state yourself.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022roles-or-permissions-are-unexpectedly-denied\u0022\u003ERoles or permissions are unexpectedly denied\u003C/h3\u003E\n\u003Cp\u003EConfirm that:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EThe user is authenticated.\u003C/li\u003E\n\u003Cli\u003EThe state contains the expected role or permission.\u003C/li\u003E\n\u003Cli\u003EThe correct match mode is selected.\u003C/li\u003E\n\u003Cli\u003EThe user\u0027s session state satisfies \u003Ccode\u003ERequireActive\u003C/code\u003E.\u003C/li\u003E\n\u003Cli\u003EThe client state has been updated after any server-side changes.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022i-need-a-policy-directly-on-a-routed-page\u0022\u003EI need a policy directly on a routed page\u003C/h3\u003E\n\u003Cp\u003EUse ASP.NET Core\u0027s \u003Ccode\u003E[Authorize(Policy = \u0026quot;...\u0026quot;)]\u003C/code\u003E attribute.\u003C/p\u003E\n\u003Cp\u003EThe current \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E attribute does not expose a \u003Ccode\u003EPolicy\u003C/code\u003E property.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022summary\u0022\u003ESummary\u003C/h2\u003E\n\u003Cdiv class=\u0022docs-table-wrapper\u0022\u003E\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EScenario\u003C/th\u003E\n\u003Cth\u003ERecommended approach\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EProtect an entire Blazor page\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003ERequire an UltimateAuth role\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003E[UAuthAuthorize(Roles = \u0026quot;...\u0026quot;)]\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003ERequire an UltimateAuth permission\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003E[UAuthAuthorize(Permissions = \u0026quot;...\u0026quot;)]\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003ECombine roles and permissions\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003EMatchMode\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003ERequire ASP.NET Core policy authorization\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003E[Authorize(Policy = \u0026quot;...\u0026quot;)]\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003ECombine ASP.NET Core and UltimateAuth\u003C/td\u003E\n\u003Ctd\u003EUse both attributes\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EProtect an individual UI section\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003EUAuthStateView\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EUse built-in routing\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003EUAuthApp UseBuiltInRouter=\u0026quot;true\u0026quot;\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EUse custom routing\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EReact to authentication lifecycle changes\u003C/td\u003E\n\u003Ctd\u003E\u003Ccode\u003EUAuthComponentBase\u003C/code\u003E\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EProtect an API or server operation\u003C/td\u003E\n\u003Ctd\u003EEnforce authorization on the server\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\u003C/div\u003E\n\u003Cp\u003EUltimateAuth\u0027s Blazor authorization model allows you to declare requirements at the page level, conditionally render protected sections, and integrate with ASP.NET Core authorization without coupling page protection to a specific base class.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022next-steps\u0022\u003ENext Steps\u003C/h2\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ca href=\u0022/docs/getting-started/quickstart\u0022\u003EQuickStart\u003C/a\u003E \u2014 Create a working UltimateAuth application.\u003C/li\u003E\n\u003Cli\u003E\u003Ca href=\u0022/docs/fundamentals/auth-model\u0022\u003EAuthentication Model\u003C/a\u003E \u2014 Understand UltimateAuth authentication concepts.\u003C/li\u003E\n\u003Cli\u003E\u003Ca href=\u0022/docs/migration/v0.1.1\u0022\u003EMigration to v0.1.1\u003C/a\u003E \u2014 Update custom routers and existing Blazor authorization code.\u003C/li\u003E\n\u003C/ul\u003E\n",
+ "Headings": [
+ {
+ "Id": "prerequisites",
+ "Text": "Prerequisites",
+ "Level": 0
+ },
+ {
+ "Id": "protect-a-page-with-uauthauthorize",
+ "Text": "1. Protect a Page with UAuthAuthorize",
+ "Level": 0
+ },
+ {
+ "Id": "does-the-page-need-to-inherit-from-uauthcomponentbase",
+ "Text": "Does the page need to inherit from UAuthComponentBase?",
+ "Level": 1
+ },
+ {
+ "Id": "require-a-role",
+ "Text": "2. Require a Role",
+ "Level": 0
+ },
+ {
+ "Id": "require-a-permission",
+ "Text": "3. Require a Permission",
+ "Level": 0
+ },
+ {
+ "Id": "combine-roles-and-permissions",
+ "Text": "4. Combine Roles and Permissions",
+ "Level": 0
+ },
+ {
+ "Id": "understand-match-modes",
+ "Text": "5. Understand Match Modes",
+ "Level": 0
+ },
+ {
+ "Id": "category-the-default",
+ "Text": "Category \u2014 the default",
+ "Level": 1
+ },
+ {
+ "Id": "any-one-match-is-enough",
+ "Text": "Any \u2014 one match is enough",
+ "Level": 1
+ },
+ {
+ "Id": "all-every-value-is-required",
+ "Text": "All \u2014 every value is required",
+ "Level": 1
+ },
+ {
+ "Id": "choosing-a-match-mode",
+ "Text": "Choosing a match mode",
+ "Level": 1
+ },
+ {
+ "Id": "require-an-active-session",
+ "Text": "6. Require an Active Session",
+ "Level": 0
+ },
+ {
+ "Id": "protect-part-of-a-page-with-uauthstateview",
+ "Text": "7. Protect Part of a Page with UAuthStateView",
+ "Level": 0
+ },
+ {
+ "Id": "basic-authentication-only-section",
+ "Text": "Basic authentication-only section",
+ "Level": 1
+ },
+ {
+ "Id": "protect-a-section-with-permissions",
+ "Text": "Protect a section with permissions",
+ "Level": 1
+ },
+ {
+ "Id": "combine-requirements-in-a-section",
+ "Text": "Combine requirements in a section",
+ "Level": 1
+ },
+ {
+ "Id": "access-the-current-authentication-state",
+ "Text": "Access the current authentication state",
+ "Level": 1
+ },
+ {
+ "Id": "handle-unauthorized-inactive-and-authorizing-states",
+ "Text": "8. Handle Unauthorized, Inactive, and Authorizing States",
+ "Level": 0
+ },
+ {
+ "Id": "use-an-asp.net-core-authorization-policy",
+ "Text": "9. Use an ASP.NET Core Authorization Policy",
+ "Level": 0
+ },
+ {
+ "Id": "protect-a-page-with-asp.net-core-authorize",
+ "Text": "10. Protect a Page with ASP.NET Core Authorize",
+ "Level": 0
+ },
+ {
+ "Id": "which-attribute-should-i-use",
+ "Text": "Which attribute should I use?",
+ "Level": 1
+ },
+ {
+ "Id": "combine-both-attributes",
+ "Text": "Combine both attributes",
+ "Level": 1
+ },
+ {
+ "Id": "how-uauthapp-protects-routes",
+ "Text": "11. How UAuthApp Protects Routes",
+ "Level": 0
+ },
+ {
+ "Id": "built-in-router",
+ "Text": "Built-in router",
+ "Level": 1
+ },
+ {
+ "Id": "runtime-initialization",
+ "Text": "Runtime initialization",
+ "Level": 1
+ },
+ {
+ "Id": "manual-and-reactive-render-modes",
+ "Text": "Manual and Reactive render modes",
+ "Level": 1
+ },
+ {
+ "Id": "protect-pages-with-a-custom-router",
+ "Text": "12. Protect Pages with a Custom Router",
+ "Level": 0
+ },
+ {
+ "Id": "do-i-need-uauthcomponentbase",
+ "Text": "13. Do I Need UAuthComponentBase?",
+ "Level": 0
+ },
+ {
+ "Id": "can-i-use-uauthauthorize-on-a-regular-child-component",
+ "Text": "Can I use UAuthAuthorize on a regular child component?",
+ "Level": 1
+ },
+ {
+ "Id": "advanced-customize-authorization-evaluation",
+ "Text": "14. Advanced: Customize Authorization Evaluation",
+ "Level": 0
+ },
+ {
+ "Id": "important-security-considerations",
+ "Text": "15. Important Security Considerations",
+ "Level": 0
+ },
+ {
+ "Id": "blazor-ui-authorization-is-not-api-authorization",
+ "Text": "Blazor UI authorization is not API authorization",
+ "Level": 1
+ },
+ {
+ "Id": "uauthauthorize-is-currently-a-blazor-attribute",
+ "Text": "UAuthAuthorize is currently a Blazor attribute",
+ "Level": 1
+ },
+ {
+ "Id": "revocation-and-role-changes",
+ "Text": "Revocation and role changes",
+ "Level": 1
+ },
+ {
+ "Id": "authorization-during-navigation",
+ "Text": "Authorization during navigation",
+ "Level": 1
+ },
+ {
+ "Id": "do-not-rely-on-hidden-controls-for-security",
+ "Text": "Do not rely on hidden controls for security",
+ "Level": 1
+ },
+ {
+ "Id": "troubleshooting",
+ "Text": "16. Troubleshooting",
+ "Level": 0
+ },
+ {
+ "Id": "uauthauthorize-does-not-prevent-access",
+ "Text": "UAuthAuthorize does not prevent access",
+ "Level": 1
+ },
+ {
+ "Id": "the-protected-page-appears-blank-during-startup",
+ "Text": "The protected page appears blank during startup",
+ "Level": 1
+ },
+ {
+ "Id": "uauthstateview-reports-a-missing-cascading-uauthstate",
+ "Text": "UAuthStateView reports a missing cascading UAuthState",
+ "Level": 1
+ },
+ {
+ "Id": "asp.net-core-authorization-reports-a-missing-authenticationstate",
+ "Text": "ASP.NET Core authorization reports a missing AuthenticationState",
+ "Level": 1
+ },
+ {
+ "Id": "roles-or-permissions-are-unexpectedly-denied",
+ "Text": "Roles or permissions are unexpectedly denied",
+ "Level": 1
+ },
+ {
+ "Id": "i-need-a-policy-directly-on-a-routed-page",
+ "Text": "I need a policy directly on a routed page",
+ "Level": 1
+ },
+ {
+ "Id": "summary",
+ "Text": "Summary",
+ "Level": 0
+ },
+ {
+ "Id": "next-steps",
+ "Text": "Next Steps",
+ "Level": 0
+ }
+ ],
+ "SourceHash": "DCAF757286008CAF750DF1425284DB7AAD17EAAF6B7FEA009089C1D6DEBEB91F",
+ "BuilderVersion": "1"
+}
\ No newline at end of file
diff --git a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/migration/index.json b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/migration/index.json
new file mode 100644
index 00000000..c595f397
--- /dev/null
+++ b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/migration/index.json
@@ -0,0 +1,14 @@
+{
+ "Slug": "migration/index",
+ "Title": "Migration Guides",
+ "Html": "\n\u003Cp\u003EVersion-specific instructions for upgrading UltimateAuth applications.\u003C/p\u003E\n\u003Cp\u003EMigration guides focus on breaking changes, behavior changes, and required application updates.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022available-guides\u0022\u003EAvailable Guides\u003C/h2\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ca href=\u0022/docs/migration/v0.1.1\u0022\u003EMigrating to v0.1.1\u003C/a\u003E \u2014 Blazor route authorization and component lifecycle changes.\u003C/li\u003E\n\u003C/ul\u003E\n",
+ "Headings": [
+ {
+ "Id": "available-guides",
+ "Text": "Available Guides",
+ "Level": 0
+ }
+ ],
+ "SourceHash": "FA6FAFE02BA9EF2656EBA1C8531CEC3F43A2666D05A61B6E2979BD96B3593D8B",
+ "BuilderVersion": "1"
+}
\ No newline at end of file
diff --git a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/migration/v0.1.1.json b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/migration/v0.1.1.json
new file mode 100644
index 00000000..5b5ae49d
--- /dev/null
+++ b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/migration/v0.1.1.json
@@ -0,0 +1,24 @@
+{
+ "Slug": "migration/v0.1.1",
+ "Title": "Migrating to v0.1.1",
+ "Html": "\n\u003Cp\u003EUltimateAuth v0.1.1 improves Blazor page authorization by moving \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E enforcement to the routing layer.\u003C/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EMost applications require no changes.\u003C/strong\u003E If you\u0027re using the built-in \u003Ccode\u003EUAuthApp\u003C/code\u003E router, authorization works automatically.\u003C/p\u003E\n\u003Cp\u003EOnly the following cases require attention.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022custom-routers\u0022\u003E1. Custom Routers\u003C/h2\u003E\n\u003Cp\u003EIf you use a custom Blazor router, replace \u003Ccode\u003EAuthorizeRouteView\u003C/code\u003E with \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EBefore:\u003C/strong\u003E\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;AuthorizeRouteView RouteData=\u0026quot;routeData\u0026quot; DefaultLayout=\u0026quot;typeof(MainLayout)\u0026quot; /\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003E\u003Cstrong\u003EAfter:\u003C/strong\u003E\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E\u0026lt;UAuthAuthorizeRouteView RouteData=\u0026quot;routeData\u0026quot; DefaultLayout=\u0026quot;typeof(MainLayout)\u0026quot; /\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EThis enables \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E enforcement while preserving ASP.NET Core \u003Ccode\u003E[Authorize]\u003C/code\u003E support.\u003C/p\u003E\n\u003Cp\u003EMake sure your custom router is rendered inside \u003Ccode\u003EUAuthApp\u003C/code\u003E.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022uauthcomponentbase-overrides\u0022\u003E2. UAuthComponentBase Overrides\u003C/h2\u003E\n\u003Cp\u003E\u003Ccode\u003EUAuthComponentBase\u003C/code\u003E no longer handles authorization or automatic redirects.\u003C/p\u003E\n\u003Cp\u003EIf you previously overrode \u003Ccode\u003EOnUnauthorized()\u003C/code\u003E or \u003Ccode\u003EOnForbidden()\u003C/code\u003E, replace that behavior with the \u003Ccode\u003ENotAuthorized\u003C/code\u003E fragment on \u003Ccode\u003EUAuthApp\u003C/code\u003E (built-in router) or \u003Ccode\u003EUAuthAuthorizeRouteView\u003C/code\u003E (custom router).\u003C/p\u003E\n\u003Cp\u003EThe authentication state change hook is now asynchronous.\u003C/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EBefore:\u003C/strong\u003E\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003EC#\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-csharp\u0022\u003Eprotected override void HandleAuthStateChanged(UAuthStateChangeReason reason)\n{\n}\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003E\u003Cstrong\u003EAfter:\u003C/strong\u003E\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003EC#\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-csharp\u0022\u003Eprotected override Task HandleAuthStateChangedAsync(UAuthStateChangeReason reason)\n{\n return Task.CompletedTask;\n}\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EPages no longer need to inherit from \u003Ccode\u003EUAuthComponentBase\u003C/code\u003E to use \u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022session-requirement\u0022\u003E3. Session Requirement\u003C/h2\u003E\n\u003Cp\u003E\u003Ccode\u003E[UAuthAuthorize]\u003C/code\u003E now defaults to \u003Ccode\u003ERequireActive = true\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EIf your application intentionally allows authenticated users with a reported inactive session state, explicitly use:\u003C/p\u003E\n\u003Cdiv class=\u0022docs-code-wrapper\u0022\u003E\u003Cdiv class=\u0022docs-code-header\u0022\u003E\u003Cspan class=\u0022docs-code-language\u0022\u003ERazor\u003C/span\u003E\u003Cbutton type=\u0022button\u0022 class=\u0022docs-code-copy\u0022 aria-label=\u0022Copy code\u0022\u003ECopy\u003C/button\u003E\u003C/div\u003E\u003Cpre\u003E\u003Ccode class=\u0022language-razor\u0022\u003E@attribute [UAuthAuthorize(RequireActive = false)]\n\u003C/code\u003E\u003C/pre\u003E\u003C/div\u003E\n\u003Cp\u003EOtherwise, no change is needed.\u003C/p\u003E\n\u003Chr\u003E\n\u003Cp\u003EFor usage examples, see \u003Ca href=\u0022/docs/how-to-guides/protect-a-page\u0022\u003EProtect a Page\u003C/a\u003E.\u003C/p\u003E\n",
+ "Headings": [
+ {
+ "Id": "custom-routers",
+ "Text": "1. Custom Routers",
+ "Level": 0
+ },
+ {
+ "Id": "uauthcomponentbase-overrides",
+ "Text": "2. UAuthComponentBase Overrides",
+ "Level": 0
+ },
+ {
+ "Id": "session-requirement",
+ "Text": "3. Session Requirement",
+ "Level": 0
+ }
+ ],
+ "SourceHash": "27406465426DBB34AD27694EB7C388BBCE987897BBC5B2E241605D76F450B5D6",
+ "BuilderVersion": "1"
+}
\ No newline at end of file