@@ -5,6 +5,7 @@ import akka.http.scaladsl.server.Directives._
55import akka .http .scaladsl .server .Route
66import app .softnetwork .serialization .commonFormats
77import org .json4s .Formats
8+ import sttp .model .headers .WWWAuthenticateChallenge
89import sttp .model .{HeaderNames , StatusCode , Uri }
910import sttp .tapir .EndpointOutput .OneOf
1011import sttp .tapir .server .PartialServerEndpointWithSecurityOutput
@@ -70,6 +71,23 @@ object ApiErrors extends SchemaDerivation with TapirJson4s {
7071 }
7172 )(_.left.get.toString())
7273
74+ case class UnauthorizedWithChallenge (scheme : String , realm : String ) extends ErrorInfo {
75+ override val message : String = " Unauthorized"
76+ override def toString : String = WWWAuthenticateChallenge (scheme).realm(realm).toString()
77+ }
78+
79+ implicit val unauthorizedWithChallengeCodec
80+ : Codec [String , UnauthorizedWithChallenge , CodecFormat .TextPlain ] =
81+ Codec .string.mapDecode(s =>
82+ WWWAuthenticateChallenge .parseSingle(s) match {
83+ case Right (challenge) =>
84+ DecodeResult .Value (
85+ UnauthorizedWithChallenge (challenge.scheme, challenge.realm.getOrElse(" " ))
86+ )
87+ case Left (_) => DecodeResult .Error (s, new Exception (" Cannot parse WWW-Authenticate header" ))
88+ }
89+ )(_.toString())
90+
7391 implicit def apiError2Route (apiError : ErrorInfo )(implicit formats : Formats ): Route =
7492 apiError match {
7593 case r : BadRequest => complete(HttpResponse (StatusCodes .BadRequest , entity = r))
@@ -134,13 +152,20 @@ object ApiErrors extends SchemaDerivation with TapirJson4s {
134152 .example(ApiErrors .ErrorMessage (" Test error message" ))
135153 )
136154
155+ val unauthorizedWithChallengeVariant : EndpointOutput .OneOfVariant [UnauthorizedWithChallenge ] =
156+ oneOfVariant(
157+ statusCode(StatusCode .Unauthorized )
158+ .and(header[UnauthorizedWithChallenge ](HeaderNames .WwwAuthenticate ))
159+ )
160+
137161 val oneOfApiErrors : EndpointOutput .OneOf [ApiErrors .ErrorInfo , ApiErrors .ErrorInfo ] =
138162 oneOf[ApiErrors .ErrorInfo ](
139163 // returns required http code for different types of ErrorInfo.
140164 // For secured endpoint you need to define
141165 // all cases before defining security logic
142166 forbiddenVariant,
143167 unauthorizedVariant,
168+ unauthorizedWithChallengeVariant,
144169 notFoundVariant,
145170 foundVariant,
146171 badRequestVariant,
@@ -226,6 +251,7 @@ object ApiErrors extends SchemaDerivation with TapirJson4s {
226251 body.errorOutVariants(
227252 forbiddenVariant,
228253 unauthorizedVariant,
254+ unauthorizedWithChallengeVariant,
229255 notFoundVariant,
230256 foundVariant,
231257 badRequestVariant,
0 commit comments