diff --git a/app/controllers/admin/university/apps_controller.rb b/app/controllers/admin/university/apps_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5832899bcb9d5308535d997ba0a2e2f9a8de72c8
--- /dev/null
+++ b/app/controllers/admin/university/apps_controller.rb
@@ -0,0 +1,70 @@
+class Admin::University::AppsController < Admin::University::ApplicationController
+  load_and_authorize_resource class: University::App,
+                              through: :current_university,
+                              through_association: :apps
+
+  def index
+    @apps = apply_scopes(@apps).ordered.page(params[:page])
+    breadcrumb
+  end
+
+  def show
+    @should_display_token = @app.display_token!
+    breadcrumb
+  end
+
+  def new
+    breadcrumb
+  end
+
+  def edit
+    breadcrumb
+    add_breadcrumb t('edit')
+  end
+
+  def create
+    if @app.save
+      redirect_to admin_university_app_path(@app),
+                  notice: t('admin.successfully_created_html', model: @app.to_s)
+    else
+      breadcrumb
+      render :new, status: :unprocessable_entity
+    end
+  end
+
+  def update
+    if @app.update(app_params)
+      redirect_to admin_university_app_path(@app),
+                  notice: t('admin.successfully_updated_html', model: @app.to_s)
+    else
+      breadcrumb
+      add_breadcrumb t('edit')
+    end
+  end
+
+  def destroy
+    @app.destroy
+    redirect_to admin_university_apps_url,
+                notice: t('admin.successfully_destroyed_html', model: @app.to_s)
+  end
+
+  def regenerate_token
+    @app.regenerate_token!
+    redirect_to admin_university_app_path(@app), notice: t('university.apps.token_successfully_regenerated')
+  end
+
+  protected
+
+  def breadcrumb
+    super
+    add_breadcrumb  University::App.model_name.human(count: 2),
+                    admin_university_apps_path
+    breadcrumb_for @app
+  end
+
+  def app_params
+    params.require(:university_app)
+          .permit(:name)
+          .merge(university_id: current_university.id)
+  end
+end
\ No newline at end of file
diff --git a/app/controllers/api/osuny/application_controller.rb b/app/controllers/api/osuny/application_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..74e5ba47e8acb595529a58bf52c2eb90195d2ecc
--- /dev/null
+++ b/app/controllers/api/osuny/application_controller.rb
@@ -0,0 +1,8 @@
+class Api::Osuny::ApplicationController < Api::ApplicationController
+  protected
+
+  def verify_app_token
+    @app = current_university.apps.find_by(token: request.headers['X-Osuny-Token'])
+    raise_403_unless @app
+  end
+end
\ No newline at end of file
diff --git a/app/controllers/api/osuny/communication/websites/posts_controller.rb b/app/controllers/api/osuny/communication/websites/posts_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9047d91a0bc231c4684a150d40968a0f0c5361e6
--- /dev/null
+++ b/app/controllers/api/osuny/communication/websites/posts_controller.rb
@@ -0,0 +1,66 @@
+class Api::Osuny::Communication::Websites::PostsController < Api::Osuny::ApplicationController
+  skip_before_action :verify_authenticity_token, only: :import
+  before_action :verify_app_token, only: :import
+
+  def import
+    create_post
+    import_blocks
+    render json: :ok
+  end
+
+  protected
+
+  def create_post
+    post.language = website.default_language
+    post.update post_params
+    post.save
+  end
+
+  def post
+    @post ||= website.posts
+                  .where(
+                    university: current_university,
+                    website: website,
+                    migration_identifier: migration_identifier
+                  )
+                  .first_or_initialize
+  end
+
+  def import_blocks
+    blocks.each do |b|
+      migration_identifier = b[:migration_identifier]
+      template_kind = b[:template_kind]
+      block = post.blocks
+                  .where(
+                    template_kind: template_kind,
+                    migration_identifier: migration_identifier
+                  )
+                  .first_or_initialize
+      block.university = current_university
+      data = b[:data].to_unsafe_hash
+      block.data = block.template.data.merge data
+      block.save
+    end
+  end
+
+  def blocks
+    return [] unless params[:post].has_key?(:blocks)
+    @blocks ||= params[:post][:blocks]
+  end
+
+  def website
+    @website ||= current_university.websites.find params[:website_id]
+  end
+
+  def migration_identifier
+    @migration_identifier ||= params[:migration_identifier]
+  end
+
+  def post_params
+    params.require(:post)
+          .permit(
+            :title, :language, :meta_description, :summary,
+          )
+  end
+
+end
diff --git a/app/controllers/api/osuny/communication/websites_controller.rb b/app/controllers/api/osuny/communication/websites_controller.rb
index a6d4a480946862ded51a537e7d21147f1056a1ad..7b8c17d328d6b93dab05feb2277d0bd6feeb93e4 100644
--- a/app/controllers/api/osuny/communication/websites_controller.rb
+++ b/app/controllers/api/osuny/communication/websites_controller.rb
@@ -1,4 +1,4 @@
-class Api::Osuny::Communication::WebsitesController < Api::ApplicationController
+class Api::Osuny::Communication::WebsitesController < Api::Osuny::ApplicationController
 
   def index
     @websites = current_university.communication_websites.in_production
diff --git a/app/controllers/api/osuny/communication_controller.rb b/app/controllers/api/osuny/communication_controller.rb
index 597ec060fd44c983375bd75e6d909159830f2557..483a8c844ea33324e38cff99544a8a7781a7a41d 100644
--- a/app/controllers/api/osuny/communication_controller.rb
+++ b/app/controllers/api/osuny/communication_controller.rb
@@ -1,4 +1,4 @@
-class Api::Osuny::CommunicationController < Api::ApplicationController
+class Api::Osuny::CommunicationController < Api::Osuny::ApplicationController
   def index
   end
 end
diff --git a/app/controllers/api/osuny/server/websites_controller.rb b/app/controllers/api/osuny/server/websites_controller.rb
index c34306c0b7924980007af42be44b44266cb780a1..797aaf0b304232d2955c115a52e3ccdb8b5f94df 100644
--- a/app/controllers/api/osuny/server/websites_controller.rb
+++ b/app/controllers/api/osuny/server/websites_controller.rb
@@ -1,4 +1,4 @@
-class Api::Osuny::Server::WebsitesController < Api::ApplicationController
+class Api::Osuny::Server::WebsitesController < Api::Osuny::ApplicationController
   skip_before_action :verify_authenticity_token, only: [:theme_released]
 
   def index
diff --git a/app/controllers/api/osuny/server_controller.rb b/app/controllers/api/osuny/server_controller.rb
index 3b59a6e157a1e90880c63543d7d01ad1c2dcae21..2732f8f5e9e55504bf27d4a36f4f81211f54b503 100644
--- a/app/controllers/api/osuny/server_controller.rb
+++ b/app/controllers/api/osuny/server_controller.rb
@@ -1,4 +1,4 @@
-class Api::Osuny::ServerController < Api::ApplicationController
+class Api::Osuny::ServerController < Api::Osuny::ApplicationController
   def index
   end
 end
diff --git a/app/models/communication/block.rb b/app/models/communication/block.rb
index b8e96cc8a5cdee27dd866485ad81bfb0964eb67e..f71d4fe69cd478a107c3138053bf098f2466f6fe 100644
--- a/app/models/communication/block.rb
+++ b/app/models/communication/block.rb
@@ -5,6 +5,7 @@
 #  id                       :uuid             not null, primary key
 #  about_type               :string           indexed => [about_id]
 #  data                     :jsonb
+#  migration_identifier     :string
 #  position                 :integer          default(0), not null
 #  published                :boolean          default(TRUE)
 #  template_kind            :integer          default(NULL), not null
diff --git a/app/models/communication/extranet.rb b/app/models/communication/extranet.rb
index 1a4615b3d6c6865f180dd318b43f9c1268235907..0dc31636314ab864924471003317609996665e7c 100644
--- a/app/models/communication/extranet.rb
+++ b/app/models/communication/extranet.rb
@@ -2,35 +2,34 @@
 #
 # Table name: communication_extranets
 #
-#  id                             :uuid             not null, primary key
-#  about_type                     :string           indexed => [about_id]
-#  allow_experiences_modification :boolean          default(TRUE)
-#  color                          :string
-#  cookies_policy                 :text
-#  css                            :text
-#  feature_alumni                 :boolean          default(FALSE)
-#  feature_contacts               :boolean          default(FALSE)
-#  feature_jobs                   :boolean          default(FALSE)
-#  feature_library                :boolean          default(FALSE)
-#  feature_posts                  :boolean          default(FALSE)
-#  has_sso                        :boolean          default(FALSE)
-#  home_sentence                  :text
-#  host                           :string
-#  name                           :string
-#  privacy_policy                 :text
-#  registration_contact           :string
-#  sass                           :text
-#  sso_button_label               :string
-#  sso_cert                       :text
-#  sso_mapping                    :jsonb
-#  sso_name_identifier_format     :string
-#  sso_provider                   :integer          default("saml")
-#  sso_target_url                 :string
-#  terms                          :text
-#  created_at                     :datetime         not null
-#  updated_at                     :datetime         not null
-#  about_id                       :uuid             indexed => [about_type]
-#  university_id                  :uuid             not null, indexed
+#  id                         :uuid             not null, primary key
+#  about_type                 :string           indexed => [about_id]
+#  color                      :string
+#  cookies_policy             :text
+#  css                        :text
+#  feature_alumni             :boolean          default(FALSE)
+#  feature_contacts           :boolean          default(FALSE)
+#  feature_jobs               :boolean          default(FALSE)
+#  feature_library            :boolean          default(FALSE)
+#  feature_posts              :boolean          default(FALSE)
+#  has_sso                    :boolean          default(FALSE)
+#  home_sentence              :text
+#  host                       :string
+#  name                       :string
+#  privacy_policy             :text
+#  registration_contact       :string
+#  sass                       :text
+#  sso_button_label           :string
+#  sso_cert                   :text
+#  sso_mapping                :jsonb
+#  sso_name_identifier_format :string
+#  sso_provider               :integer          default("saml")
+#  sso_target_url             :string
+#  terms                      :text
+#  created_at                 :datetime         not null
+#  updated_at                 :datetime         not null
+#  about_id                   :uuid             indexed => [about_type]
+#  university_id              :uuid             not null, indexed
 #
 # Indexes
 #
diff --git a/app/models/communication/website/post.rb b/app/models/communication/website/post.rb
index a59fa872424973a64fe07f000b74e35c8ec1aa08..1d6d33d22ae24189b54e022a755ae2fc52143b9b 100644
--- a/app/models/communication/website/post.rb
+++ b/app/models/communication/website/post.rb
@@ -6,6 +6,7 @@
 #  featured_image_alt       :string
 #  featured_image_credit    :text
 #  meta_description         :text
+#  migration_identifier     :string
 #  pinned                   :boolean          default(FALSE)
 #  published                :boolean          default(FALSE)
 #  published_at             :datetime
diff --git a/app/models/university.rb b/app/models/university.rb
index 783967bd869c6ae216961b3ec9f10e7626f21adc..2789a655b08f108b736ea9a3e72e1e65db3358dd 100644
--- a/app/models/university.rb
+++ b/app/models/university.rb
@@ -56,6 +56,7 @@ class University < ApplicationRecord
   # We use after_destroy to let the attachment go first
   has_many :active_storage_blobs, class_name: 'ActiveStorage::Blob'
   has_many :imports, dependent: :destroy
+  has_many :apps, dependent: :destroy
   belongs_to :default_language, class_name: "Language"
 
   validates_presence_of :name
diff --git a/app/models/university/app.rb b/app/models/university/app.rb
new file mode 100644
index 0000000000000000000000000000000000000000..70a5952ba2f3f2fec3b4a7f9ff1458033fdf11ab
--- /dev/null
+++ b/app/models/university/app.rb
@@ -0,0 +1,52 @@
+# == Schema Information
+#
+# Table name: university_apps
+#
+#  id                  :uuid             not null, primary key
+#  name                :string
+#  token               :string           indexed
+#  token_was_displayed :boolean          default(FALSE)
+#  created_at          :datetime         not null
+#  updated_at          :datetime         not null
+#  university_id       :uuid             not null, indexed
+#
+# Indexes
+#
+#  index_university_apps_on_token          (token) UNIQUE
+#  index_university_apps_on_university_id  (university_id)
+#
+# Foreign Keys
+#
+#  fk_rails_2d07655e23  (university_id => universities.id)
+#
+class University::App < ApplicationRecord
+  TOKEN_LENGTH = 30
+
+  include WithUniversity
+
+  validates :token, uniqueness: true
+
+  before_validation :generate_token
+
+  scope :ordered, -> { order(:name) }
+
+  def display_token!
+    return false if token_was_displayed?
+    toggle!(:token_was_displayed)
+    true
+  end
+
+  def regenerate_token!
+    update(token: nil, token_was_displayed: false)
+  end
+
+  def to_s
+    "#{name}"
+  end
+
+  protected
+
+  def generate_token
+    self.token = SecureRandom.base64(TOKEN_LENGTH) if self.token.blank?
+  end
+end
diff --git a/app/views/admin/university/apps/_form.html.erb b/app/views/admin/university/apps/_form.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..2d99fdf5ef184f84ddec7e1b7361e0d70e26b857
--- /dev/null
+++ b/app/views/admin/university/apps/_form.html.erb
@@ -0,0 +1,10 @@
+<%= simple_form_for [:admin, app] do |f| %>
+  <%= f.error_notification %>
+  <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
+
+  <%= f.input :name %>
+
+  <% content_for :action_bar_right do %>
+    <%= submit f %>
+  <% end %>
+<% end %>
diff --git a/app/views/admin/university/apps/_list.html.erb b/app/views/admin/university/apps/_list.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..dac7abf24e89b47e09dcf5049c7b0eed199239aa
--- /dev/null
+++ b/app/views/admin/university/apps/_list.html.erb
@@ -0,0 +1,23 @@
+<div class="table-responsive">
+  <table class="<%= table_classes %>">
+    <thead>
+      <tr>
+        <th><%= University::App.human_attribute_name('name') %></th>
+        <th></th>
+      </tr>
+    </thead>
+    <tbody>
+      <% apps.each do |app| %>
+        <tr>
+          <td><%= link_to app, admin_university_app_path(app) %></td>
+          <td class="text-end">
+            <div class="btn-group" role="group">
+              <%= edit_link app %>
+              <%= destroy_link app %>
+            </div>
+          </td>
+        </tr>
+      <% end %>
+    </tbody>
+  </table>
+</div>
diff --git a/app/views/admin/university/apps/edit.html.erb b/app/views/admin/university/apps/edit.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..75e77d2eac6e9ff041e6bb2d13ae5a809060209c
--- /dev/null
+++ b/app/views/admin/university/apps/edit.html.erb
@@ -0,0 +1,3 @@
+<% content_for :title, @app %>
+
+<%= render 'form', app: @app %>
diff --git a/app/views/admin/university/apps/index.html.erb b/app/views/admin/university/apps/index.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..47be60d351f12117bb747579dd7621b05fd57477
--- /dev/null
+++ b/app/views/admin/university/apps/index.html.erb
@@ -0,0 +1,14 @@
+<% content_for :title, University::App.model_name.human(count: 2) %>
+
+<%
+action = ''
+action += link_to t('create'),
+                  new_admin_university_app_path,
+                  class: button_classes if can?(:create, University::App)
+subtitle = t('admin.elements', count: @apps.total_count)
+%>
+<%= osuny_panel University::App.model_name.human(count: 2), subtitle: subtitle, action: action do %>
+  <%= render 'filters', current_path: admin_university_apps_path, filters: @filters if @filters.any?  %>
+  <%= render 'admin/university/apps/list', apps: @apps %>
+  <%= paginate @apps, theme: 'bootstrap-5' %>
+<% end %>
diff --git a/app/views/admin/university/apps/new.html.erb b/app/views/admin/university/apps/new.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..f2d7dae9625c3b921b69aee42a58881b46637c7c
--- /dev/null
+++ b/app/views/admin/university/apps/new.html.erb
@@ -0,0 +1,3 @@
+<% content_for :title, University::App.model_name.human %>
+
+<%= render 'form', app: @app %>
diff --git a/app/views/admin/university/apps/show.html.erb b/app/views/admin/university/apps/show.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..bd95b1d36717d4576217304d1a9e9db54824ab55
--- /dev/null
+++ b/app/views/admin/university/apps/show.html.erb
@@ -0,0 +1,24 @@
+<% content_for :title, @app %>
+
+<% if @should_display_token %>
+  <p class="text-danger"><%= t('university.apps.token_display_notice') %></p>
+<% end %>
+
+<div class="row">
+  <div class="col-lg-6">
+    <%= osuny_label University::App.human_attribute_name('token') %>
+    <input type="string" value="<%= @should_display_token ? @app.token : masked_string(@app.token) %>" class="form-control" disabled>
+  </div>
+</div>
+
+<% content_for :action_bar_left do %>
+  <%= link_to t('university.apps.regenerate_token'),
+              [:regenerate_token, :admin, @app],
+              method: :post,
+              data: { confirm: t('please_confirm') },
+              class: 'btn btn-warning btn-xs' %>
+<% end %>
+
+<% content_for :action_bar_right do %>
+  <%= edit_link @app %>
+<% end %>
diff --git a/config/locales/university/en.yml b/config/locales/university/en.yml
index 2c134393a3a608622f7b72ef6f1db8ba3e6579dc..6672718206516c68aebb258457fcd05759bd8e33 100644
--- a/config/locales/university/en.yml
+++ b/config/locales/university/en.yml
@@ -24,6 +24,9 @@ en:
         sso_target_url: Target URL
         url: URL
         zipcode: Zipcode
+      university/app:
+        name: Name
+        token: Secret token
       university/organization:
         address: Address
         address_name: Address name
@@ -128,6 +131,9 @@ en:
       university:
         one: University
         other: Universities
+      university/app:
+        one: App
+        other: Apps
       university/person:
         one: Person
         other: People
@@ -202,7 +208,11 @@ en:
         import_btn: Import cohorts
         import_hint_html: "Possible values for <i>gender</i> are: m (male), f (female) and n (non binary).<br><i>Phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> and <i>zipcode</i> fields must have a text format, not numbers.<br><i>Country</i> field must contain the ISO 3166 code of the country, so 2 upcase characters (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">list</a>).<br><i>Social_twitter</i> field should have no @.<br><i>School</i> field should contain the internal school id.<br><i>Program</i> field should contain the internal program id."
         title: Cohorts imports
-    contributing: 
+    apps:
+      regenerate_token: Regenerate token
+      token_display_notice: Make sure to store your token somewhere safe. You won’t be able to see it again!
+      token_successfully_regenerated: The token was successfully regenerated.
+    contributing:
       one: contributing university
       other: contributing universities
     contributions_total: Contributions (total)
diff --git a/config/locales/university/fr.yml b/config/locales/university/fr.yml
index c88446772c0bb3e42008c3d87b8f0cc0466f54f8..7e71a8b68a68e594ba5a9d7b26ba602bc9440f94 100644
--- a/config/locales/university/fr.yml
+++ b/config/locales/university/fr.yml
@@ -24,6 +24,9 @@ fr:
         sso_target_url: URL cible
         url: 'URL'
         zipcode: Code postal
+      university/app:
+        name: Nom
+        token: Jeton secret
       university/organization:
         address: Adresse
         address_name: Nom de l'adresse
@@ -128,6 +131,9 @@ fr:
       university:
         one: Université
         other: Universités
+      university/app:
+        one: App
+        other: Apps
       university/person:
         one: Personne
         other: Personnes
@@ -202,7 +208,11 @@ fr:
         import_btn: Importer des promotions
         import_hint_html: "Les valeurs pour <i>gender</i> peuvent être m (masculin), f (féminin) et n (non binaire).<br>Les champs <i>phone_professional</i>, <i>phone_personal</i>, <i>mobile</i> et <i>zipcode</i> doivent être au format texte, pas nombre.<br>Le champ <i>country</i> doit contenir le code ISO 3166 du pays, sur 2 caratères en majuscule (<a href=\"https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes\" target=\_blank\">liste</a>)<br>Le champ <i>social_twitter</i> ne doit pas contenir d'@.<br>Le champ <i>school</i> doit contenir l'id interne de l'école.<br>Le champ <i>program</i> doit contenir l'id interne de la formation."
         title: Imports de promotions
-    contributing: 
+    apps:
+      regenerate_token: Regénérer le jeton
+      token_display_notice: Assurez-vous de stocker votre jeton secret de manière sécurisée. Vous ne pourrez pas le revoir !
+      token_successfully_regenerated: Le jeton a bien été regénéré.
+    contributing:
       one: université contributrice
       other: universités contributrices
     contributions_total: Contributions (total)
diff --git a/config/routes/admin/university.rb b/config/routes/admin/university.rb
index 10d8c533ac62025ac1d2e7a9e773f3a78ca7b09a..440e4fb71b06c4deeebda6c29c22a886e6150046 100644
--- a/config/routes/admin/university.rb
+++ b/config/routes/admin/university.rb
@@ -8,6 +8,9 @@ namespace :university do
       resources :imports, only: [:index, :show, :new, :create]
     end
   end
+  resources :apps do
+    post :regenerate_token, on: :member
+  end
   resources :alumni, only: [:index, :show] do
     member do
       get 'cohorts' => 'alumni/cohorts#edit'
@@ -32,7 +35,7 @@ namespace :university do
     end
   end
   resources :organizations do
-    collection do 
+    collection do
       get :search, defaults: { format: 'json' }
       resources :categories, controller: 'organizations/categories', as: 'organization_categories'
     end
diff --git a/config/routes/api.rb b/config/routes/api.rb
index 45b8a12697656e0efcd632765092a1b46ebc8b97..ead34b0004c1ecce6cf71f63d11ec43fad9e05e3 100644
--- a/config/routes/api.rb
+++ b/config/routes/api.rb
@@ -5,6 +5,9 @@ namespace :api do
     get 'communication' => 'communication#index'
     namespace :communication do
       get 'websites' => 'websites#index'
+      namespace :websites do
+        post ':website_id/posts/import' => 'posts#import'
+      end
     end
     get 'server' => 'server#index'
     namespace :server do
diff --git a/db/migrate/20230917145029_create_university_applications.rb b/db/migrate/20230917145029_create_university_applications.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d53e7416f32c0f2fe3848c83e5d3d75dea89341f
--- /dev/null
+++ b/db/migrate/20230917145029_create_university_applications.rb
@@ -0,0 +1,11 @@
+class CreateUniversityApplications < ActiveRecord::Migration[7.0]
+  def change
+    create_table :university_apps, id: :uuid do |t|
+      t.string :name
+      t.references :university, null: false, foreign_key: true, type: :uuid
+      t.string :token
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/migrate/20230917153555_add_migration_id_to_communication_websites_post.rb b/db/migrate/20230917153555_add_migration_id_to_communication_websites_post.rb
new file mode 100644
index 0000000000000000000000000000000000000000..299d20e65c41ba9f3de2c25cd4d0fba8d784b724
--- /dev/null
+++ b/db/migrate/20230917153555_add_migration_id_to_communication_websites_post.rb
@@ -0,0 +1,5 @@
+class AddMigrationIdToCommunicationWebsitesPost < ActiveRecord::Migration[7.0]
+  def change
+    add_column :communication_website_posts, :migration_identifier, :string
+  end
+end
diff --git a/db/migrate/20230917160437_add_migration_id_to_communication_blocks.rb b/db/migrate/20230917160437_add_migration_id_to_communication_blocks.rb
new file mode 100644
index 0000000000000000000000000000000000000000..acfbdbd05aafc668755095bac6a0e745ffc8f42f
--- /dev/null
+++ b/db/migrate/20230917160437_add_migration_id_to_communication_blocks.rb
@@ -0,0 +1,5 @@
+class AddMigrationIdToCommunicationBlocks < ActiveRecord::Migration[7.0]
+  def change
+    add_column :communication_blocks, :migration_identifier, :string
+  end
+end
diff --git a/db/migrate/20230918105825_add_keys_to_university_apps.rb b/db/migrate/20230918105825_add_keys_to_university_apps.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c0e6933621254ac5496eb90eab433a89738a9ac3
--- /dev/null
+++ b/db/migrate/20230918105825_add_keys_to_university_apps.rb
@@ -0,0 +1,6 @@
+class AddKeysToUniversityApps < ActiveRecord::Migration[7.0]
+  def change
+    add_column :university_apps, :access_key, :string
+    rename_column :university_apps, :token, :secret_key
+  end
+end
diff --git a/db/migrate/20230925125538_set_single_token_for_university_apps.rb b/db/migrate/20230925125538_set_single_token_for_university_apps.rb
new file mode 100644
index 0000000000000000000000000000000000000000..95495862681e4901a24ffd70c94fbe8f81f33153
--- /dev/null
+++ b/db/migrate/20230925125538_set_single_token_for_university_apps.rb
@@ -0,0 +1,8 @@
+class SetSingleTokenForUniversityApps < ActiveRecord::Migration[7.0]
+  def change
+    remove_column :university_apps, :access_key
+    rename_column :university_apps, :secret_key, :token
+    add_index :university_apps, :token, unique: true
+    add_column :university_apps, :token_was_displayed, :boolean, default: false
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index b7ce0e815da0bdba64e82a2b221194bb8933ba33..10b2f9dba3fa6b50d6b72e51de8761fefdd7641c 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema[7.0].define(version: 2023_09_14_101635) do
+ActiveRecord::Schema[7.0].define(version: 2023_09_25_125538) do
   # These are extensions that must be enabled in order to support this database
   enable_extension "pgcrypto"
   enable_extension "plpgsql"
@@ -105,8 +105,9 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_14_101635) do
     t.datetime "updated_at", null: false
     t.string "title"
     t.boolean "published", default: true
-    t.uuid "communication_website_id"
     t.uuid "heading_id"
+    t.uuid "communication_website_id"
+    t.string "migration_identifier"
     t.index ["about_type", "about_id"], name: "index_communication_website_blocks_on_about"
     t.index ["communication_website_id"], name: "index_communication_blocks_on_communication_website_id"
     t.index ["heading_id"], name: "index_communication_blocks_on_heading_id"
@@ -223,7 +224,6 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_14_101635) do
     t.text "home_sentence"
     t.text "sass"
     t.text "css"
-    t.boolean "allow_experiences_modification", default: true
     t.index ["about_type", "about_id"], name: "index_communication_extranets_on_about"
     t.index ["university_id"], name: "index_communication_extranets_on_university_id"
   end
@@ -489,7 +489,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_14_101635) do
     t.index ["university_id"], name: "index_communication_website_pages_on_university_id"
   end
 
-  create_table "communication_website_permalinks", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+  create_table "communication_website_permalinks", id: :uuid, default: -> { "public.gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "website_id", null: false
     t.string "about_type", null: false
@@ -521,6 +521,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_14_101635) do
     t.uuid "language_id", null: false
     t.text "featured_image_credit"
     t.uuid "original_id"
+    t.string "migration_identifier"
     t.index ["author_id"], name: "index_communication_website_posts_on_author_id"
     t.index ["communication_website_id"], name: "index_communication_website_posts_on_communication_website_id"
     t.index ["language_id"], name: "index_communication_website_posts_on_language_id"
@@ -970,6 +971,17 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_14_101635) do
     t.index ["default_language_id"], name: "index_universities_on_default_language_id"
   end
 
+  create_table "university_apps", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+    t.string "name"
+    t.uuid "university_id", null: false
+    t.string "token"
+    t.datetime "created_at", null: false
+    t.datetime "updated_at", null: false
+    t.boolean "token_was_displayed", default: false
+    t.index ["token"], name: "index_university_apps_on_token", unique: true
+    t.index ["university_id"], name: "index_university_apps_on_university_id"
+  end
+
   create_table "university_organization_categories", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
     t.string "name"
     t.uuid "university_id", null: false
@@ -1282,6 +1294,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_14_101635) do
   add_foreign_key "research_theses", "university_people", column: "author_id"
   add_foreign_key "research_theses", "university_people", column: "director_id"
   add_foreign_key "universities", "languages", column: "default_language_id"
+  add_foreign_key "university_apps", "universities"
   add_foreign_key "university_organization_categories", "universities"
   add_foreign_key "university_organizations", "languages"
   add_foreign_key "university_organizations", "universities"
diff --git a/test/fixtures/communication/blocks.yml b/test/fixtures/communication/blocks.yml
index 70569fd8d2063f15ccbb63db96fed64c4665da24..58b3307202f84330e33a32036c87f8f7511736e3 100644
--- a/test/fixtures/communication/blocks.yml
+++ b/test/fixtures/communication/blocks.yml
@@ -5,6 +5,7 @@
 #  id                       :uuid             not null, primary key
 #  about_type               :string           indexed => [about_id]
 #  data                     :jsonb
+#  migration_identifier     :string
 #  position                 :integer          default(0), not null
 #  published                :boolean          default(TRUE)
 #  template_kind            :integer          default(NULL), not null
diff --git a/test/fixtures/communication/extranets.yml b/test/fixtures/communication/extranets.yml
index 5b00f559b78ac19b9a3871e2736923e92e325c4b..c4a72564511a4905256b44eff1b90d9ad95d76db 100644
--- a/test/fixtures/communication/extranets.yml
+++ b/test/fixtures/communication/extranets.yml
@@ -2,35 +2,34 @@
 #
 # Table name: communication_extranets
 #
-#  id                             :uuid             not null, primary key
-#  about_type                     :string           indexed => [about_id]
-#  allow_experiences_modification :boolean          default(TRUE)
-#  color                          :string
-#  cookies_policy                 :text
-#  css                            :text
-#  feature_alumni                 :boolean          default(FALSE)
-#  feature_contacts               :boolean          default(FALSE)
-#  feature_jobs                   :boolean          default(FALSE)
-#  feature_library                :boolean          default(FALSE)
-#  feature_posts                  :boolean          default(FALSE)
-#  has_sso                        :boolean          default(FALSE)
-#  home_sentence                  :text
-#  host                           :string
-#  name                           :string
-#  privacy_policy                 :text
-#  registration_contact           :string
-#  sass                           :text
-#  sso_button_label               :string
-#  sso_cert                       :text
-#  sso_mapping                    :jsonb
-#  sso_name_identifier_format     :string
-#  sso_provider                   :integer          default("saml")
-#  sso_target_url                 :string
-#  terms                          :text
-#  created_at                     :datetime         not null
-#  updated_at                     :datetime         not null
-#  about_id                       :uuid             indexed => [about_type]
-#  university_id                  :uuid             not null, indexed
+#  id                         :uuid             not null, primary key
+#  about_type                 :string           indexed => [about_id]
+#  color                      :string
+#  cookies_policy             :text
+#  css                        :text
+#  feature_alumni             :boolean          default(FALSE)
+#  feature_contacts           :boolean          default(FALSE)
+#  feature_jobs               :boolean          default(FALSE)
+#  feature_library            :boolean          default(FALSE)
+#  feature_posts              :boolean          default(FALSE)
+#  has_sso                    :boolean          default(FALSE)
+#  home_sentence              :text
+#  host                       :string
+#  name                       :string
+#  privacy_policy             :text
+#  registration_contact       :string
+#  sass                       :text
+#  sso_button_label           :string
+#  sso_cert                   :text
+#  sso_mapping                :jsonb
+#  sso_name_identifier_format :string
+#  sso_provider               :integer          default("saml")
+#  sso_target_url             :string
+#  terms                      :text
+#  created_at                 :datetime         not null
+#  updated_at                 :datetime         not null
+#  about_id                   :uuid             indexed => [about_type]
+#  university_id              :uuid             not null, indexed
 #
 # Indexes
 #
diff --git a/test/fixtures/communication/website/posts.yml b/test/fixtures/communication/website/posts.yml
index b63bfa60e1f8eaee67ae1e474eef151de45a1c5f..70ba9563ed0af6083003e3be91abdc19f36af99f 100644
--- a/test/fixtures/communication/website/posts.yml
+++ b/test/fixtures/communication/website/posts.yml
@@ -6,6 +6,7 @@
 #  featured_image_alt       :string
 #  featured_image_credit    :text
 #  meta_description         :text
+#  migration_identifier     :string
 #  pinned                   :boolean          default(FALSE)
 #  published                :boolean          default(FALSE)
 #  published_at             :datetime
diff --git a/test/fixtures/university/apps.yml b/test/fixtures/university/apps.yml
new file mode 100644
index 0000000000000000000000000000000000000000..09f154e0b504b29af65474e4102fff684c7e4b81
--- /dev/null
+++ b/test/fixtures/university/apps.yml
@@ -0,0 +1,31 @@
+# == Schema Information
+#
+# Table name: university_apps
+#
+#  id                  :uuid             not null, primary key
+#  name                :string
+#  token               :string           indexed
+#  token_was_displayed :boolean          default(FALSE)
+#  created_at          :datetime         not null
+#  updated_at          :datetime         not null
+#  university_id       :uuid             not null, indexed
+#
+# Indexes
+#
+#  index_university_apps_on_token          (token) UNIQUE
+#  index_university_apps_on_university_id  (university_id)
+#
+# Foreign Keys
+#
+#  fk_rails_2d07655e23  (university_id => universities.id)
+#
+
+one:
+  name: MyString
+  university: one
+  token: MyString
+
+two:
+  name: MyString
+  university: two
+  token: MyOtherString
diff --git a/test/models/university/app_test.rb b/test/models/university/app_test.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9562b2c9eb23d57e7436b906e0231fec2a39d92c
--- /dev/null
+++ b/test/models/university/app_test.rb
@@ -0,0 +1,28 @@
+# == Schema Information
+#
+# Table name: university_apps
+#
+#  id                  :uuid             not null, primary key
+#  name                :string
+#  token               :string           indexed
+#  token_was_displayed :boolean          default(FALSE)
+#  created_at          :datetime         not null
+#  updated_at          :datetime         not null
+#  university_id       :uuid             not null, indexed
+#
+# Indexes
+#
+#  index_university_apps_on_token          (token) UNIQUE
+#  index_university_apps_on_university_id  (university_id)
+#
+# Foreign Keys
+#
+#  fk_rails_2d07655e23  (university_id => universities.id)
+#
+require "test_helper"
+
+class University::ApplicationTest < ActiveSupport::TestCase
+  # test "the truth" do
+  #   assert true
+  # end
+end