private[auth] def invokeBlockWithTime[A]()

in backend/app/utils/auth/AuthActionBuilder.scala [36:95]


  private[auth] def invokeBlockWithTime[A](request: Request[A], block: (UserIdentityRequest[A]) => Future[Result],
                                           now: Long): Future[Either[Failure, Result]] = {
    implicit val implicitReq = request
    val claimData = request.jwtSession.claimData
    val maybeToken = claimData.validate[Token]
    maybeToken match {
      case (JsSuccess(token, _)) if token.loginExpiry > now =>
        val isVerificationExpired = token.verificationExpiry <= now
        for {
          maybeDbUser <- if (isVerificationExpired) getUser(token.user.username).asFuture else Future.successful(Left(AuthenticationFailure("Verification hasn't expired", reportAsFailure = true)))
          result <- block(new AuthenticatedRequest(token.user, request))
        } yield {
          if (isVerificationExpired) {
            maybeDbUser match {
              case Right(user) if user.invalidationTime.exists(token.issuedAt < _) =>
                // The user has logged out
                val msg = s"Authenticated failed because token was issued before database invalidation time"
                logger.warn(token.user.asLogMarker, msg)
                Left(AuthenticationFailure(msg, reportAsFailure = true))
              case Left(failure) =>
                logger.error(token.user.asLogMarker, "Authentication failed because user was not found in DB", failure.toThrowable)
                Left(failure)
              case Right(_) =>
                val verificationExpiry = now + maxVerificationAge.toMillis
                val expiryDateTime = LocalDateTime.ofInstant(
                  Instant.ofEpochMilli(verificationExpiry),
                  ZoneId.systemDefault()
                )
                logger.info(token.user.asLogMarker, s"Authentication succeeded, verification expired but token renewed. New verification expiry: ${expiryDateTime}")
                Right(result
                  .refreshJwtSession
                  .addingToJwtSession(Token.VERIFICATION_EXPIRY_KEY, verificationExpiry)
                  .addingToJwtSession(Token.REFRESHED_AT_KEY, now)
                )
            }
          } else {
            Right(result
              .refreshJwtSession
              .addingToJwtSession(Token.REFRESHED_AT_KEY, now)
            )
          }
        }

      case JsSuccess(token, _) => {
        val msg = s"Token is older than $maxLoginAge"
        logger.info(token.user.asLogMarker, msg)
        Future.successful(Left(AuthenticationFailure(msg, reportAsFailure = false)))
      }

      case JsError(errors) => {
        val msg = s"Failed to parse token: $errors"
        logger.warn(msg)
        // This error happens whenever the token is missing,
        // as a result of vulnerability scanners and occasionally developer testing/debugging
        // (e.g. just opening https://giant.pfi.gutools.co.uk/api/search in your browser will fire this alarm).
        // For this reason we don't want to get an alarm.
        Future.successful(Left(AuthenticationFailure(msg, reportAsFailure = false)))
      }
    }
  }