diff --git a/src/components/S3KeyView.vue b/src/components/S3KeyView.vue
index 71c865308c06a0bd2b731658fca1023429b3a91c..0ba2f825236449fea35edcc8af05c32581aa4f06 100644
--- a/src/components/S3KeyView.vue
+++ b/src/components/S3KeyView.vue
@@ -3,9 +3,15 @@ import type { S3Key } from "@/client";
 import type { Ref } from "vue";
 import { ref, watch } from "vue";
 import BootstrapIcon from "@/components/BootstrapIcon.vue";
+import DeleteModal from "@/components/Modals/DeleteModal.vue";
 
 const props = defineProps<{
   s3key: S3Key;
+  deletable: boolean;
+}>();
+
+const emit = defineEmits<{
+  (e: "delete-key", accessKey: string): void;
 }>();
 
 watch(
@@ -16,9 +22,22 @@ watch(
 );
 
 const visibleSecret: Ref<boolean> = ref(false);
+
+function deleteKeyTrigger() {
+  if (props.deletable) {
+    emit("delete-key", props.s3key.access_key);
+  }
+}
 </script>
 
 <template>
+  <DeleteModal
+    modalID="delete-key-modal"
+    modal-label="Delete S3 Key"
+    :object-name-delete="props.s3key.access_key"
+    :back-modal-id="undefined"
+    @confirm-delete="deleteKeyTrigger"
+  />
   <h3>Access Key:</h3>
   <input
     class="form-control-plaintext text-white fs-4"
@@ -52,7 +71,15 @@ const visibleSecret: Ref<boolean> = ref(false);
     aria-describedby="s3-secret-key"
     readonly
   />
-  <button type="button" class="btn btn-danger fs-5" disabled>Delete</button>
+  <button
+    type="button"
+    class="btn btn-danger fs-5"
+    :disabled="!props.deletable"
+    data-bs-toggle="modal"
+    data-bs-target="#delete-key-modal"
+  >
+    Delete
+  </button>
 </template>
 
 <style scoped></style>
diff --git a/src/views/object-storage/S3KeysView.vue b/src/views/object-storage/S3KeysView.vue
index 8995f7d4a074ee2769ae519bab8bf4fca75f364a..6f6d0f386a579a198ae02e3b6effd9e1a0fbf6df 100644
--- a/src/views/object-storage/S3KeysView.vue
+++ b/src/views/object-storage/S3KeysView.vue
@@ -1,9 +1,11 @@
 <script setup lang="ts">
 import S3KeyView from "@/components/S3KeyView.vue";
-import { reactive, onMounted } from "vue";
+import { reactive, onMounted, computed } from "vue";
+import type { ComputedRef } from "vue";
 import type { S3Key } from "@/client";
 import { KeyService } from "@/client";
 import { useAuthStore } from "@/stores/auth";
+import { Toast } from "bootstrap";
 
 const authStore = useAuthStore();
 
@@ -13,26 +15,51 @@ authStore.$onAction(({ name, args }) => {
   }
 });
 
+let successToast: Toast | null = null;
+
 const keyState = reactive({
   keys: [],
   activeKey: 0,
-  loading: true,
+  initialLoading: true,
+  deletedKey: "",
 } as {
   keys: S3Key[];
   activeKey: number;
-  loading: boolean;
+  initialLoading: boolean;
+  deletedKey: string;
 });
 
+const allowKeyDeletion: ComputedRef<boolean> = computed(
+  () => keyState.keys.length > 1
+);
+
 function refreshKeys(uid: string) {
   KeyService.keyGetUserKeys(uid)
     .then((keys) => {
       keyState.keys = keys;
     })
     .catch((err) => console.error(err))
-    .finally(() => (keyState.loading = false));
+    .finally(() => (keyState.initialLoading = false));
+}
+
+function deleteKey(accessKey: string) {
+  if (allowKeyDeletion.value && authStore.user != null) {
+    KeyService.keyDeleteUserKey(accessKey, authStore.user.uid)
+      .then(() => {
+        keyState.deletedKey = accessKey;
+        keyState.activeKey = 0;
+        keyState.keys = keyState.keys.filter(
+          (s3key) => s3key.access_key !== accessKey
+        );
+        authStore.setS3Key(keyState.keys[0]);
+        successToast?.show();
+      })
+      .catch((err) => console.error(err));
+  }
 }
 
 onMounted(() => {
+  successToast = new Toast("#successKeyToast");
   if (authStore.user != null) {
     refreshKeys(authStore.user.uid);
   }
@@ -40,6 +67,28 @@ onMounted(() => {
 </script>
 
 <template>
+  <div class="toast-container position-fixed top-0 end-0 p-3">
+    <div
+      role="alert"
+      aria-live="assertive"
+      aria-atomic="true"
+      class="toast text-bg-success align-items-center border-0"
+      data-bs-autohide="true"
+      :id="'successKeyToast'"
+    >
+      <div class="d-flex">
+        <div class="toast-body">
+          Successfully deleted S3 Key {{ keyState.deletedKey }}
+        </div>
+        <button
+          type="button"
+          class="btn-close btn-close-white me-2 m-auto"
+          data-bs-dismiss="toast"
+          aria-label="Close"
+        ></button>
+      </div>
+    </div>
+  </div>
   <div class="row m-2 border-bottom border-light mt-4">
     <div class="col-12"></div>
     <h1 class="mb-2 text-light">S3 Keys</h1>
@@ -63,6 +112,8 @@ onMounted(() => {
       <s3-key-view
         v-if="keyState.keys.length > 0"
         :s3key="keyState.keys[keyState.activeKey]"
+        :deletable="allowKeyDeletion"
+        @delete-key="deleteKey"
       />
       <div v-else>
         No keys here. <br />