![]() |
VOOZH | about |
dotnet add package Indiko.Blocks.Security.Authentication.ASPNetCore --version 2.8.0
NuGet\Install-Package Indiko.Blocks.Security.Authentication.ASPNetCore -Version 2.8.0
<PackageReference Include="Indiko.Blocks.Security.Authentication.ASPNetCore" Version="2.8.0" />
<PackageVersion Include="Indiko.Blocks.Security.Authentication.ASPNetCore" Version="2.8.0" />Directory.Packages.props
<PackageReference Include="Indiko.Blocks.Security.Authentication.ASPNetCore" />Project file
paket add Indiko.Blocks.Security.Authentication.ASPNetCore --version 2.8.0
#r "nuget: Indiko.Blocks.Security.Authentication.ASPNetCore, 2.8.0"
#:package Indiko.Blocks.Security.Authentication.ASPNetCore@2.8.0
#addin nuget:?package=Indiko.Blocks.Security.Authentication.ASPNetCore&version=2.8.0Install as a Cake Addin
#tool nuget:?package=Indiko.Blocks.Security.Authentication.ASPNetCore&version=2.8.0Install as a Cake Tool
JWT Bearer authentication implementation for ASP.NET Core APIs with token generation and validation.
This package provides complete JWT (JSON Web Token) authentication for ASP.NET Core applications, including token generation, validation, and SignalR hub support.
dotnet add package Indiko.Blocks.Security.Authentication.ASPNetCore
{
"AspNetCoreAuthenticationOptions": {
"Enabled": true,
"Secret": "your-256-bit-secret-key-minimum-32-characters",
"Issuer": "https://api.example.com",
"Audience": "api.example.com",
"ValidateIssuer": true,
"ValidateAudience": true,
"ValidateLifetime": true,
"ValidateIssuerSigningKey": true,
"TokenExpirationMinutes": 60,
"RefreshTokenExpirationDays": 7,
"SignalRHubPath": "/hubs"
}
}
// Authentication is auto-configured via block system
// Just ensure appsettings.json has the configuration above
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
private readonly ITokenProvider _tokenProvider;
private readonly IUserService _userService;
public AuthController(ITokenProvider tokenProvider, IUserService userService)
{
_tokenProvider = tokenProvider;
_userService = userService;
}
[HttpPost("login")]
[AllowAnonymous]
public async Task<IActionResult> Login([FromBody] LoginRequest request)
{
// Validate credentials
var user = await _userService.ValidateCredentialsAsync(
request.Username,
request.Password);
if (user == null)
return Unauthorized(new { message = "Invalid credentials" });
// Create identity user
var identityUser = new IdentityUser
{
UserId = user.Id.ToString(),
Username = user.Username,
Email = user.Email,
Roles = new[] { "User", "Admin" }
};
// Generate tokens
var tokenResponse = await _tokenProvider.GetToken(identityUser);
return Ok(new
{
access_token = tokenResponse.AccessToken,
token_type = "Bearer",
expires_in = 3600,
refresh_token = tokenResponse.RefreshToken
});
}
}
[HttpPost("login-with-claims")]
public async Task<IActionResult> LoginWithClaims([FromBody] LoginRequest request)
{
var user = await _userService.ValidateCredentialsAsync(request.Username, request.Password);
if (user == null) return Unauthorized();
var identityUser = new IdentityUser
{
UserId = user.Id.ToString(),
Username = user.Username,
Email = user.Email,
Roles = user.Roles.ToArray()
};
var customClaims = new Dictionary<string, string>
{
{ "tenant_id", user.TenantId.ToString() },
{ "subscription_tier", user.SubscriptionTier },
{ "permissions", string.Join(",", user.Permissions) }
};
var tokenResponse = await _tokenProvider.GetToken(identityUser, customClaims);
return Ok(tokenResponse);
}
[ApiController]
[Route("api/[controller]")]
[Authorize] // Requires valid JWT token
public class UsersController : ControllerBase
{
[HttpGet]
public IActionResult GetUsers()
{
return Ok(users);
}
[HttpGet("me")]
public IActionResult GetCurrentUser()
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var username = User.FindFirst(ClaimTypes.Name)?.Value;
var email = User.FindFirst(ClaimTypes.Email)?.Value;
return Ok(new { userId, username, email });
}
}
[Authorize(Roles = "Admin")]
[HttpDelete("{id}")]
public IActionResult DeleteUser(Guid id)
{
// Only admins can delete
return NoContent();
}
[Authorize(Roles = "Admin,Moderator")]
[HttpPut("{id}/ban")]
public IActionResult BanUser(Guid id)
{
// Admins or Moderators can ban
return NoContent();
}
// In Startup.cs
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdminRole", policy =>
policy.RequireRole("Admin"));
options.AddPolicy("RequirePremium", policy =>
policy.RequireClaim("subscription_tier", "Premium", "Enterprise"));
options.AddPolicy("MinimumAge", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(18)));
});
// In Controller
[Authorize(Policy = "RequirePremium")]
[HttpGet("premium-content")]
public IActionResult GetPremiumContent()
{
return Ok(premiumContent);
}
The block automatically supports SignalR hub authentication via query strings:
// Client-side JavaScript
const connection = new signalR.HubConnectionBuilder()
.withUrl("/hubs/chat", {
accessTokenFactory: () => localStorage.getItem("access_token")
})
.build();
await connection.start();
[Authorize]
public class ChatHub : Hub
{
public override async Task OnConnectedAsync()
{
var username = Context.User?.Identity?.Name;
Console.WriteLine($"{username} connected");
await base.OnConnectedAsync();
}
public async Task SendMessage(string message)
{
var username = Context.User?.Identity?.Name;
await Clients.All.SendAsync("ReceiveMessage", username, message);
}
}
Tokens are automatically validated on every request to protected endpoints:
ValidateLifetime is trueValidateIssuer is trueValidateAudience is truepublic class TokenValidator
{
private readonly AspNetCoreAuthenticationOptions _options;
public bool ValidateToken(string token, out ClaimsPrincipal principal)
{
var tokenHandler = new JwtSecurityTokenHandler();
principal = null;
try
{
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = _options.ValidateIssuer,
ValidateAudience = _options.ValidateAudience,
ValidateLifetime = _options.ValidateLifetime,
ValidIssuer = _options.Issuer,
ValidAudience = _options.Audience,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_options.Secret))
};
principal = tokenHandler.ValidateToken(token, validationParameters, out _);
return true;
}
catch
{
return false;
}
}
}
// Login
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: 'user', password: 'pass' })
});
const { access_token } = await response.json();
localStorage.setItem('access_token', access_token);
// Protected request
const data = await fetch('/api/users', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('access_token')}`
}
});
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
var response = await client.GetAsync("https://api.example.com/api/users");
[HttpPost("refresh")]
public async Task<IActionResult> RefreshToken([FromBody] RefreshTokenRequest request)
{
// Validate refresh token
var storedToken = await _tokenRepository.GetByTokenAsync(request.RefreshToken);
if (storedToken == null || storedToken.IsExpired)
return Unauthorized(new { message = "Invalid refresh token" });
// Get user
var user = await _userService.GetByIdAsync(storedToken.UserId);
var identityUser = new IdentityUser
{
UserId = user.Id.ToString(),
Username = user.Username,
Email = user.Email,
Roles = user.Roles.ToArray()
};
// Generate new tokens
var tokenResponse = await _tokenProvider.GetToken(identityUser);
// Revoke old refresh token
await _tokenRepository.RevokeAsync(request.RefreshToken);
return Ok(tokenResponse);
}
The block logs detailed authentication events:
Indiko.Blocks.Security.Authentication.AbstractionsMicrosoft.AspNetCore.Authentication.JwtBearerSystem.IdentityModel.Tokens.JwtSee LICENSE file in the repository root.
Indiko.Blocks.Security.Authentication.Abstractions - Authentication abstractionsIndiko.Blocks.Security.AuthenticationProvider.Blazor - Blazor authenticationIndiko.Hosting.Web - Web API hosting| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.8.0 | 99 | 5/22/2026 |
| 2.7.8 | 100 | 5/7/2026 |
| 2.7.7 | 94 | 5/7/2026 |
| 2.7.6 | 107 | 4/23/2026 |
| 2.7.5 | 102 | 4/23/2026 |
| 2.7.4 | 109 | 4/23/2026 |
| 2.7.3 | 112 | 4/23/2026 |
| 2.7.2 | 108 | 4/23/2026 |
| 2.7.1 | 97 | 4/23/2026 |
| 2.7.0 | 96 | 4/23/2026 |
| 2.6.4 | 102 | 4/21/2026 |
| 2.6.3 | 101 | 4/21/2026 |
| 2.6.2 | 100 | 4/21/2026 |
| 2.6.1 | 98 | 4/18/2026 |
| 2.6.0 | 98 | 4/17/2026 |
| 2.5.1 | 104 | 4/14/2026 |
| 2.5.0 | 128 | 3/30/2026 |
| 2.2.18 | 117 | 3/8/2026 |
| 2.2.17 | 106 | 3/8/2026 |
| 2.2.16 | 106 | 3/8/2026 |