Skip to content

Commit a0f3e10

Browse files
committed
Add authentication endpoints and CORS updates
- Introduced new versioned authentication endpoints for login, logout, and status checks. - Added JWT token handling in the authentication process. - Updated CORS policy to allow multiple origins during development. - Cleaned up unused user endpoint code.
1 parent b254920 commit a0f3e10

3 files changed

Lines changed: 165 additions & 84 deletions

File tree

whateverAPI/Endpoints/AuthEndpoints.cs

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using Asp.Versioning;
1+
using System.Security.Claims;
2+
using Asp.Versioning;
3+
using Microsoft.AspNetCore.Mvc;
24
using whateverAPI.Helpers;
35
using whateverAPI.Models;
46
using whateverAPI.Services;
@@ -9,39 +11,105 @@ public class AuthEndpoints : IEndpoints
911
{
1012
public static void MapEndpoints(IEndpointRouteBuilder app)
1113
{
12-
var apiGroup = app.MapGroup("/api");
13-
var googleAuthGroup2 = app
14-
.MapGroup("/api/auth/google")
15-
.WithTags("Authentication")
16-
.RequireRateLimiting(Helper.AuthPolicy);
17-
var microsoftAuthGroup2 = app
18-
.MapGroup("/api/auth/microsoft")
19-
.WithTags("Authentication")
20-
.RequireRateLimiting(Helper.AuthPolicy);
21-
var facebookAuthGroup2 = app
22-
.MapGroup("/api/auth/facebook")
23-
.WithTags("Authentication")
24-
.RequireRateLimiting(Helper.AuthPolicy);
25-
26-
2714
var microsoftAuthGroup = app.NewVersionedApi()
2815
.MapGroup("/api/v{version:apiVersion}/auth/microsoft")
2916
.WithTags("Authentication")
3017
.HasApiVersion(new ApiVersion(1, 0))
3118
.RequireRateLimiting(Helper.AuthPolicy);
32-
19+
3320
var googleAuthGroup = app.NewVersionedApi()
3421
.MapGroup("/api/v{version:apiVersion}/auth/google")
3522
.WithTags("Authentication")
3623
.HasApiVersion(new ApiVersion(1, 0))
3724
.RequireRateLimiting(Helper.AuthPolicy);
38-
25+
3926
var facebookAuthGroup = app.NewVersionedApi()
4027
.MapGroup("/api/v{version:apiVersion}/auth/facebook")
4128
.WithTags("Authentication")
4229
.HasApiVersion(new ApiVersion(1, 0))
4330
.RequireRateLimiting(Helper.AuthPolicy);
4431

32+
var authGroup = app.NewVersionedApi()
33+
.MapGroup("/api/v{version:apiVersion}/auth")
34+
.WithTags("Authentication")
35+
.HasApiVersion(new ApiVersion(1, 0));
36+
37+
38+
authGroup.MapGet("/status", async Task<IResult> (
39+
HttpContext context,
40+
IJwtTokenService jwtTokenService) =>
41+
{
42+
var token = jwtTokenService.GetToken();
43+
if (string.IsNullOrEmpty(token))
44+
{
45+
return TypedResults.Ok(new { isAuthenticated = false });
46+
}
47+
48+
var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
49+
var email = context.User.FindFirst(ClaimTypes.Email)?.Value;
50+
var name = context.User.FindFirst(ClaimTypes.Name)?.Value;
51+
var role = context.User.FindFirst(ClaimTypes.Role)?.Value;
52+
53+
return TypedResults.Ok(new
54+
{
55+
isAuthenticated = true,
56+
userId,
57+
email,
58+
name,
59+
role
60+
});
61+
})
62+
.WithName("AuthStatus")
63+
.WithDescription("Checks if the user is currently authenticated and returns their basic information")
64+
.WithSummary("Get authentication status")
65+
.WithOpenApi()
66+
.Produces<object>(StatusCodes.Status200OK);
67+
// .RequireAuthorization(Helper.RequireAuthenticatedUser);
68+
69+
70+
authGroup.MapPost("/login", async Task<IResult> (
71+
[FromBody] UserLoginRequest request,
72+
IJwtTokenService jwtTokenService,
73+
HttpContext context) =>
74+
{
75+
var jwtToken =
76+
await jwtTokenService.GenerateToken(Guid.CreateVersion7().ToString(), request.Email, request.Name, "local");
77+
return !string.IsNullOrEmpty(jwtToken)
78+
? TypedResults.Ok(new { request.Email, Token = jwtToken })
79+
: context.CreateUnauthorizedProblem("Invalid credentials provided");
80+
})
81+
.WithName("UserLogin")
82+
.WithDescription("Authenticates a user and returns a JWT token for subsequent requests")
83+
.WithSummary("Login user")
84+
.WithOpenApi()
85+
.Accepts<UserLoginRequest>("application/json")
86+
.Produces<object>(StatusCodes.Status200OK)
87+
.ProducesProblem(StatusCodes.Status401Unauthorized)
88+
.ProducesValidationProblem(StatusCodes.Status400BadRequest)
89+
.AddEndpointFilter<ValidationFilter<UserLoginRequest>>();
90+
91+
92+
// User Logout
93+
authGroup.MapPost("/logout", async Task<IResult> (
94+
[FromServices] IJwtTokenService jwtTokenService,
95+
HttpContext context) =>
96+
{
97+
var token = jwtTokenService.GetToken();
98+
if (string.IsNullOrEmpty(token))
99+
{
100+
return context.CreateUnauthorizedProblem("No valid authentication token found");
101+
}
102+
103+
jwtTokenService.InvalidateToken(token);
104+
return TypedResults.Ok();
105+
})
106+
.WithName("UserLogout")
107+
.WithDescription("Invalidates the current user's JWT token")
108+
.WithSummary("Logout user")
109+
.WithOpenApi()
110+
.Produces(StatusCodes.Status200OK)
111+
.ProducesProblem(StatusCodes.Status401Unauthorized);
112+
45113
// Endpoint to start the OAuth flow
46114
googleAuthGroup.MapGet("/login", async Task<IResult> (
47115
IGoogleAuthService authService,

whateverAPI/Endpoints/UserEndpoints.cs

Lines changed: 44 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,58 +10,55 @@ public class UserEndpoints : IEndpoints
1010
{
1111
public static void MapEndpoints(IEndpointRouteBuilder app)
1212
{
13-
var apiGroup = app.MapGroup("/api");
14-
var userGroup2 = apiGroup.MapGroup("/user").WithTags("User");
15-
1613
var userGroup = app.NewVersionedApi()
1714
.MapGroup("/api/v{version:apiVersion}/user")
1815
.WithTags("User")
1916
.HasApiVersion(new ApiVersion(1, 0))
20-
.RequireRateLimiting(Helper.GlobalPolicy);
21-
22-
23-
// User Login
24-
userGroup.MapPost("/login", async Task<IResult> (
25-
[FromBody] UserLoginRequest request,
26-
IJwtTokenService jwtTokenService,
27-
HttpContext context) =>
28-
{
29-
var jwtToken =
30-
await jwtTokenService.GenerateToken(Guid.CreateVersion7().ToString(), request.Email, request.Name, "local");
31-
return !string.IsNullOrEmpty(jwtToken)
32-
? TypedResults.Ok(new { request.Email, Token = jwtToken })
33-
: context.CreateUnauthorizedProblem("Invalid credentials provided");
34-
})
35-
.WithName("UserLogin")
36-
.WithDescription("Authenticates a user and returns a JWT token for subsequent requests")
37-
.WithSummary("Login user")
38-
.WithOpenApi()
39-
.Accepts<UserLoginRequest>("application/json")
40-
.Produces<object>(StatusCodes.Status200OK)
41-
.ProducesProblem(StatusCodes.Status401Unauthorized)
42-
.ProducesValidationProblem(StatusCodes.Status400BadRequest)
43-
.AddEndpointFilter<ValidationFilter<UserLoginRequest>>();
17+
.RequireRateLimiting(Helper.AuthPolicy);
4418

4519

46-
// User Logout
47-
userGroup.MapPost("/logout", async Task<IResult> (
48-
[FromServices] IJwtTokenService jwtTokenService,
49-
HttpContext context) =>
50-
{
51-
var token = jwtTokenService.GetToken();
52-
if (string.IsNullOrEmpty(token))
53-
{
54-
return context.CreateUnauthorizedProblem("No valid authentication token found");
55-
}
56-
57-
jwtTokenService.InvalidateToken(token);
58-
return TypedResults.Ok();
59-
})
60-
.WithName("UserLogout")
61-
.WithDescription("Invalidates the current user's JWT token")
62-
.WithSummary("Logout user")
63-
.WithOpenApi()
64-
.Produces(StatusCodes.Status200OK)
65-
.ProducesProblem(StatusCodes.Status401Unauthorized);
20+
// User Login
21+
// userGroup.MapPost("/login", async Task<IResult> (
22+
// [FromBody] UserLoginRequest request,
23+
// IJwtTokenService jwtTokenService,
24+
// HttpContext context) =>
25+
// {
26+
// var jwtToken =
27+
// await jwtTokenService.GenerateToken(Guid.CreateVersion7().ToString(), request.Email, request.Name, "local");
28+
// return !string.IsNullOrEmpty(jwtToken)
29+
// ? TypedResults.Ok(new { request.Email, Token = jwtToken })
30+
// : context.CreateUnauthorizedProblem("Invalid credentials provided");
31+
// })
32+
// .WithName("UserLogin")
33+
// .WithDescription("Authenticates a user and returns a JWT token for subsequent requests")
34+
// .WithSummary("Login user")
35+
// .WithOpenApi()
36+
// .Accepts<UserLoginRequest>("application/json")
37+
// .Produces<object>(StatusCodes.Status200OK)
38+
// .ProducesProblem(StatusCodes.Status401Unauthorized)
39+
// .ProducesValidationProblem(StatusCodes.Status400BadRequest)
40+
// .AddEndpointFilter<ValidationFilter<UserLoginRequest>>();
41+
//
42+
//
43+
// // User Logout
44+
// userGroup.MapPost("/logout", async Task<IResult> (
45+
// [FromServices] IJwtTokenService jwtTokenService,
46+
// HttpContext context) =>
47+
// {
48+
// var token = jwtTokenService.GetToken();
49+
// if (string.IsNullOrEmpty(token))
50+
// {
51+
// return context.CreateUnauthorizedProblem("No valid authentication token found");
52+
// }
53+
//
54+
// jwtTokenService.InvalidateToken(token);
55+
// return TypedResults.Ok();
56+
// })
57+
// .WithName("UserLogout")
58+
// .WithDescription("Invalidates the current user's JWT token")
59+
// .WithSummary("Logout user")
60+
// .WithOpenApi()
61+
// .Produces(StatusCodes.Status200OK)
62+
// .ProducesProblem(StatusCodes.Status401Unauthorized);
6663
}
6764
}

whateverAPI/Program.cs

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,34 @@ await builder.Services
2828
.AddDbContext<AppDbContext>(options =>
2929
options.UseNpgsql(builder.Configuration.GetConnectionString(Helper.DefaultConnection), o =>
3030
o.EnableRetryOnFailure()).EnableDetailedErrors().EnableSensitiveDataLogging())
31-
// .AddCors(options =>
32-
// {
33-
// var corsOptions = builder.Configuration.GetSection(nameof(CorsOptions)).Get<CorsOptions>();
34-
// options.AddPolicy(Helper.DefaultPolicy, policyBuilder =>
35-
// {
36-
// if (builder.Environment.IsDevelopment())
37-
// {
38-
// policyBuilder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
39-
// }
40-
// else
41-
// {
42-
// policyBuilder
43-
// .WithOrigins(corsOptions?.AllowedOrigins ?? ["https://whatever-roan-five.vercel.app"])
44-
// .WithMethods(corsOptions?.AllowedMethods ?? ["GET", "POST", "PUT", "DELETE", "OPTIONS"])
45-
// .WithHeaders(corsOptions?.AllowedHeaders ?? ["*"])
46-
// .AllowCredentials();
47-
// }
48-
// });
49-
// })
31+
.AddCors(options =>
32+
{
33+
var corsOptions = builder.Configuration.GetSection(nameof(CorsOptions)).Get<CorsOptions>();
34+
options.AddPolicy(Helper.DefaultPolicy, policyBuilder =>
35+
{
36+
if (builder.Environment.IsDevelopment())
37+
{
38+
policyBuilder
39+
.WithOrigins(
40+
"https://kzmlzzhzbnsjrj9w0s3t.lite.vusercontent.net",
41+
"https://v0.dev/chat/joke-app-requirements-etJhPhgl5vq",
42+
"http://localhost:3000",
43+
"http://localhost:3001",
44+
"https://localhost:3000"
45+
)
46+
.AllowAnyMethod()
47+
.AllowAnyHeader()
48+
.AllowCredentials(); }
49+
else
50+
{
51+
policyBuilder
52+
.WithOrigins(corsOptions?.AllowedOrigins ?? ["https://whatever-roan-five.vercel.app"])
53+
.WithMethods(corsOptions?.AllowedMethods ?? ["GET", "POST", "PUT", "DELETE", "OPTIONS"])
54+
.WithHeaders(corsOptions?.AllowedHeaders ?? ["*"])
55+
.AllowCredentials();
56+
}
57+
});
58+
})
5059
.AddApplicationInsightsTelemetry()
5160
.AddProblemDetails(options =>
5261
{
@@ -167,6 +176,13 @@ await builder.Services
167176
.UseStaticFiles()
168177
.UseAuthentication()
169178
.UseAuthorization();
179+
180+
app.UseCors(Helper.DefaultPolicy);
181+
182+
// app.UseCors(policyBuilder =>
183+
// {
184+
// policyBuilder.AllowAnyOrigin();
185+
// });
170186
// .UseCors(Helper.DefaultPolicy);
171187

172188
await app.InitializeDatabaseRetryAsync();

0 commit comments

Comments
 (0)