diff --git a/Applications/Backend/Source/HttpsRichardy.Federation.Domain/Errors/AuthenticationErrors.cs b/Applications/Backend/Source/HttpsRichardy.Federation.Domain/Errors/AuthenticationErrors.cs index 87bad49..4ec44e6 100644 --- a/Applications/Backend/Source/HttpsRichardy.Federation.Domain/Errors/AuthenticationErrors.cs +++ b/Applications/Backend/Source/HttpsRichardy.Federation.Domain/Errors/AuthenticationErrors.cs @@ -17,6 +17,11 @@ public static class AuthenticationErrors Description: "The token signature is invalid." ); + public static readonly Error InvalidIssuer = new( + Code: "#ERROR-1A9C3", + Description: "The token issuer is invalid." + ); + public static readonly Error InvalidRefreshToken = new( Code: "#ERROR-2C0D9", Description: "The provided refresh token is invalid, expired, or has already been used." diff --git a/Applications/Backend/Source/HttpsRichardy.Federation.WebApi/Constants/Authentication.cs b/Applications/Backend/Source/HttpsRichardy.Federation.WebApi/Constants/Authentication.cs index d0fc937..5952cb7 100644 --- a/Applications/Backend/Source/HttpsRichardy.Federation.WebApi/Constants/Authentication.cs +++ b/Applications/Backend/Source/HttpsRichardy.Federation.WebApi/Constants/Authentication.cs @@ -26,6 +26,31 @@ public static class Authentication return context.Response.WriteAsync(JsonSerializer.Serialize(AuthenticationErrors.InvalidTokenFormat, _serializer)); }, + OnTokenValidated = context => + { + var request = context.HttpContext.Request; + if (context.SecurityToken is not Microsoft.IdentityModel.JsonWebTokens.JsonWebToken token) + { + context.HttpContext.Items["authentication.error"] = AuthenticationErrors.InvalidTokenFormat; + context.Fail("The token format is invalid or the token is malformed."); + + return Task.CompletedTask; + } + + var expectedIssuer = $"{request.Scheme}://{request.Host}".TrimEnd('/'); + var actualIssuer = token.Issuer?.TrimEnd('/'); + + if (!string.Equals(actualIssuer, expectedIssuer, StringComparison.OrdinalIgnoreCase)) + { + context.HttpContext.Items["authentication.error"] = AuthenticationErrors.InvalidIssuer; + context.Fail("The token issuer is invalid."); + + return Task.CompletedTask; + } + + return Task.CompletedTask; + }, + OnChallenge = context => { context.HandleResponse(); @@ -36,7 +61,11 @@ public static class Authentication context.Response.StatusCode = StatusCodes.Status401Unauthorized; context.Response.ContentType = MediaTypeNames.Application.Json; - return context.Response.WriteAsync(JsonSerializer.Serialize(AuthenticationErrors.Unauthenticated, _serializer)); + var error = context.HttpContext.Items["authentication.error"] as Error + ?? AuthenticationErrors.Unauthenticated; + + return context.Response.WriteAsync(JsonSerializer.Serialize(error, _serializer)); } }; -} \ No newline at end of file +} +