diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Documentation/AuthProxyDocumentFilter.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Documentation/AuthProxyDocumentFilter.cs
new file mode 100644
index 00000000..8cb9c6c0
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Documentation/AuthProxyDocumentFilter.cs
@@ -0,0 +1,123 @@
+using EnvelopeGenerator.API.Models;
+using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Models;
+using Swashbuckle.AspNetCore.SwaggerGen;
+
+namespace EnvelopeGenerator.API.Documentation;
+
+///
+///
+///
+public sealed class AuthProxyDocumentFilter : IDocumentFilter
+{
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
+ {
+ AddLoginOperation(swaggerDoc, context);
+ AddEnvelopeReceiverLoginOperation(swaggerDoc, context);
+ }
+
+ private static void AddLoginOperation(OpenApiDocument swaggerDoc, DocumentFilterContext context)
+ {
+ const string path = "/api/auth";
+
+ var loginSchema = context.SchemaGenerator.GenerateSchema(typeof(Login), context.SchemaRepository);
+ var loginExample = new OpenApiObject
+ {
+ ["password"] = new OpenApiString(""),
+ ["username"] = new OpenApiString("")
+ };
+
+ var operation = new OpenApiOperation
+ {
+ Summary = "Proxy login (auth-hub)",
+ Description = "Proxies the request to the auth service. Add query parameter `cookie=true|false`.",
+ Tags = [new() { Name = "Auth" }],
+ Parameters =
+ {
+ new OpenApiParameter
+ {
+ Name = "cookie",
+ In = ParameterLocation.Query,
+ Required = false,
+ Schema = new OpenApiSchema { Type = "boolean", Default = new OpenApiBoolean(true) },
+ Example = new OpenApiBoolean(true),
+ Description = "If true, auth service sets the auth cookie."
+ }
+ },
+ RequestBody = new OpenApiRequestBody
+ {
+ Required = true,
+ Content =
+ {
+ ["application/json"] = new OpenApiMediaType { Schema = loginSchema, Example = loginExample },
+ ["multipart/form-data"] = new OpenApiMediaType { Schema = loginSchema, Example = loginExample }
+ }
+ },
+ Responses =
+ {
+ ["200"] = new OpenApiResponse { Description = "OK (proxied response)" },
+ ["401"] = new OpenApiResponse { Description = "Unauthorized" }
+ }
+ };
+
+ swaggerDoc.Paths[path] = new OpenApiPathItem
+ {
+ Operations =
+ {
+ [OperationType.Post] = operation
+ }
+ };
+ }
+
+ private static void AddEnvelopeReceiverLoginOperation(OpenApiDocument swaggerDoc, DocumentFilterContext context)
+ {
+ const string path = "/api/Auth/envelope-receiver/{key}";
+
+ var bodySchema = context.SchemaGenerator.GenerateSchema(typeof(EnvelopeReceiverLogin), context.SchemaRepository);
+
+ var operation = new OpenApiOperation
+ {
+ Summary = "Envelope receiver login (auth-hub proxy)",
+ Description = "Proxies the envelope receiver login to the auth service. " +
+ "The `cookie` query parameter is always forwarded as `true` so the auth service sets the per-envelope cookie automatically.",
+ Tags = [new() { Name = "Auth" }],
+ Parameters =
+ {
+ new OpenApiParameter
+ {
+ Name = "key",
+ In = ParameterLocation.Path,
+ Required = true,
+ Schema = new OpenApiSchema { Type = "string" },
+ Description = "The unique envelope receiver key."
+ }
+ },
+ RequestBody = new OpenApiRequestBody
+ {
+ Required = false,
+ Content =
+ {
+ ["multipart/form-data"] = new OpenApiMediaType { Schema = bodySchema }
+ }
+ },
+ Responses =
+ {
+ ["200"] = new OpenApiResponse { Description = "OK – per-envelope cookie set by auth service." },
+ ["401"] = new OpenApiResponse { Description = "Unauthorized – invalid or missing access code." }
+ }
+ };
+
+ swaggerDoc.Paths[path] = new OpenApiPathItem
+ {
+ Operations =
+ {
+ [OperationType.Post] = operation
+ }
+ };
+ }
+}
\ No newline at end of file