diff --git a/blazor-toc.html b/blazor-toc.html index 5bfb8131d8..5476cedb12 100644 --- a/blazor-toc.html +++ b/blazor-toc.html @@ -398,6 +398,9 @@
Only users in the Admin group can access this page.
+``` + +> Group creation and behavior are documented in AWS; using roles in Blazor/ASP.NET Core follows Microsoft's standard policy system. + +## Prerequisites + +* .NET SDK (version 8.0 or later; this guide uses .NET 10.0) +* Visual Studio 2022 or VS Code + C# Dev Kit +* AWS Account with permission to manage Cognito + +## Integrating Cognito with Blazor + +Configure OpenID Connect with the Cognito Hosted UI (Authorization Code + PKCE), which Microsoft's docs show for any OIDC provider in Blazor Web Apps. + +### Create a Blazor Server Project + +If you already have a Blazor project, proceed to the **Create a Cognito User Pool** section. Otherwise, create one using Syncfusion Blazor Server getting started guides. + +* [Server](https://blazor.syncfusion.com/documentation/getting-started/blazor-server-side-visual-studio) + +### Create a Cognito User Pool + +Before building the Blazor app, set up an AWS Cognito User Pool: + +1. Go to **AWS Management Console** > **Amazon Cognito**. +2. Click **Create user pool**. +3. Choose authentication method: **Email** or **Phone number** (or both). +4. Continue through the setup wizard. Accept defaults or customize as needed. +5. Note the **User pool ID** and **User pool name**. +6. Go to **App integration** > **App clients** (or **App clients and analytics**). +7. Click **Create app client**: + - **App type:** Choose **Public client** (for PKCE without a secret). + - **Client name:** (for example, `MyBlazorServer`). + - **Authentication flows:** Ensure **Authorization code flow** is selected. + - Under **Allowed redirect URIs**, add: `https://localhost:7000/signin` (adjust port if different; check `Properties/launchSettings.json`). + - Under **Allowed sign-out URIs**, add: `https://localhost:7000/signout`. +8. Create the app client and note the **Client ID**. +9. In **Domain name** (under App integration), create a custom domain or use the Cognito-provided sub-domain. Note the full Hosted UI domain: + ``` + https://your-domain.auth.{region}.amazoncognito.com + ``` + +You now have the values to add to `appsettings.json`. + +[Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools.html) + +### Update `appsettings.json` + +This stores your Cognito Hosted UI domain and app client ID so the app can read them at startup. The `Authority` is the base URL of your Cognito User Pool domain, and `ClientId` identifies your web app in Cognito. Keep these out of code to simplify environment changes. Replace the placeholders with your actual Cognito values. + +{% tabs %} +{% highlight %} + +{ + "Cognito": { + "Authority": "https://your-domain.auth.ap-south-1.amazoncognito.com", //Replace **ap-south-1** with your AWS region (e.g., us-east-1, eu-west-1). Check your Cognito User Pool details page for the correct region. + "ClientId": "YOUR_APP_CLIENT_ID" + }, + "AllowedHosts": "*" +} + +{% endhighlight %} +{% endtabs %} + +N> This sample uses Authorization Code + PKCE with a public client (no client secret). If you created a confidential client, add ClientSecret to configuration and set `options.ClientSecret` in the OIDC options. + +### `Program.cs` (OIDC + Cookies) + +This wires OpenID Connect against Cognito’s Hosted UI using the Authorization Code flow (PKCE) and uses cookies for the authenticated session. `SaveTokens = true` keeps ID/Access tokens available for downstream API calls. `RoleClaimType = "cognito:groups"` turns Cognito groups into ASP.NET Core roles. The `/sign-in` and `/sign-out` endpoints start and end the hosted login flow. + +{% tabs %} +{% highlight cs %} + +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.OpenIdConnect; +using Microsoft.IdentityModel.Tokens; +using Syncfusion.Blazor; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +builder.Services.AddRazorPages(); +builder.Services.AddServerSideBlazor(); +builder.Services.AddSyncfusionBlazor(); +builder.Services.AddHttpContextAccessor(); + +var cognitoDomain = builder.Configuration["Cognito:Authority"]; +var clientId = builder.Configuration["Cognito:ClientId"]; + +bool TryGetAuthorityUri(string? authority, out Uri? uri) +{ + uri = null; + if (string.IsNullOrWhiteSpace(authority)) return false; + if (authority.Contains("your-domain")) return false; + // Require a valid absolute URI (for example, https://your-domain.auth.region.amazoncognito.com) + if (!Uri.TryCreate(authority, UriKind.Absolute, out var parsed)) return false; + // only http or https are acceptable here for dev detection; production will require https + if (parsed.Scheme != Uri.UriSchemeHttp && parsed.Scheme != Uri.UriSchemeHttps) return false; + uri = parsed; + return true; +} + +// Decide whether to enable OIDC (Cognito) or fall back to cookie-only auth in Development. +bool useOidc = false; +if (!string.IsNullOrWhiteSpace(cognitoDomain) + && !cognitoDomain.Contains("your-domain") + && !string.Equals(cognitoDomain, "Test user", StringComparison.OrdinalIgnoreCase) + && !string.IsNullOrWhiteSpace(clientId) + && !clientId.Contains("YOUR_APP_CLIENT_ID")) +{ + if (Uri.TryCreate(cognitoDomain, UriKind.Absolute, out var u)) + { + // Allow only HTTPS authority generally + if (string.Equals(u.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) + { + useOidc = true; + } + else if (string.Equals(u.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) + && !u.IsLoopback + && builder.Environment.IsDevelopment()) + { + // Allow non-local http authority in development (rare) + useOidc = true; + } + } +} + +if (useOidc) +{ + builder.Services.AddAuthentication(options => + { + options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; + }) + .AddCookie() + .AddOpenIdConnect(options => + { + options.Authority = cognitoDomain!; // Cognito Hosted UI domain + options.ClientId = clientId!; // App client ID + options.ResponseType = "code"; // Authorization Code + PKCE + options.SaveTokens = true; // Persist ID/Access tokens in session for use in API calls or as Bearer tokens + + // If the authority is http and we're in Development, allow non-https metadata. + options.RequireHttpsMetadata = !(builder.Environment.IsDevelopment() + && Uri.TryCreate(cognitoDomain, UriKind.Absolute, out var uu) + && string.Equals(uu.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase)); + + options.Scope.Clear(); + options.Scope.Add("openid"); + options.Scope.Add("email"); + options.Scope.Add("profile"); + + options.TokenValidationParameters = new TokenValidationParameters + { + NameClaimType = "cognito:username", + RoleClaimType = "cognito:groups" + }; + + options.CallbackPath = "/signin-oidc"; + options.SignedOutCallbackPath = "/signout-callback-oidc"; + }); +} +else +{ + // Cookie-only auth for development/test when Cognito isn't configured. + builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) + .AddCookie(); +} + +// In Production require a valid HTTPS Cognito authority. +if (!builder.Environment.IsDevelopment()) +{ + if (!TryGetAuthorityUri(cognitoDomain, out var prodUri) || prodUri!.Scheme != Uri.UriSchemeHttps || string.IsNullOrWhiteSpace(clientId) || clientId.Contains("YOUR_APP_CLIENT_ID")) + { + throw new InvalidOperationException( + "Cognito configuration is invalid. Set 'Cognito:Authority' to your Cognito Hosted UI domain (https://Please sign in to view the grid.
+ Sign in +