How change authorization to separate server?

I inherited a project on the play framework and scala. It uses silhouette, PasswordHasherRegistry and JWT authenticator. I have tables with users.

I have a file with the description:

trait BaseEnv extends Env {
  type I = AuthUser
  type A = JWTAuthenticator
}

I also have a Silhouette Module.scala file, here is a part of it:

  override def configure() {
    bind[Silhouette[OnlineEnv]].to[SilhouetteProvider[OnlineEnv]]
    bind[Silhouette[MobileEnv]].to[SilhouetteProvider[MobileEnv]]
    bind[CacheLayer].to[PlayCacheLayer]
    bind[IDGenerator].toProvider[IDGeneratorProvider]
    bind[PasswordHasher].toInstance(new BCryptPasswordHasher)
    bind[FingerprintGenerator].toInstance(new DefaultFingerprintGenerator(false))
    bind[EventBus].toInstance(EventBus())
    bind[Clock].toInstance(Clock())
    bind[DelegableAuthInfoDAO[OAuth1Info]].toInstance(new InMemoryAuthInfoDAO[OAuth1Info])
    bind[DelegableAuthInfoDAO[OAuth2Info]].toInstance(new InMemoryAuthInfoDAO[OAuth2Info])
    bind[DelegableAuthInfoDAO[OpenIDInfo]].toInstance(new InMemoryAuthInfoDAO[OpenIDInfo])
  }

  @Provides
  def providePasswordDAO(implicit ec: ExecutionContext, dbConfigProvider: DatabaseConfigProvider): DelegableAuthInfoDAO[PasswordInfo]
  = new PasswordInfoAuthDAO(dbConfigProvider)

  @Provides
  def provideOnlineEnvironment(implicit ec: ExecutionContext,
                               userService: UserService,
                               @Named("authenticator-online-service") authenticatorService: AuthenticatorService[JWTAuthenticator],
                               eventBus: EventBus): Environment[OnlineEnv] = {

    Environment[OnlineEnv](
      userService,
      authenticatorService,
      Seq(),
      eventBus
    )
  }

Token creation function

  def getJWTToken(authUser: AuthUser, rememberMe: Option[Boolean] = None, deviceId: Option[String] = None)(implicit request: RequestHeader): Future[String] = {
    val loginInfo = authUser.loginInfo //LoginInfo(CredentialsProvider.ID, authUser.phone)

    silhouette.env.authenticatorService.create(loginInfo)(request).map {
      case authenticator if rememberMe.getOrElse(false) =>
        if (silhouette.env.isInstanceOf[BaseEnv]) {}
        val c = configuration.underlying
        authenticator.copy(
          expirationDateTime = clock.now + c.as[FiniteDuration]("silhouette.authenticator.online.rememberMe.authenticatorExpiry"),
          idleTimeout = c.getAs[FiniteDuration]("silhouette.authenticator.online.rememberMe.authenticatorIdleTimeout")
        )
      case authenticator if deviceId.isDefined =>
        authenticator.copy(customClaims = Some(Json.obj("sysid" -> deviceId.get)))
      case authenticator => authenticator
    }.flatMap { authenticator =>
      if (rememberMe.getOrElse(false)) {
        silhouette.env.eventBus.publish(LoginEvent(authUser, request))
      }
      silhouette.env.authenticatorService.init(authenticator)(request).map { token =>
        silhouette.env.eventBus.publish(SignUpEvent(authUser, request))
        silhouette.env.eventBus.publish(LoginEvent(authUser, request))
        token
      }
    }
  }

The ApiController.scala file has wrappers for parsing incoming requests:

  def unsecuredAsync[T](block: (T, Request[AnyContent]) => Future[Result])(implicit reads: Reads[T]): Action[AnyContent] =
    silhouette.UnsecuredAction.async { implicit request =>
      request.body.asJson.map { json =>
        json.asOpt[T] match {
          case Some(dto) =>
            block(dto, request)
          case None =>
            val Failure(e) = Try(json.as[T])
            Future.successful(BadRequest(ApiResponse(InvalidJson, JsString(e.getMessage))))
        }
      }.getOrElse(Future.successful(UnsupportedMediaType(ApiResponse(WrongDTO))))
    }

  def securedAsync[T](block: (T, SecuredRequest[E, AnyContent]) => Future[Result])(implicit reads: Reads[T]): Action[AnyContent] =
    silhouette.SecuredAction.async {
      implicit request =>
        request.body.asJson.map { json =>
          json.asOpt[T] match {
            case Some(dto) =>
              block(dto, request)
            case None =>
              val Failure(e) = Try(json.as[T])
              Future.successful(BadRequest(ApiResponse(InvalidJson, JsString(e.getMessage))))
          }
        }.getOrElse(Future.successful(UnsupportedMediaType(ApiResponse(WrongDTO))))
    }

These wrappers are used in controllers:

  def removeUser: Action[AnyContent] = securedAsync[RemoveUserRequestDTO] { (dto, request) =>
    if (!request.identity.roles.contains(RoleType.admin))
    ) {
      Future.successful(()).map(_ => Forbidden(ApiResponse(WrongRights)))
    }
    else {
      userService.removeUser(dto.userId)
        .map(_ => Ok(ApiResponse(RemoveSuccessful, Json.toJson(
          RemoveUserResponseDTO(dto.userId)
        ))))
    }
  }

Now I was faced with the task of making a second copy of the server, but leaving common users on both servers. I assume that for this I need to take out authentication and authorization to a separate server. I am considering 2 options:

  1. Create the server to the play framework and libraries https://github.com/nulab/scala-oauth2-provider. Move the user base there. Change the authorization from using the internal database to using OpenID.
  2. Use Keycloak.

Can you tell me how to do this correctly? Preferably with minimal rewriting of the controller code.
There is one nuance. I want to authorize users without redirecting to the authorization server using my custom form, requesting authorization and receiving a JWT token via the API from the authorization server. And give the token to the user independently.

Best regards.