diff --git a/cli/src/main/scala/acab/devcon0/dtos/FederationMemberInstallInputVariables.scala b/cli/src/main/scala/acab/devcon0/dtos/FederationMemberInstallInputVariables.scala
index 76a82089876efcac1178d7673bdad63a6a96b9dd..de9541b3feb980cb521ad76581cb1859230ef7dc 100644
--- a/cli/src/main/scala/acab/devcon0/dtos/FederationMemberInstallInputVariables.scala
+++ b/cli/src/main/scala/acab/devcon0/dtos/FederationMemberInstallInputVariables.scala
@@ -1,11 +1,12 @@
 package acab.devcon0.dtos
 
 import acab.devcon0.dtos.TrileCli.Environment
+import acab.devcon0.dtos.TrileCli.EnvironmentVariables.TrileFederationEnvVars
 
 case class FederationMemberInstallInputVariables(
     environment: Environment,
     nickname: String,
-    fedvarsAbsolutePath: String,
+    fedvarsMap: TrileFederationEnvVars,
     sharedDiskSpaceGB: Int,
     sharingFolder: String
 )
diff --git a/cli/src/main/scala/acab/devcon0/dtos/TrileCli.scala b/cli/src/main/scala/acab/devcon0/dtos/TrileCli.scala
index cac2ee99569573a078ea9e353e80f7d68db5c527..ccc19b16c2400e20ab152bcbc3e5f74df1221a15 100644
--- a/cli/src/main/scala/acab/devcon0/dtos/TrileCli.scala
+++ b/cli/src/main/scala/acab/devcon0/dtos/TrileCli.scala
@@ -35,6 +35,7 @@ object TrileCli {
     val TFC_CERTBOT_SERVICE_NAME            = "TRILE_FEDERATION_CONTROLLER_CERTBOT_SERVICE_NAME"
     val TFC_CERTBOT_STAGING                 = "TRILE_FEDERATION_CONTROLLER_CERTBOT_STAGING"
     val TFC_CONFIGURATION_FOLDER            = "TRILE_FEDERATION_CONTROLLER_CONFIGURATION_FOLDER"
+    val TFC_FEDVARS_ABSOLUTE_PATH           = "TRILE_FEDERATION_CONTROLLER_FEDVARS_ABSOLUTE_PATH"
     val TFC_IPFS_ADDRESS                    = "TRILE_FEDERATION_CONTROLLER_IPFS_ADDRESS"
     val TFC_IPFS_CLUSTER_ADDRESS            = "TRILE_FEDERATION_CONTROLLER_IPFS_CLUSTER_ADDRESS"
     val TFC_IPFS_CLUSTER_PEER_ID            = "TRILE_FEDERATION_CONTROLLER_IPFS_CLUSTER_PEER_ID"
@@ -66,15 +67,14 @@ object TrileCli {
 
     private val cliDirectoryAbsolutePath: String = System.getProperty("user.dir")
 
-    val userHomeAbsolutePath: String                = System.getProperty("user.home")
-    val ipfsSwarmPort: String                       = "4001"
-    val ipfsClusterSwarmPort: String                = "9096"
-    val sharedDiskSpaceGb: Int = 10
-    val environment                                 = "production"
-    val fedvarsAbsolutePath: String                 = s"$cliDirectoryAbsolutePath/.fedvars"
-    val nickname: String                            = userHomeAbsolutePath.split("/").last
-    val federationMemberBackendPrivatePort: Int     = 9999
-    val trileConfigurationAbsolutePath              = s"$userHomeAbsolutePath/.config/trile"
-    val ipfsClusterReplicaFactorMax                 = 5
+    val userHomeAbsolutePath: String            = System.getProperty("user.home")
+    val ipfsSwarmPort: String                   = "4001"
+    val ipfsClusterSwarmPort: String            = "9096"
+    val sharedDiskSpaceGb: Int                  = 10
+    val environment                             = "production"
+    val nickname: String                        = userHomeAbsolutePath.split("/").last
+    val federationMemberBackendPrivatePort: Int = 9999
+    val trileConfigurationAbsolutePath          = s"$userHomeAbsolutePath/.config/trile"
+    val ipfsClusterReplicaFactorMax             = 5
   }
 }
diff --git a/cli/src/main/scala/acab/devcon0/files/templates/dev/federationcontroller/DockerCompose.scala b/cli/src/main/scala/acab/devcon0/files/templates/dev/federationcontroller/DockerCompose.scala
index 473ae0836097e289fda120b096692d19353c4b87..6f373e37f138e0d11399333151dea6b89ec168ef 100644
--- a/cli/src/main/scala/acab/devcon0/files/templates/dev/federationcontroller/DockerCompose.scala
+++ b/cli/src/main/scala/acab/devcon0/files/templates/dev/federationcontroller/DockerCompose.scala
@@ -50,9 +50,11 @@ services:
       TRILE_FEDERATION_CONTROLLER_IPFS_API_URL: http://${TRILE_IPFS_DOCKER_CONTAINER_NAME}:5001/api/v0/
       TRILE_FEDERATION_CONTROLLER_IPFS_CLUSTER_API_URL: http://${TRILE_IPFS_CLUSTER_DOCKER_CONTAINER_NAME}:9094/
       TRILE_FEDERATION_CONTROLLER_IPFS_SWARM_KEY_VALUE: ${TRILE_FEDERATION_IPFS_SWARM_KEY_VALUE}
+      TRILE_FEDERATION_CONTROLLER_FEDVARS_ABSOLUTE_PATH: /data/.fedvars
       TRILE_FEDERATION_CONTROLLER_P2P_PRIVATE_KEY: ${TRILE_FEDERATION_CONTROLLER_P2P_PRIVATE_KEY}
       TRILE_FEDERATION_CONTROLLER_REDIS_HOST: trile-dev-federation-controller-redis-stack
     volumes:
+      - ${TRILE_FEDERATION_CONTROLLER_FEDVARS_ABSOLUTE_PATH}:/data/.fedvars
       - /var/run/docker.sock:/var/run/docker.sock
 
   trile_dev_federation_controller_ipfs_cluster:
diff --git a/cli/src/main/scala/acab/devcon0/program/commands/InstallFederationMemberCommand.scala b/cli/src/main/scala/acab/devcon0/program/commands/InstallFederationMemberCommand.scala
index 0b59483c4e81c5008378adf4339a5c1710a45643..b526b9fffd1f876359ab8e610f69906221a61cb1 100644
--- a/cli/src/main/scala/acab/devcon0/program/commands/InstallFederationMemberCommand.scala
+++ b/cli/src/main/scala/acab/devcon0/program/commands/InstallFederationMemberCommand.scala
@@ -6,7 +6,7 @@ import acab.devcon0.dtos.TrileCli.Environment
 import acab.devcon0.dtos.TrileCli.Environment.*
 import acab.devcon0.dtos.TrileCli.EnvironmentVariables.*
 import acab.devcon0.program.opts.{TrileOptsFederation, TrileOptsFederationMember}
-import acab.devcon0.services.EnvVarsFileLoader
+import acab.devcon0.services.{EnvVarsFileLoader, FederationControllerService}
 import acab.devcon0.services.command.install.InstallMemberCommandHandler
 import acab.devcon0.services.shell.{Clear, ConfirmAndRun, Greeter, PrintLn}
 import cats.effect.IO
@@ -27,7 +27,7 @@ object InstallFederationMemberCommand {
         TrileOptsFederationMember.nicknameOpt,
         TrileOptsFederationMember.sharedDiskSpaceGBMandatoryOpt,
         TrileOptsFederationMember.sharingFolderMandatoryOpt,
-        TrileOptsFederation.fedvarsAbsolutePathOpt,
+        TrileOptsFederation.federationUrl,
         TrileOptsFederation.assumeYesFlag
       ).mapN {
         (
@@ -35,30 +35,35 @@ object InstallFederationMemberCommand {
             nickname,
             sharedDiskSpaceGBMandatory,
             sharingFolderMandatory,
-            fedvarsAbsolutePath,
+            federationUrl,
             assumeYes
         ) =>
-          val fedvarsMap: TrileFederationEnvVars =
-            EnvVarsFileLoader(fedvarsAbsolutePath)
-
-          Greeter(action = s"join the '${fedvarsMap(TRILE_FEDERATION_NAME)}'")
-
-          val sharedDiskSpaceGB: Int = loadOrReadSharedDiskSpaceGB(sharedDiskSpaceGBMandatory)
-          val sharingFolder          = loadOrReadSharingFolder(sharingFolderMandatory)
-          val federationMemberInstallInputVariables: FederationMemberInstallInputVariables =
-            FederationMemberInstallInputVariables(
-              environment,
-              nickname,
-              fedvarsAbsolutePath,
-              sharedDiskSpaceGB,
-              sharingFolder
-            )
-          printInputVariables(federationMemberInstallInputVariables)
-
-          ConfirmAndRun(
-            skipConfirmation = assumeYes,
-            action = () => triggerInstallation(fedvarsMap, federationMemberInstallInputVariables)
-          )
+          {
+            for fedvarsMap <- FederationControllerService.getFedvars(environment, federationUrl)
+            yield {
+              Greeter(action = s"join the '${fedvarsMap(TRILE_FEDERATION_NAME)}'")
+
+              val sharedDiskSpaceGB: Int = loadOrReadSharedDiskSpaceGB(sharedDiskSpaceGBMandatory)
+              val sharingFolder          = loadOrReadSharingFolder(sharingFolderMandatory)
+              val federationMemberInstallInputVariables: FederationMemberInstallInputVariables =
+                FederationMemberInstallInputVariables(
+                  environment,
+                  nickname,
+                  fedvarsMap,
+                  sharedDiskSpaceGB,
+                  sharingFolder
+                )
+              printInputVariables(federationMemberInstallInputVariables)
+
+              ConfirmAndRun(
+                skipConfirmation = assumeYes,
+                action = () => triggerInstallation(fedvarsMap, federationMemberInstallInputVariables)
+              )
+            }
+          }
+            .attemptTap(_.fold(throwable => IO(println(throwable)), result => IO(println(result))))
+            .unsafeToFuture()(TrileCommand.trileRuntime)
+            .wait()
       }
     }
 
@@ -81,7 +86,7 @@ object InstallFederationMemberCommand {
     println(s"- Shared disk space (GBs): ${inputVariables.sharedDiskSpaceGB}")
     println(s"- Shared folder: ${inputVariables.sharingFolder}")
     println(s"- Backend port: ${inputVariables.sharingFolder}")
-    println(s"- .fedvars location: ${inputVariables.fedvarsAbsolutePath}")
+    println(s"- .fedvars content: ${inputVariables.fedvarsMap}")
     println()
   }
 
diff --git a/cli/src/main/scala/acab/devcon0/program/opts/TrileOptsFederation.scala b/cli/src/main/scala/acab/devcon0/program/opts/TrileOptsFederation.scala
index 5ac1abaea4586633385c3b8f9d6c7c3994da9fe6..b1f00ba75dcabbf4669dfb8110262addd002dd08 100644
--- a/cli/src/main/scala/acab/devcon0/program/opts/TrileOptsFederation.scala
+++ b/cli/src/main/scala/acab/devcon0/program/opts/TrileOptsFederation.scala
@@ -16,12 +16,11 @@ object TrileOptsFederation {
   val federationNameOpt: Opts[String] = Opts
     .option[String](long = "federation-name", short = "f", help = s"The name you want to use in the federation")
 
-  val fedvarsAbsolutePathOpt: Opts[String] = Opts
+  val federationUrl: Opts[String] = Opts
     .option[String](
-      "fedvars-file",
-      help = s"Absolute path for the federation variables files (default=${Defaults.fedvarsAbsolutePath})"
+      "federation-url",
+      help = s"URL of the federation. For instance: demo.trile.link"
     )
-    .withDefault(Defaults.fedvarsAbsolutePath)
     .map(PathSanitizer.expandHome)
 
   val assumeYesFlag: Opts[Boolean] = Opts
diff --git a/cli/src/main/scala/acab/devcon0/services/FederationControllerEnvironmentVariables.scala b/cli/src/main/scala/acab/devcon0/services/FederationControllerEnvironmentVariables.scala
index 14ec7a398ff417eccb575664ac099e4c10067ff1..05ae801e1caea0c02097f426b3a8362a8e6916b0 100644
--- a/cli/src/main/scala/acab/devcon0/services/FederationControllerEnvironmentVariables.scala
+++ b/cli/src/main/scala/acab/devcon0/services/FederationControllerEnvironmentVariables.scala
@@ -29,10 +29,9 @@ object FederationControllerEnvironmentVariables {
     val backendServiceName: String   = backendContainerName.replace('-', '_')
     val ipfsSwarmPort: String        = Defaults.ipfsSwarmPort
     val ipfsClusterSwarmPort: String = Defaults.ipfsClusterSwarmPort
-    val certbotDirectory = inputVariables.certbotFolderAbsolutePathOptional
-      .getOrElse(s"$controllerConfigurationFolder/certbot")
-    val sharedDiskSpaceGb: Int = inputVariables.sharedDiskSpaceGb
-      .getOrElse(Defaults.sharedDiskSpaceGb)
+    val sharedDiskSpaceGb: Int       = inputVariables.sharedDiskSpaceGb.getOrElse(Defaults.sharedDiskSpaceGb)
+    val certbotDirectory =
+      inputVariables.certbotFolderAbsolutePathOptional.getOrElse(s"$controllerConfigurationFolder/certbot")
     Map(
       DOLLAR                                             -> "$",
       HOST_UID                                           -> UserId().toString,
@@ -52,6 +51,7 @@ object FederationControllerEnvironmentVariables {
       TFC_CERTBOT_SERVICE_NAME                           -> certbotServiceName,
       TFC_CERTBOT_STAGING                                -> inputVariables.stagingSSL,
       TFC_CONFIGURATION_FOLDER                           -> controllerConfigurationFolder,
+      TFC_FEDVARS_ABSOLUTE_PATH                          -> s"$controllerConfigurationFolder/.fedvars",
       TFC_IPFS_CLUSTER_ADDRESS -> getIpfsClusterAddress(controllerNetworkAddress, environment, ipfsClusterSwarmPort),
       TFC_IPFS_CLUSTER_REPLICA_FACTOR_MAX -> inputVariables.ipfsClusterReplicaFactorMax.toString,
       TFC_IPFS_MAX_DISK_SPACE_GB          -> sharedDiskSpaceGb.toString,
diff --git a/cli/src/main/scala/acab/devcon0/services/FederationControllerService.scala b/cli/src/main/scala/acab/devcon0/services/FederationControllerService.scala
index 946467aa561443d8adf375ee8b35c6a06c304d52..47e9f12c42fa7cda0e78648b088b75c40633a7c7 100644
--- a/cli/src/main/scala/acab/devcon0/services/FederationControllerService.scala
+++ b/cli/src/main/scala/acab/devcon0/services/FederationControllerService.scala
@@ -2,13 +2,14 @@ package acab.devcon0.services
 
 import acab.devcon0.dtos.TrileCli
 import acab.devcon0.dtos.TrileCli.Environment
+import acab.devcon0.dtos.TrileCli.EnvironmentVariables.TrileFederationEnvVars
 import acab.devcon0.dtos.aliases.P2pPeerId
 import acab.devcon0.services.shell.PrintLn
 import cats.effect.IO
 import cats.implicits.catsSyntaxMonadError
 import sttp.client4.curl.CurlBackend
-import sttp.client4.{SyncBackend, UriContext, quickRequest}
-import sttp.model.{StatusCode, Uri}
+import sttp.client4.{Response, SyncBackend, UriContext, quickRequest}
+import sttp.model.{HeaderNames, StatusCode, Uri}
 
 import java.util.concurrent.TimeUnit
 import scala.concurrent.duration.Duration
@@ -16,13 +17,33 @@ import scala.concurrent.duration.Duration
 object FederationControllerService {
   private val backend: SyncBackend = CurlBackend()
 
-  def getPeerId(environment: Environment, networkAddress: P2pPeerId): IO[P2pPeerId] = {
-    val uri: Uri = getUri(environment, networkAddress)
+  def getFedvars(environment: Environment, networkAddress: String): IO[TrileFederationEnvVars] = {
+    val uri: Uri = getFedvarsUri(environment, networkAddress)
+    triggerFedvarsRequest(uri)
+      .map(
+        _.split("\\\\n")
+          .map { line =>
+            val Array(key, value) = line.split("=", 2)
+            key -> value
+          }
+          .toMap
+      )
+      .attemptTap(_.fold(throwable => IO(println(throwable.getMessage + uri)), result => IO(println(result))))
+  }
+
+  def getPeerId(environment: Environment, networkAddress: String): IO[P2pPeerId] = {
+    val uri: Uri = getIdUri(environment, networkAddress)
     getP2pPeerIdInner(uri, 300)
       .attemptTap(PrintLn.subStepAttemptTap("Fetching P2P peer id", _))
   }
 
-  private def getUri(environment: Environment, networkAddress: P2pPeerId): Uri = {
+  private def getFedvarsUri(environment: Environment, networkAddress: P2pPeerId): Uri = {
+    environment match
+      case TrileCli.Environment.Dev        => uri"http://$networkAddress:8078/api/federation/.fedvars"
+      case TrileCli.Environment.Production => uri"https://api.$networkAddress/api/federation/.fedvars"
+  }
+
+  private def getIdUri(environment: Environment, networkAddress: P2pPeerId): Uri = {
     environment match
       case TrileCli.Environment.Dev        => uri"http://$networkAddress:8078/api/p2p/id"
       case TrileCli.Environment.Production => uri"https://api.$networkAddress/api/p2p/id"
@@ -36,13 +57,25 @@ object FederationControllerService {
     }
   }
 
+  private def triggerFedvarsRequest(uri: Uri): IO[String] = {
+    triggerRequest(IO(quickRequest.get(uri).header(HeaderNames.Authorization, "Bearer TOKEN").send(backend)))
+  }
+
   private def triggerRequest(uri: Uri): IO[String] = {
-    IO(quickRequest.get(uri).send(backend))
+    triggerRequest(IO(quickRequest.get(uri).send(backend)))
+  }
+
+  private def triggerRequest(value: IO[Response[String]]): IO[String] = {
+    value
       .flatMap(response => {
         if response.code.equals(StatusCode.Ok) then IO(response)
-        else IO.raiseError(new IllegalArgumentException())
+        else {
+          println(response)
+          IO.raiseError(new IllegalArgumentException())
+        }
       })
       .map(_.body)
       .map(_.stripPrefix("\"").stripSuffix("\""))
+
   }
 }
diff --git a/cli/src/main/scala/acab/devcon0/services/command/install/InstallControllerCommandHandler.scala b/cli/src/main/scala/acab/devcon0/services/command/install/InstallControllerCommandHandler.scala
index 1b0e0f995d30584a9489a735bb6373f1e27fb93c..7731e1a7e6d740bc54ae79805ac3a276eeefb9ac 100644
--- a/cli/src/main/scala/acab/devcon0/services/command/install/InstallControllerCommandHandler.scala
+++ b/cli/src/main/scala/acab/devcon0/services/command/install/InstallControllerCommandHandler.scala
@@ -42,8 +42,7 @@ object InstallControllerCommandHandler {
     val environment: Environment = inputVariables.environment
     for peerId <- FederationControllerService.getPeerId(environment, networkAddress)
     yield {
-      val configurationFolderAbsolutePath = getConfigurationFolderAbsolutePath(environmentVariablesMap)
-      val fedvarsAbsolutePath             = s"$configurationFolderAbsolutePath/.fedvars"
+      val fedvarsAbsolutePath = environmentVariablesMap(TFC_FEDVARS_ABSOLUTE_PATH)
       val map: TrileFederationEnvVars = Map(
         TRILE_FEDERATION_IPFS_SWARM_KEY_VALUE -> getIpfsSwarmKeyValue(environmentVariablesMap),
         TFC_NETWORK_ADDRESS                   -> networkAddress,
@@ -130,6 +129,7 @@ object InstallControllerCommandHandler {
     val nginxPreSslConfigurationFileAbsolutePath = getNginxPreSslConfigurationFileAbsolutePath(nginxFolderAbsolutePath)
     val swarmKeyAbsolutePath                     = ipfsConfigurationFolderAbsolutePath + "/swarm.key"
     val dockerComposeAbsolutePath                = getDockerComposeAbsolutePath(configFolderAbsolutePath)
+    val fedvarsAbsolutePath                      = geFedvarsAbsolutePath(envVars)
 
     val dockerComposeTemplateContent           = files.Loader.get(DockerCompose, FederationController, environment)
     val nginxConfTemplateContent               = files.Loader.get(NginxConf, FederationController, environment)
@@ -139,6 +139,7 @@ object InstallControllerCommandHandler {
     for
       _ <- SudoRm(configFolderAbsolutePath)
       _ <- MkdirP(configFolderAbsolutePath)
+      _ <- Touch(fedvarsAbsolutePath)
       _ <- MkdirP(certbotConfigurationFolderAbsolutePath)
       _ <- MkdirP(nginxFolderAbsolutePath)
       _ <- MkdirP(ipfsConfigurationFolderAbsolutePath)
@@ -200,6 +201,10 @@ object InstallControllerCommandHandler {
     nginxConfigurationFolderAbsolutePath + "/nginx-pre-ssl.conf"
   }
 
+  private def geFedvarsAbsolutePath(envVars: TrileFederationEnvVars): String = {
+    envVars(TFC_FEDVARS_ABSOLUTE_PATH)
+  }
+
   private def getConfigurationFolderAbsolutePath(envVars: TrileFederationEnvVars): String = {
     envVars(TFC_CONFIGURATION_FOLDER)
   }
diff --git a/cli/src/main/scala/acab/devcon0/services/shell/Touch.scala b/cli/src/main/scala/acab/devcon0/services/shell/Touch.scala
new file mode 100644
index 0000000000000000000000000000000000000000..3b7d5cd84853e98cf881e3eb39e0226f9e6cd028
--- /dev/null
+++ b/cli/src/main/scala/acab/devcon0/services/shell/Touch.scala
@@ -0,0 +1,18 @@
+package acab.devcon0.services.shell
+
+import cats.effect.IO
+
+object Touch {
+
+  private val cmdLabel: String = "Ensuring file exists"
+
+  def apply(filePath: String): IO[Unit] = {
+    val cmd: String = getCmd(filePath)
+    val label       = s"$cmdLabel: ${filePath.split('/').lastOption.getOrElse(filePath)}"
+    SubStep.withProgress(cmd, label)
+  }
+
+  private def getCmd(filePath: String): String = {
+    s"touch $filePath"
+  }
+}
diff --git a/federation-controller-backend/project/Dependencies.scala b/federation-controller-backend/project/Dependencies.scala
index b578f3ccd1696e04ad74d6a3f051849f791c9bba..1c68b73f83431b5d326a8bada04306d7d0dd0c75 100644
--- a/federation-controller-backend/project/Dependencies.scala
+++ b/federation-controller-backend/project/Dependencies.scala
@@ -1,4 +1,4 @@
-import sbt._
+import sbt.*
 
 // Dependencies
 // Alphabetical
diff --git a/federation-controller-backend/project/metals.sbt b/federation-controller-backend/project/metals.sbt
index 89020435fc590a2b98a4e2c46d604038c0e76872..119c92969dd3b38f04693c535f56fec79558ea02 100644
--- a/federation-controller-backend/project/metals.sbt
+++ b/federation-controller-backend/project/metals.sbt
@@ -1,11 +1,6 @@
 // DO NOT EDIT! This file is auto-generated.
 
-// This plugin enables semantic information to be produced by sbt.
-// It also adds support for debugging using the Debug Adapter Protocol
+// This file enables sbt-bloop to create bloop config files.
 
-addSbtPlugin("org.scalameta" % "sbt-metals" % "1.2.2")
-
-// This plugin adds the BSP debug capability to sbt server.
-
-addSbtPlugin("ch.epfl.scala" % "sbt-debug-adapter" % "3.1.6")
+addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.15")
 
diff --git a/federation-controller-backend/src/main/resources/application.conf b/federation-controller-backend/src/main/resources/application.conf
index fa60c52e77d174260c31e997e0223624da554d51..bf23dd460ea941e55c32ac65a60be0f15c55e29b 100644
--- a/federation-controller-backend/src/main/resources/application.conf
+++ b/federation-controller-backend/src/main/resources/application.conf
@@ -19,6 +19,8 @@ app {
         swarm-key-value = ""
         swarm-key-value = ${?TRILE_FEDERATION_CONTROLLER_IPFS_SWARM_KEY_VALUE}
     }
+    fedvars-absolute-path = ""
+    fedvars-absolute-path = ${?TRILE_FEDERATION_CONTROLLER_FEDVARS_ABSOLUTE_PATH}
 }
 
 akka-http-cors {
diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/boot/ioc/CommonsIoC.scala b/federation-controller-backend/src/main/scala/acab/devcon0/boot/ioc/CommonsIoC.scala
index b28ae887bb203ae0d8b7929412d72f929be342d9..2faa2b5e433587ccee0f08425d7183adaaa33fae 100644
--- a/federation-controller-backend/src/main/scala/acab/devcon0/boot/ioc/CommonsIoC.scala
+++ b/federation-controller-backend/src/main/scala/acab/devcon0/boot/ioc/CommonsIoC.scala
@@ -74,9 +74,13 @@ object CommonsIoC {
       informationQueryHandler = FederationMemberIoC.Domain.Port.federationMembersInformationQueryHandler
     )
 
+    val federationRoute: FederationRoute = new FederationRoute(Configuration.configuration)
+
     val p2pRoute: P2pRoute = new P2pRoute(Configuration.configuration.p2p)
+
     val routes: Routes = new Routes(
-      nodeRoute = nodeRoute,
+      federationRoute = federationRoute,
+      federationMemberRoute = nodeRoute,
       federationMembersRoute = federationMembersRoute,
       ipfsCidRoute = ipfsCidRoute,
       p2pRoute = p2pRoute
diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/configuration/Configuration.scala b/federation-controller-backend/src/main/scala/acab/devcon0/configuration/Configuration.scala
index 24091580f0fe6ebdf04850394ce6672a88307c2c..0e5d9fafe223fd82ac46db70e404e682405537b1 100644
--- a/federation-controller-backend/src/main/scala/acab/devcon0/configuration/Configuration.scala
+++ b/federation-controller-backend/src/main/scala/acab/devcon0/configuration/Configuration.scala
@@ -32,7 +32,8 @@ final case class Configuration(
     ipfsCluster: IpfsClusterConfiguration,
     http: HttpConfiguration,
     redis: RedisConfiguration,
-    p2p: P2pConfiguration
+    p2p: P2pConfiguration,
+    fedvarsAbsolutePath: String
 )
 
 object TrileControllerBackendConfigFactory {
@@ -70,7 +71,8 @@ object TrileControllerBackendConfigFactory {
       ipfsCluster = ipfsClusterConfiguration,
       http = httpConfiguration,
       redis = redisConfiguration,
-      p2p = p2pConfiguration
+      p2p = p2pConfiguration,
+      fedvarsAbsolutePath = appConfig.getString("fedvars-absolute-path")
     )
   }
 
diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/input/http/FederationMembersRoute.scala b/federation-controller-backend/src/main/scala/acab/devcon0/input/http/FederationMembersRoute.scala
index ef96f45599d0009d3a93d317c877d3732f85da4a..4fa816df936da825e180741db3677847af88850a 100644
--- a/federation-controller-backend/src/main/scala/acab/devcon0/input/http/FederationMembersRoute.scala
+++ b/federation-controller-backend/src/main/scala/acab/devcon0/input/http/FederationMembersRoute.scala
@@ -14,7 +14,7 @@ class FederationMembersRoute(informationQueryHandler: InformationQueryHandler) {
 
   private val logger: Logger[IO] = Slf4jLogger.getLogger[IO]
 
-  val rootRoutes: HttpRoutes[IO] = {
+  val routes: HttpRoutes[IO] = {
     HttpRoutes
       .of[IO] { case GET -> Root =>
         (for
diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/input/http/FederationRoute.scala b/federation-controller-backend/src/main/scala/acab/devcon0/input/http/FederationRoute.scala
new file mode 100644
index 0000000000000000000000000000000000000000..a680ee03c9846df45d67ad31e9ec99667c52a5fd
--- /dev/null
+++ b/federation-controller-backend/src/main/scala/acab/devcon0/input/http/FederationRoute.scala
@@ -0,0 +1,60 @@
+package acab.devcon0.input.http
+
+import acab.devcon0.configuration.Configuration
+import acab.devcon0.trile.utils.EffectsUtils
+import cats.effect._
+import cats.implicits.catsSyntaxMonadError
+import fs2.io.file.Files
+import fs2.io.file.Path
+import org.http4s._
+import org.http4s.circe.CirceEntityEncoder.circeEntityEncoder
+import org.http4s.dsl.io._
+import org.http4s.headers.Authorization
+import org.typelevel.log4cats.Logger
+import org.typelevel.log4cats.slf4j.Slf4jLogger
+
+class FederationRoute(configuration: Configuration) {
+
+  implicit val logger: Logger[IO] = Slf4jLogger.getLogger[IO]
+
+  val routes: HttpRoutes[IO] = HttpRoutes
+    .of[IO] {
+      case req @ GET -> Root / ".fedvars" => {
+        validateToken(req)
+          .flatMap {
+            case ok @ Response(Status.Ok, _, _, _, _) => {
+              val filePath: Path = Path(configuration.fedvarsAbsolutePath)
+              Files[IO]
+                .readAll(filePath)
+                .through(fs2.text.utf8.decode)
+                .compile
+                .string
+                .flatMap(fileContent => Ok(fileContent))
+            }
+            case badRequest @ Response(Status.BadRequest, _, _, _, _) => {
+              IO.pure(badRequest)
+            }
+            case unauthorized @ Response(Status.Unauthorized, _, _, _, _) => {
+              IO.pure(unauthorized)
+            }
+          }
+          .attemptTap(EffectsUtils.attemptTLog)
+      }
+    }
+
+  private def validateToken(req: Request[IO]): IO[Response[IO]] = {
+    val maybeAuthorization: Option[Authorization] = req.headers.get[Authorization]
+    maybeAuthorization match {
+      case Some(Authorization(Credentials.Token(AuthScheme.Bearer, token))) =>
+        if isValidToken(token) then { IO(Response(Status.Ok)) }
+        else { IO(Response(Status.Unauthorized)) }
+      case _ => {
+        IO(Response(Status.BadRequest).withEntity("Missing Authorization Header"))
+      }
+    }
+  }
+
+  private def isValidToken(token: String): Boolean = {
+    true
+  }
+}
diff --git a/federation-controller-backend/src/main/scala/acab/devcon0/input/http/Routes.scala b/federation-controller-backend/src/main/scala/acab/devcon0/input/http/Routes.scala
index b29e0fb5ee26865456d5b2a0a1aeeca19d66a07e..7041fe02c20ab3d5fd36fe840c9591a385320bd6 100644
--- a/federation-controller-backend/src/main/scala/acab/devcon0/input/http/Routes.scala
+++ b/federation-controller-backend/src/main/scala/acab/devcon0/input/http/Routes.scala
@@ -6,7 +6,8 @@ import org.http4s.server.Router
 import org.http4s.server.middleware.CORS
 
 class Routes(
-    nodeRoute: FederationMemberRoute,
+    federationRoute: FederationRoute,
+    federationMemberRoute: FederationMemberRoute,
     federationMembersRoute: FederationMembersRoute,
     ipfsCidRoute: IpfsCidRoute,
     p2pRoute: P2pRoute
@@ -14,8 +15,9 @@ class Routes(
 
   val httpApp: Http[IO, IO] = CORS.policy.withAllowOriginAll(
     Router(
-      "/api/federation/members" -> federationMembersRoute.rootRoutes,
-      "/api/federation/members" -> nodeRoute.routes,
+      "/api/federation/"         -> federationRoute.routes,
+      "/api/federation/members" -> federationMembersRoute.routes,
+      "/api/federation/members" -> federationMemberRoute.routes,
       "/api/ipfs/"              -> ipfsCidRoute.routes,
       "/api/p2p/"               -> p2pRoute.routes
     ).orNotFound
diff --git a/trile-backend-commons/src/main/scala/acab/devcon0/trile/Main.scala b/trile-backend-commons/src/main/scala/acab/devcon0/trile/Main.scala
deleted file mode 100644
index 6f352eab1d480c43b27c1cee3ed62249fde41828..0000000000000000000000000000000000000000
--- a/trile-backend-commons/src/main/scala/acab/devcon0/trile/Main.scala
+++ /dev/null
@@ -1,57 +0,0 @@
-package acab.devcon0.trileimport scala.util.Try
-
-import acab.devcon0.trile.domain.dtos.pubsub.P2p.Message
-import io.circe._
-import io.circe.generic.semiauto.deriveDecoder
-import io.circe.generic.semiauto.deriveEncoder
-import io.circe.jawn.decode
-import io.circe.syntax.EncoderOps
-
-object Main {
-
-  final case class Message[T <: Data](meta: Metadata, data: Data)
-  final case class Metadata(metadataField: String)
-  sealed trait Data
-  final case class DataTypeA(fieldA: String) extends Data
-  final case class DataTypeB(fieldB: Int)    extends Data
-
-  implicit val metadataDecoder: Decoder[Metadata]   = deriveDecoder
-  implicit val dataTypeADecoder: Decoder[DataTypeA] = deriveDecoder
-  implicit val dataTypeBDecoder: Decoder[DataTypeB] = deriveDecoder
-
-  implicit val metadataEncoder: Encoder[Metadata]   = deriveEncoder
-  implicit val dataTypeAEncoder: Encoder[DataTypeA] = deriveEncoder
-  implicit val dataTypeBEncoder: Encoder[DataTypeB] = deriveEncoder
-
-  implicit def messageEncoder[T <: Data: Encoder]: Encoder[Message[T]] = deriveEncoder
-  implicit def messageDecoder[T <: Data: Decoder]: Decoder[Message[T]] = deriveDecoder
-
-  def main(args: Array[String]): Unit = {
-
-    val dataTypeAMessage: Message[DataTypeA] = Message[DataTypeA](
-      meta = Metadata(metadataField = "metadata"),
-      data = DataTypeA("fieldA")
-    )
-    val dataTypeBMessage: Message[DataTypeB] = Message[DataTypeB](
-      meta = Metadata(metadataField = "metadata"),
-      data = DataTypeB(10)
-    )
-    val dataTypeAMessageEncoded = encodeInner[DataTypeA](dataTypeAMessage)
-    val dataTypeBMessageEncoded = encodeInner[DataTypeB](dataTypeBMessage)
-    val dataTypeAMessageDecoded = decodeInner[DataTypeA](dataTypeAMessageEncoded)
-    val dataTypeBMessageDecoded = decodeInner[DataTypeB](dataTypeBMessageEncoded)
-
-    println(s"dataTypeAMessageEncoded=$dataTypeAMessageEncoded")
-    println(s"dataTypeBMessageEncoded=$dataTypeBMessageEncoded")
-    println(s"dataTypeAMessageDecoded=$dataTypeAMessageDecoded")
-    println(s"dataTypeBMessageDecoded=$dataTypeBMessageDecoded")
-  }
-
-  private def encodeInner[T <: Data: Encoder](message: Message[T]): String = {
-    EncoderOps[Message[T]](message).asJson.noSpaces
-  }
-
-  private def decodeInner[T <: Data: Decoder](json: String): Message[T] = {
-    decode[Message[T]](json).right.get
-  }
-}
diff --git a/trile-backend-commons/src/main/scala/acab/devcon0/trile/domain/codecs/IpfsClusterCodecs.scala b/trile-backend-commons/src/main/scala/acab/devcon0/trile/domain/codecs/IpfsClusterCodecs.scala
index 895fa4034c1dbe52e6fcc69dc9b84dd5d09dc976..575968b4ca51e9c0222103edfd4915f44499a080 100644
--- a/trile-backend-commons/src/main/scala/acab/devcon0/trile/domain/codecs/IpfsClusterCodecs.scala
+++ b/trile-backend-commons/src/main/scala/acab/devcon0/trile/domain/codecs/IpfsClusterCodecs.scala
@@ -1,11 +1,16 @@
 package acab.devcon0.trile.domain.codecs
 
+import java.time.Instant
+
 import acab.devcon0.trile.domain.dtos
 import acab.devcon0.trile.domain.dtos.IpfsClusterPeer
 import acab.devcon0.trile.domain.dtos.IpfsClusterPeerIpfsInfo
 import acab.devcon0.trile.domain.dtos.IpfsClusterPeers
 import acab.devcon0.trile.domain.dtos.IpfsClusterPin
+import acab.devcon0.trile.domain.dtos.IpfsClusterPinAllocation
 import acab.devcon0.trile.domain.dtos.IpfsClusterPins
+import acab.devcon0.trile.domain.dtos.aliases.IpfsCid
+import acab.devcon0.trile.domain.dtos.aliases.IpfsClusterPeerId
 import cats.effect.IO
 import io.circe._
 import io.circe.generic.semiauto.deriveDecoder
@@ -51,6 +56,33 @@ object IpfsClusterCodecs {
       }
     }
 
+    implicit val allocation: Decoder[IpfsClusterPinAllocation] = (c: HCursor) => {
+      for
+        replicationFactorMin <- c.downField("replication_factor_min").as[Int]
+        replicationFactorMax <- c.downField("replication_factor_max").as[Int]
+        name                 <- c.downField("name").as[String]
+        mode                 <- c.downField("mode").as[String]
+        cid                  <- c.downField("cid").as[IpfsCid]
+        allocations          <- c.downField("allocations").as[Set[IpfsClusterPeerId]]
+        timestamp            <- c.downField("timestamp").as[Instant]
+      yield {
+        dtos.IpfsClusterPinAllocation(
+          replicationFactorMin = replicationFactorMin,
+          replicationFactorMax = replicationFactorMax,
+          name = name,
+          mode = mode,
+          cid = cid,
+          allocations = allocations,
+          timestamp = timestamp
+        )
+      }
+    }
+
+    object IpfsClusterPinAllocation {
+      def apply(rawJson: String): IO[IpfsClusterPinAllocation] =
+        IO.fromEither(decode[IpfsClusterPinAllocation](rawJson))
+    }
+
     object IpfsClusterPeerIpfsInfo {
       def apply(rawJson: String): IO[IpfsClusterPeerIpfsInfo] = IO.fromEither(decode[IpfsClusterPeerIpfsInfo](rawJson))
     }
diff --git a/trile-backend-commons/src/main/scala/acab/devcon0/trile/domain/dtos/IpfsClusterPeer.scala b/trile-backend-commons/src/main/scala/acab/devcon0/trile/domain/dtos/IpfsClusterPeer.scala
index c7f382f6eb1439b12bd6349e7539ce221b72510f..542b66a1d5b33e725552f3e3c12fc0d29b43e121 100644
--- a/trile-backend-commons/src/main/scala/acab/devcon0/trile/domain/dtos/IpfsClusterPeer.scala
+++ b/trile-backend-commons/src/main/scala/acab/devcon0/trile/domain/dtos/IpfsClusterPeer.scala
@@ -1,5 +1,7 @@
 package acab.devcon0.trile.domain.dtos
 
+import java.time.Instant
+
 import acab.devcon0.trile.domain.dtos.aliases.IpfsCid
 import acab.devcon0.trile.domain.dtos.aliases.IpfsClusterPeerId
 import acab.devcon0.trile.domain.dtos.aliases.IpfsPeerId
@@ -24,3 +26,13 @@ final case class IpfsClusterPeerIpfsInfo(
     addresses: List[String],
     error: String
 )
+
+case class IpfsClusterPinAllocation(
+    replicationFactorMin: Int,
+    replicationFactorMax: Int,
+    name: String,
+    mode: String,
+    cid: IpfsCid,
+    allocations: Set[IpfsClusterPeerId],
+    timestamp: Instant
+)