authenticateOrRejectWithChallenge
Signature
type AuthenticationResult[+T] = Either[HttpChallenge, T]
def authenticateOrRejectWithChallenge[T](authenticator: Option[HttpCredentials] => Future[AuthenticationResult[T]]): AuthenticationDirective[T]
Description
Lifts an authenticator function into a directive.
This directive allows implementing the low level challenge-response type of authentication that some services may require.
More details about challenge-response authentication are available in the RFC 2617, RFC 7616 and RFC 7617.
Example
- Scala
-
sourceval challenge = HttpChallenge("MyAuth", Some("MyRealm"))
// your custom authentication logic:
def auth(creds: HttpCredentials): Boolean = true
def myUserPassAuthenticator(credentials: Option[HttpCredentials]): Future[AuthenticationResult[String]] =
Future {
credentials match {
case Some(creds) if auth(creds) => Right("some-user-name-from-creds")
case _ => Left(challenge)
}
}
val route =
Route.seal {
path("secured") {
authenticateOrRejectWithChallenge(myUserPassAuthenticator _) { userName =>
complete("Authenticated!")
}
}
}
// tests:
Get("/secured") ~> route ~> check {
status shouldEqual StatusCodes.Unauthorized
responseAs[String] shouldEqual "The resource requires authentication, which was not supplied with the request"
header[`WWW-Authenticate`].get.challenges.head shouldEqual HttpChallenge("MyAuth", Some("MyRealm"))
}
val validCredentials = BasicHttpCredentials("John", "p4ssw0rd")
Get("/secured") ~> addCredentials(validCredentials) ~> // adds Authorization header
route ~> check {
status shouldEqual StatusCodes.OK
responseAs[String] shouldEqual "Authenticated!"
}
- Java
-
sourceimport akka.http.javadsl.model.headers.HttpChallenge;
import akka.http.javadsl.model.headers.HttpCredentials;
import static akka.http.javadsl.server.Directives.authenticateOrRejectWithChallenge;
import static akka.http.javadsl.server.Directives.complete;
import static akka.http.javadsl.server.Directives.path;
final HttpChallenge challenge = HttpChallenge.create("MyAuth", new Option.Some<>("MyRealm"));
// your custom authentication logic:
final Function<HttpCredentials, Boolean> auth = credentials -> true;
final Function<Optional<HttpCredentials>, CompletionStage<Either<HttpChallenge, String>>> myUserPassAuthenticator =
opt -> {
if (opt.isPresent() && auth.apply(opt.get())) {
return CompletableFuture.completedFuture(Right.apply("some-user-name-from-creds"));
} else {
return CompletableFuture.completedFuture(Left.apply(challenge));
}
};
final Route route = path("secured", () ->
authenticateOrRejectWithChallenge(myUserPassAuthenticator, userName ->
complete("Authenticated!")
)
).seal();
// tests:
testRoute(route).run(HttpRequest.GET("/secured"))
.assertStatusCode(StatusCodes.UNAUTHORIZED)
.assertEntity("The resource requires authentication, which was not supplied with the request")
.assertHeaderExists("WWW-Authenticate", "MyAuth realm=\"MyRealm\"");
final HttpCredentials validCredentials =
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validCredentials))
.assertStatusCode(StatusCodes.OK)
.assertEntity("Authenticated!");
Found an error in this documentation? The source code for this page can be found
here.
Please feel free to edit and contribute a pull request.