Overview
Silky uses JWT (JSON Web Token) for authentication. The gateway validates Bearer tokens from external clients and propagates user identity to downstream services via RpcContext. Internal service-to-service calls can also be secured with RPC tokens.
JWT Module
Installation
<PackageReference Include="Silky.Jwt" Version="3.9.2" />
Module
[DependsOn(
typeof(JwtModule),
typeof(GatewayHostModule)
)]
public class GatewayModule : SilkyModule { }
Configuration
{
"jwt": {
"secret": "your-256-bit-secret-key-at-least-32-characters",
"issuer": "silky-gateway",
"audience": "silky-services",
"expiresIn": 7200
}
}
Issuing a JWT Token
Use IJwtTokenGenerator to issue tokens after authentication:
public class AuthAppService : IAuthAppService, IScopedDependency
{
private readonly IJwtTokenGenerator _tokenGenerator;
public AuthAppService(IJwtTokenGenerator tokenGenerator)
{
_tokenGenerator = tokenGenerator;
}
public async Task<LoginOutput> LoginAsync(LoginInput input)
{
// Validate credentials (omitted for brevity)
var user = await ValidateUserAsync(input.UserName, input.Password);
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.Role, user.Role)
};
var token = _tokenGenerator.GenerateToken(claims);
return new LoginOutput { AccessToken = token, ExpiresIn = 7200 };
}
}
Protecting Service Entries
Use standard ASP.NET Core authorization attributes on service interface methods:
[ServiceRoute]
public interface IOrderAppService
{
// Public — no authentication required
[HttpGet("public/prices")]
Task<PriceOutput> GetPublicPricesAsync();
// Requires authentication
[Authorize]
[HttpGet("{id}")]
Task<OrderOutput> GetAsync(long id);
// Requires specific role
[Authorize(Roles = "Admin")]
[HttpDelete("{id}")]
Task DeleteAsync(long id);
}
Accessing User Identity in Services
User identity propagated through RpcContext is accessible via ICurrentUser:
public class OrderAppService : IOrderAppService, IScopedDependency
{
private readonly ICurrentUser _currentUser;
public OrderAppService(ICurrentUser currentUser)
{
_currentUser = currentUser;
}
public async Task<OrderOutput> GetAsync(long id)
{
var userId = _currentUser.Id;
var userName = _currentUser.UserName;
var roles = _currentUser.Roles;
// ...
}
}
RPC Token Security
Service-to-service calls can be authenticated with an RPC token. The framework validates the token using constant-time comparison to prevent timing attacks:
{
"rpc": {
"token": "your-internal-rpc-token",
"isDisableSsl": false
}
}
Warning
Use a strong, randomly generated rpc.token and rotate it periodically. This token is not related to the JWT used for external clients.
Startup.cs Authentication Registration
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = Configuration["jwt:issuer"],
ValidateAudience = true,
ValidAudience = Configuration["jwt:audience"],
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(Configuration["jwt:secret"])),
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
});
services.AddAuthorization();
}
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
app.UseAuthorization();
// ...
}
