using System.Linq; using System.Security.Claims; using System.IdentityModel.Tokens.Jwt; using AS400API.Auth; using AS400API.Configuration; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; namespace AS400API.Endpoints; public static class AuthEndpoints { public static RouteGroupBuilder MapAuthEndpoints(this RouteGroupBuilder group) { group.MapPost("/v1/auth/login", async Task (LoginRequest request, DemoUserStore userStore, TokenService tokenService, JwtOptions jwtOptions) => { if (request is null || string.IsNullOrWhiteSpace(request.Username) || string.IsNullOrWhiteSpace(request.Password)) { return Results.BadRequest(new { error = "Username and password are required." }); } var user = await userStore.FindByNameAsync(request.Username); if (user is null || !userStore.ValidateCredentials(user, request.Password)) { return Results.Unauthorized(); } var accessToken = tokenService.CreateToken(user); return Results.Ok(new LoginResponse(accessToken, jwtOptions.AccessTokenLifetimeMinutes * 60, "Bearer", user.Roles)); }) .AllowAnonymous() .WithSummary("Exchange credentials for a JWT access token") .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status401Unauthorized); group.MapGet("/v1/users/me", (ClaimsPrincipal user) => { var username = user.Identity?.Name ?? user.FindFirstValue(JwtRegisteredClaimNames.Sub) ?? "unknown"; var roles = user.FindAll(ClaimTypes.Role).Select(r => r.Value).ToArray(); return Results.Ok(new { username, roles }); }) .RequireAuthorization() .WithSummary("Returns the current user's profile from the access token"); return group; } }