diff --git a/swh/web/assets/src/bundles/vault/vault-ui.js b/swh/web/assets/src/bundles/vault/vault-ui.js
index 8dc7203cb8746088c662c176f7fd671020f685c1..78540e41368136047c24c5fcdbe6f655f8bcf410 100644
--- a/swh/web/assets/src/bundles/vault/vault-ui.js
+++ b/swh/web/assets/src/bundles/vault/vault-ui.js
@@ -5,7 +5,7 @@
  * See top-level LICENSE file for more information
  */
 
-import {handleFetchErrors} from 'utils/functions';
+import {handleFetchError, handleFetchErrors} from 'utils/functions';
 
 let progress = `<div class="progress">
                   <div class="progress-bar progress-bar-success progress-bar-striped"
@@ -36,6 +36,77 @@ function updateProgressBar(progressBar, cookingTask) {
   }
 }
 
+let recookTask;
+
+// called when the user wants to download a cooked archive
+export function fetchCookedObject(fetchUrl) {
+  recookTask = null;
+  // first, check if the link is still available from the vault
+  fetch(fetchUrl, {credentials: 'same-origin'})
+    .then(response => {
+      // link is still alive, proceed to download
+      if (response.ok) {
+        $('#vault-fetch-iframe').attr('src', fetchUrl);
+      // link is dead
+      } else {
+        // get the associated cooking task
+        let vaultCookingTasks = JSON.parse(localStorage.getItem('swh-vault-cooking-tasks'));
+        for (let i = 0; i < vaultCookingTasks.length; ++i) {
+          if (vaultCookingTasks[i].fetch_url === fetchUrl) {
+            recookTask = vaultCookingTasks[i];
+            break;
+          }
+        }
+        // display a modal asking the user if he wants to recook the archive
+        $('#vault-recook-object-modal').modal('show');
+      }
+    });
+}
+
+// called when the user wants to recook an archive
+// for which the download link is not available anymore
+export function recookObject() {
+  if (recookTask) {
+    // stop cookink tasks status polling
+    clearTimeout(checkVaultId);
+    // build cook request url
+    let cookingUrl;
+    if (recookTask.object_type === 'directory') {
+      cookingUrl = Urls.vault_cook_directory(recookTask.object_id);
+    } else {
+      cookingUrl = Urls.vault_cook_revision_gitfast(recookTask.object_id);
+    }
+    if (recookTask.email) {
+      cookingUrl += '?email=' + recookTask.email;
+    }
+    // request archive cooking
+    fetch(cookingUrl, {credentials: 'same-origin', method: 'POST'})
+      .then(handleFetchError)
+      .then(() => {
+        // update task status
+        recookTask.status = 'new';
+        let vaultCookingTasks = JSON.parse(localStorage.getItem('swh-vault-cooking-tasks'));
+        for (let i = 0; i < vaultCookingTasks.length; ++i) {
+          if (vaultCookingTasks[i].object_id === recookTask.object_id) {
+            vaultCookingTasks[i] = recookTask;
+            break;
+          }
+        }
+        // save updated tasks to local storage
+        localStorage.setItem('swh-vault-cooking-tasks', JSON.stringify(vaultCookingTasks));
+        // restart cooking tasks status polling
+        checkVaultCookingTasks();
+        // hide recook archive modal
+        $('#vault-recook-object-modal').modal('hide');
+      })
+      // something went wrong
+      .catch(() => {
+        checkVaultCookingTasks();
+        $('#vault-recook-object-modal').modal('hide');
+      });
+  }
+}
+
 function checkVaultCookingTasks() {
   let vaultCookingTasks = JSON.parse(localStorage.getItem('swh-vault-cooking-tasks'));
   if (!vaultCookingTasks || vaultCookingTasks.length === 0) {
@@ -83,6 +154,7 @@ function checkVaultCookingTasks() {
 
         let rowTask = $('#vault-task-' + cookingTask.object_id);
 
+        let downloadLinkWait = 'Waiting for download link to be available';
         if (!rowTask.length) {
 
           let browseUrl;
@@ -111,10 +183,10 @@ function checkVaultCookingTasks() {
           }
           tableRow += `<td class="vault-object-id" data-object-id="${cookingTask.object_id}"><a href="${browseUrl}">${cookingTask.object_id}</a></td>`;
           tableRow += `<td style="width: 350px">${progressBar.outerHTML}</td>`;
-          let downloadLink = 'Waiting for download link to be available';
+          let downloadLink = downloadLinkWait;
           if (cookingTask.status === 'done') {
-            downloadLink = `<a class="btn btn-default btn-sm" href="${cookingTask.fetch_url}` +
-                           '"><i class="fa fa-download fa-fw" aria-hidden="true"></i>Download</a>';
+            downloadLink = `<button class="btn btn-default btn-sm" onclick="swh.vault.fetchCookedObject('${cookingTask.fetch_url}')` +
+                           '"><i class="fa fa-download fa-fw" aria-hidden="true"></i>Download</button>';
           } else if (cookingTask.status === 'failed') {
             downloadLink = '';
           }
@@ -126,10 +198,12 @@ function checkVaultCookingTasks() {
           updateProgressBar(progressBar, cookingTask);
           let downloadLink = rowTask.find('.vault-dl-link');
           if (cookingTask.status === 'done') {
-            downloadLink[0].innerHTML = `<a class="btn btn-default btn-sm" href="${cookingTask.fetch_url}` +
-                                        '"><i class="fa fa-download fa-fw" aria-hidden="true"></i>Download</a>';
+            downloadLink[0].innerHTML = `<button class="btn btn-default btn-sm" onclick="swh.vault.fetchCookedObject('${cookingTask.fetch_url}')` +
+                                        '"><i class="fa fa-download fa-fw" aria-hidden="true"></i>Download</button>';
           } else if (cookingTask.status === 'failed') {
             downloadLink[0].innerHTML = '';
+          } else if (cookingTask.status === 'new') {
+            downloadLink[0].innerHTML = downloadLinkWait;
           }
         }
       }
diff --git a/swh/web/templates/browse-vault-ui.html b/swh/web/templates/browse-vault-ui.html
index d013821fa4f3488cbf17921de1a5e5d3dbd23585..8ec181223d0c58a932dfda5cf98bae2c0d83b753 100644
--- a/swh/web/templates/browse-vault-ui.html
+++ b/swh/web/templates/browse-vault-ui.html
@@ -37,7 +37,31 @@ See top-level LICENSE file for more information
     <tbody></tbody>
   </table>
 </div>
-
+<iframe id="vault-fetch-iframe" style="display:none;"></iframe>
+<div class="modal fade" id="vault-recook-object-modal" tabindex="-1" role="dialog" aria-labelledby="vault-recook-object-modal-label" aria-hidden="true">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <h6 class="modal-title" id="vault-recook-object-modal-label">Download link no more available</h6>
+        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+          <span aria-hidden="true">&times;</span>
+        </button>
+      </div>
+      <div class="modal-body">
+        <p>
+          The requested archive is no more available to download from the Sofware Heritage Vault.
+        </p>
+        <p>
+          Do you want to cook it again ?
+        </p>
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default btn-sm" data-dismiss="modal">Cancel</button>
+        <button type="button" class="btn btn-default btn-sm" onclick="swh.vault.recookObject()">Ok</button>
+      </div>
+    </div>
+  </div>
+</div>
 <script>
   swh.webapp.initPage('vault');
   swh.vault.initUi();