I\'m making a real push to understand the async powers of Play but finding a lot of conflict with regard to places where async invocation fits and places where the framework see
I've seen on theguardian's GH repo how they handle this case scenario in a asynchronous way while still having the support of the form error helpers from play. From a quick look, seems like they are storing the form errors in an encrypted cookie in a way as to display those errors back to the user the next time the user goes to the login page.
Extracted from: https://github.com/guardian/facia-tool/blob/9ec455804edbd104861117d477de9a0565776767/identity/app/controllers/ReauthenticationController.scala
def processForm = authenticatedActions.authActionWithUser.async { implicit request =>
val idRequest = idRequestParser(request)
val boundForm = formWithConstraints.bindFromRequest
val verifiedReturnUrlAsOpt = returnUrlVerifier.getVerifiedReturnUrl(request)
def onError(formWithErrors: Form[String]): Future[Result] = {
logger.info("Invalid reauthentication form submission")
Future.successful {
redirectToSigninPage(formWithErrors, verifiedReturnUrlAsOpt)
}
}
def onSuccess(password: String): Future[Result] = {
logger.trace("reauthenticating with ID API")
val persistent = request.user.auth match {
case ScGuU(_, v) => v.isPersistent
case _ => false
}
val auth = EmailPassword(request.user.primaryEmailAddress, password, idRequest.clientIp)
val authResponse = api.authBrowser(auth, idRequest.trackingData, Some(persistent))
signInService.getCookies(authResponse, persistent) map {
case Left(errors) =>
logger.error(errors.toString())
logger.info(s"Reauthentication failed for user, ${errors.toString()}")
val formWithErrors = errors.foldLeft(boundForm) { (formFold, error) =>
val errorMessage =
if ("Invalid email or password" == error.message) Messages("error.login")
else error.description
formFold.withError(error.context.getOrElse(""), errorMessage)
}
redirectToSigninPage(formWithErrors, verifiedReturnUrlAsOpt)
case Right(responseCookies) =>
logger.trace("Logging user in")
SeeOther(verifiedReturnUrlAsOpt.getOrElse(returnUrlVerifier.defaultReturnUrl))
.withCookies(responseCookies:_*)
}
}
boundForm.fold[Future[Result]](onError, onSuccess)
}
def redirectToSigninPage(formWithErrors: Form[String], returnUrl: Option[String]): Result = {
NoCache(SeeOther(routes.ReauthenticationController.renderForm(returnUrl).url).flashing(clearPassword(formWithErrors).toFlash))
}