Phase 2: Authentication scaffolding

- Add JWT Bearer auth to ASP.NET (authority/audience from AUTH__AUTHORITY / AUTH__AUDIENCE config)
- Add KnownUserMiddleware: upserts KnownUser and resolves pending shares on each authenticated request
- Add MeController as a guarded test endpoint (/api/me)
- Add oidc-client-ts + react-router-dom to client
- Create AuthContext/AuthProvider with login, logout, token storage
- Create AuthGuard component protecting all budget routes
- Add stub /callback page for OIDC redirect handling
- Wire up all routes in App.tsx with SPA routing structure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Spencer Twaddle
2026-04-25 07:54:21 -05:00
parent d788dfea03
commit ae21da6a81
16 changed files with 330 additions and 119 deletions
+23
View File
@@ -1,5 +1,8 @@
using Budget.Api.Data;
using Budget.Api.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
var builder = WebApplication.CreateBuilder(args);
@@ -11,6 +14,21 @@ var connStr = builder.Configuration.GetConnectionString("DefaultConnection")
$"Password={builder.Configuration["POSTGRES_PASSWORD"] ?? "changeme"}";
builder.Services.AddDbContext<AppDbContext>(opt => opt.UseNpgsql(connStr));
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = builder.Configuration["AUTH__AUTHORITY"];
options.Audience = builder.Configuration["AUTH__AUDIENCE"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
};
});
builder.Services.AddAuthorization();
builder.Services.AddControllers();
var app = builder.Build();
@@ -18,6 +36,11 @@ var app = builder.Build();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<KnownUserMiddleware>();
app.MapControllers();
app.MapFallbackToFile("index.html");