Skip to main content

Discussion: Understanding TideCloak in CSharp

This page explains what happens end‑to‑end when you wire ASP.NET Core to TideCloak via OpenID Connect.


1) Browser sign‑in (Authorization Code flow)​

  1. Your app calls Challenge(...) with the OpenID Connect scheme.
  2. The user is redirected to TideCloak (Keycloak) to authenticate.
  3. TideCloak redirects back to /signin-oidc with an authorization code.
  4. The OpenID Connect handler exchanges the code for ID/Access tokens and issues an auth cookie for your site.
  5. You now have claims such as preferred_username, email, and an ID token stored (if SaveTokens = true).

APIs: for APIs, prefer AddJwtBearer so requests carry a bearer token instead of cookies.


2) Claims, roles, and policies​

  • Realm roles arrive under realm_access.roles in the access token.
  • Client roles arrive under resource_access.<clientId>.roles.
  • Map roles to ClaimTypes.Role and set TokenValidationParameters.RoleClaimType = "role" (or "roles") so [Authorize(Roles="admin")] works.

You can add an event to copy roles from the token JSON into role claims during authentication.

.AddOpenIdConnect(options => {
// ... authority, clientId, etc.
options.Events = new OpenIdConnectEvents {
OnTokenValidated = ctx => {
var identity = (System.Security.Claims.ClaimsIdentity)ctx.Principal!.Identity!;
// Example: ensure Name is set
identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Name,
identity.FindFirst("preferred_username")?.Value ?? identity.Name ?? "user"));
return System.Threading.Tasks.Task.CompletedTask;
}
};
});

3) Cookies vs JWT (when to use which)​

  • Cookie auth (shown in tutorials) is perfect for MVC/Razor Pages sites.
  • JWT bearer is ideal for APIs and SPAs that call your API:
builder.Services.AddAuthentication().AddJwtBearer("bearer", o => {
o.Authority = "http://localhost:8080/realms/myrealm";
o.Audience = "myclient";
o.RequireHttpsMetadata = false; // dev only
});
app.MapGet("/api/me", [Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes="bearer")] (System.Security.Claims.ClaimsPrincipal user) => Results.Ok(new { sub = user.FindFirst("sub")?.Value }));

You can run both in the same app: cookie for site pages, bearer for API endpoints.


4) Redirect URIs & common pitfalls​

  • Add your app's callback URL in TideCloak client (e.g. http://localhost:8000/signin-oidc).
  • If you change the site base URL or run behind IIS/Reverse proxy, update the client settings & ForwardedHeadersOptions so OIDC callback URIs match.
  • In production: set RequireHttpsMetadata = true and use HTTPS everywhere.

5) Protecting pages and APIs​

  • Use [Authorize] on controllers/pages.
  • Gate Razor UI fragments with User.Identity.IsAuthenticated.
  • Use policies to check specific roles/claims:
builder.Services.AddAuthorization(options => {
options.AddPolicy("RequireAdmin", p => p.RequireRole("admin"));
});
// [Authorize(Policy = "RequireAdmin")]

6) Logout​

SignOut with both cookie and OIDC schemes. For full single‑sign‑out, configure Keycloak's end‑session endpoint in OpenIdConnectOptions (optional).


7) Hosting on IIS​

  • Install the ASP.NET Core Hosting Bundle on the server.
  • Publish with dotnet publish -c Release and point IIS site/app to the publish folder.
  • If pairing WebForms + Core, treat Core as a sub‑application under the same site (see WebForms tutorial).

8) Security checklist (prod)​

  • RequireHttpsMetadata = true
  • Enforce HTTPS redirection and HSTS
  • Validate issuer/audience if you add JwtBearer
  • Rotate client secrets; limit scopes to what you need