Dark Mode

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Latest commit

History

History
202 lines (163 loc) * 5.45 KB

api-authentication.md

File metadata and controls

202 lines (163 loc) * 5.45 KB

API Authentication

This document describes how to implement API authentication using the NETCore.Keycloak.Client library. The library provides JWT Bearer token authentication with Keycloak, including role claim transformation and flexible configuration options.

Setup

Basic Configuration

Add Keycloak authentication to your services with the following configuration:

services.AddKeycloakAuthentication(
authenticationScheme: "Bearer", // Optional, defaults to "Bearer"
keycloakConfig: options =>
{
options.Url = "http://localhost:8080/"; // Keycloak base URL
options.Issuer = "http://localhost:8080/"; // Keycloak issuer URL (usually same as base URL)
options.Realm = "your-realm"; // Your Keycloak realm
options.ClientId = "your-client"; // Your client ID
options.ClientSecret = "your-client-secret"; // Your client secret
options.RolesSource = KcRolesClaimSource.Realm; // Where to source role claims from
options.RoleClaimType = "roles"; // Claim type for roles
});

JWT Bearer Options

You can customize the JWT Bearer options:

services.AddKeycloakAuthentication(
"Bearer",
keycloakConfig: options => { /* ... */ },
configureOptions: bearerOptions =>
{
bearerOptions.RequireHttpsMetadata = false; // For development only
bearerOptions.SaveToken = true;
bearerOptions.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true
};
});

Role Claims Transformation

The library includes a KcRolesClaimsTransformer that transforms Keycloak role claims into a format suitable for your application:

public class KcRolesClaimsTransformer : IClaimsTransformation
{
private readonly string _roleClaimType;
private readonly KcRolesClaimSource _roleSource;
private readonly string _audience;

public KcRolesClaimsTransformer(
string roleClaimType,
KcRolesClaimSource roleSource,
string audience)
{
_roleClaimType = roleClaimType;
_roleSource = roleSource;
_audience = audience;
}

public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
// Transforms Keycloak role claims based on the configured source
// Returns a new ClaimsPrincipal with transformed claims
}
}

Role Claim Sources

You can configure where role claims are sourced from using KcRolesClaimSource:

  • Realm: Use realm-level roles
  • ResourceAccess: Use client-level roles from resource_access claim
  • Both: Use both realm and client-level roles

Configuration Options

The KcAuthenticationConfiguration class provides the following options:

public class KcAuthenticationConfiguration
{
// Base URL of your Keycloak server
public string Url { get; set; }

// Issuer URL (usually same as base URL)
public string Issuer { get; set; }

// Your Keycloak realm name
public string Realm { get; set; }

// Client ID for authentication
public string ClientId { get; set; }

// Client secret (if required)
public string ClientSecret { get; set; }

// Source for role claims
public KcRolesClaimSource RolesSource { get; set; }

// Claim type for roles
public string RoleClaimType { get; set; }

// JWT validation parameters
public TokenValidationParameters ValidationParameters { get; set; }
}

Usage Examples

Protecting API Endpoints

[ApiController]
[Route("api/[controller]")]
[Authorize] // Requires valid JWT token
public class OrdersController : ControllerBase
{
[HttpGet]
[Authorize(Roles = "orders-viewer")] // Requires specific role
public IActionResult GetOrders()
{
return Ok();
}

[HttpPost]
[Authorize(Roles = "orders-creator")]
public IActionResult CreateOrder()
{
return Ok();
}
}

Accessing Claims

[ApiController]
[Authorize]
public class UserController : ControllerBase
{
[HttpGet("profile")]
public IActionResult GetProfile()
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var roles = User.FindAll(_roleClaimType).Select(c => c.Value);

return Ok(new
{
UserId = userId,
Roles = roles
});
}
}

Error Handling

The authentication middleware handles various error scenarios:

  1. Token Validation Errors:

    • Invalid token format
    • Expired tokens
    • Invalid signature
    • Wrong issuer or audience
  2. Role Claim Errors:

    • Missing role claims
    • Invalid role claim format
    • Role source not found

Example error handling middleware:

app.UseExceptionHandler(builder =>
{
builder.Run(async context =>
{
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error?.Error is SecurityTokenException)
{
context.Response.StatusCode = 401;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(
JsonSerializer.Serialize(new
{
Error = "Invalid token",
Message = "The provided authentication token is invalid or expired"
}));
}
});
});