Files
promiscuity/microservices/AuthApi/Program.cs
T
admin 94ffe6e7b7
Deploy Promiscuity Auth API / deploy (push) Successful in 1m29s
k8s smoke test / test (push) Successful in 20s
Add versioned legal consent to authentication
2026-07-20 02:16:02 -05:00

111 lines
3.8 KiB
C#

using AuthApi.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Security.Claims;
using System.Text;
using System.Threading.RateLimiting;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// DI
builder.Services.AddSingleton<UserService>();
builder.Services.AddSingleton<BlacklistService>();
builder.Services.AddSingleton<SteamAuthTransactionService>();
builder.Services.AddSingleton<JwtTokenService>();
builder.Services.AddSingleton<SteamOpenIdService>();
builder.Services.AddSingleton<LegalPolicy>();
builder.Services.AddHttpClient();
builder.Services.AddRateLimiter(options =>
{
static RateLimitPartition<string> Policy(HttpContext context, int permits) =>
RateLimitPartition.GetFixedWindowLimiter(
context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
_ => new FixedWindowRateLimiterOptions
{
PermitLimit = permits,
Window = TimeSpan.FromMinutes(1),
QueueLimit = 0
});
options.AddPolicy("steam-start", context => Policy(context, 10));
options.AddPolicy("steam-poll", context => Policy(context, 120));
options.AddPolicy("steam-complete", context => Policy(context, 20));
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
});
// Swagger + JWT auth in Swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Auth API", Version = "v1" });
c.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT",
Description = "Paste your access token here (no 'Bearer ' prefix needed)."
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{ Type = ReferenceType.SecurityScheme, Id = "bearerAuth" }
},
Array.Empty<string>()
}
});
});
// AuthN/JWT
var cfg = builder.Configuration;
var jwtKey = cfg["Jwt:Key"] ?? throw new Exception("Jwt:Key missing");
var issuer = cfg["Jwt:Issuer"] ?? "GameAuthApi";
var aud = cfg["Jwt:Audience"] ?? issuer;
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true, ValidIssuer = issuer,
ValidateAudience = true, ValidAudience = aud,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey)),
ValidateLifetime = true,
ClockSkew = TimeSpan.FromSeconds(30)
};
o.Events = new JwtBearerEvents
{
OnTokenValidated = async ctx =>
{
var jti = ctx.Principal?.FindFirstValue(System.IdentityModel.Tokens.Jwt.JwtRegisteredClaimNames.Jti);
if (!string.IsNullOrEmpty(jti))
{
var bl = ctx.HttpContext.RequestServices.GetRequiredService<BlacklistService>();
if (await bl.IsBlacklistedAsync(jti)) ctx.Fail("Token revoked");
}
}
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.MapGet("/healthz", () => Results.Ok("ok"));
app.UseSwagger();
app.UseSwaggerUI(o =>
{
o.SwaggerEndpoint("/swagger/v1/swagger.json", "Auth API v1");
o.RoutePrefix = "swagger";
});
app.UseRouting();
app.UseRateLimiter();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();