diff --git a/autograde-service/src/test/java/ch/epfl/autograde/controller/api/v1/SubmissionControllerIntegrationTests.java b/autograde-service/src/test/java/ch/epfl/autograde/controller/api/v1/SubmissionControllerIntegrationTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..61afc2f4a4af72501e2eefe55f22bec7ce0bd562
--- /dev/null
+++ b/autograde-service/src/test/java/ch/epfl/autograde/controller/api/v1/SubmissionControllerIntegrationTests.java
@@ -0,0 +1,183 @@
+package ch.epfl.autograde.controller.api.v1;
+
+import ch.epfl.autograde.filters.AssignRequestIdFilter;
+import ch.epfl.autograde.utils.context.WithSharedSecretAuthentication;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.HttpHeaders;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.util.Random;
+
+import static java.lang.String.format;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
+
+/**
+ * Test class for the {@link SubmissionController} API.
+ * <p>
+ * This class verifies the behaviour of the submissions endpoint provided by the API:
+ * <ul>
+ *   <li>{@code POST:/api/v1/submission}</li>
+ *   <li>{@code GET:/api/v1/submission/{id}}</li>
+ *   <li>{@code GET:/api/v1/submission/{id}/status}</li>
+ *   <li>{@code GET:/api/v1/submission/{id}/files}</li>
+ *   <li>{@code POST:/api/v1/submission/{id}/feedback}</li>
+ * </ul>
+ * It uses Spring Boot's {@link MockMvc} for testing HTTP requests and responses,
+ * and the {@link WithSharedSecretAuthentication} annotation to simulate requests
+ * with <i>shared secret</i> authentication.
+ *
+ * @see ch.epfl.autograde.controller.api.v1.SubmissionController
+ * @see ch.epfl.autograde.config.SecurityConfig
+ *
+ * @author Hamza REMMAL (hamza.remmal@epfl.ch)
+ */
+@SpringBootTest
+@AutoConfigureMockMvc
+@DisplayName("[Integration Tests] '/api/v1/submission/**'")
+final class SubmissionControllerIntegrationTests {
+
+  private final Random rnd = new Random();
+  @Autowired private MockMvc mockMvc;
+
+  // ==============================================================================================
+  // ================================== POST:/api/v1/submission ===================================
+  // ==============================================================================================
+
+  /**
+   * If <b>not</b> authenticated with the shared secret, the request to {@code POST:/api/v1/submission}
+   * should <b>fail</b>
+   * <p>
+   * The following test will verify that:
+   * <ul>
+   *   <li>The HTTP Status is {@link org.springframework.http.HttpStatus.UNAUTHORIZED}</li>
+   *   <li>The request will not generate cookies</li>
+   *   <li>A `X-Request-Id` header was set in the response</li>
+   * </ul>
+   */
+  @Test
+  @DisplayName("'POST:/api/v1/submission' returns 401 when unauthenticated")
+  void createSubmissionShouldBeAuthenticated() throws Exception {
+    mockMvc.perform(post("/api/v1/submission"))
+            .andExpectAll(
+                    status().isUnauthorized(),
+                    header().doesNotExist(HttpHeaders.SET_COOKIE),
+                    header().exists(AssignRequestIdFilter.REQUEST_ID_HEADER)
+            );
+  }
+
+  // ==============================================================================================
+  // ================================ GET:/api/v1/submission/{id} =================================
+  // ==============================================================================================
+
+  /**
+   * If <b>not</b> authenticated with the shared secret, the request to {@code GET:/api/v1/submission/{id}}
+   * should <b>fail</b>
+   * <p>
+   * The following test will verify that:
+   * <ul>
+   *   <li>The HTTP Status is {@link org.springframework.http.HttpStatus.UNAUTHORIZED}</li>
+   *   <li>The request will not generate cookies</li>
+   *   <li>A `X-Request-Id` header was set in the response</li>
+   * </ul>
+   */
+  @Test
+  @DisplayName("'GET:/api/v1/submission/{id}' returns 401 when unauthenticated")
+  void fetchingSubmissionShouldBeAuthenticated() throws Exception {
+    final var id = rnd.nextInt();
+    mockMvc.perform(get(format("/api/v1/submission/%d", id)))
+            .andExpectAll(
+                    status().isUnauthorized(),
+                    header().doesNotExist(HttpHeaders.SET_COOKIE),
+                    header().exists(AssignRequestIdFilter.REQUEST_ID_HEADER)
+            );
+  }
+
+  // ==============================================================================================
+  // ============================= GET:/api/v1/submission/{id}/status =============================
+  // ==============================================================================================
+
+  /**
+   * If <b>not</b> authenticated with the shared secret, the request to {@code GET:/api/v1/submission/{id}/status}
+   * should <b>fail</b>
+   * <p>
+   * The following test will verify that:
+   * <ul>
+   *   <li>The HTTP Status is {@link org.springframework.http.HttpStatus.UNAUTHORIZED}</li>
+   *   <li>The request will not generate cookies</li>
+   *   <li>A `X-Request-Id` header was set in the response</li>
+   * </ul>
+   */
+  @Test
+  @DisplayName("'GET:/api/v1/submission/{id}/status' returns 401 when unauthenticated")
+  void statusShouldBeAuthenticated() throws Exception {
+    final var id = rnd.nextInt();
+    mockMvc.perform(get(format("/api/v1/submission/%d/status", id)))
+            .andExpectAll(
+                    status().isUnauthorized(),
+                    header().doesNotExist(HttpHeaders.SET_COOKIE),
+                    header().exists(AssignRequestIdFilter.REQUEST_ID_HEADER)
+            );
+  }
+
+  // ==============================================================================================
+  // ============================= GET:/api/v1/submission/{id}/files ==============================
+  // ==============================================================================================
+
+  /**
+   * If <b>not</b> authenticated with the shared secret, the request to {@code GET:/api/v1/submission/{id}/files}
+   * should <b>fail</b>
+   * <p>
+   * The following test will verify that:
+   * <ul>
+   *   <li>The HTTP Status is {@link org.springframework.http.HttpStatus.UNAUTHORIZED}</li>
+   *   <li>The request will not generate cookies</li>
+   *   <li>A `X-Request-Id` header was set in the response</li>
+   * </ul>
+   */
+  @Test
+  @DisplayName("'GET:/api/v1/submission/{id}/files' returns 401 when unauthenticated")
+  void submissionFilesShouldBeAuthenticated() throws Exception {
+    final var id = rnd.nextInt();
+    mockMvc.perform(get(format("/api/v1/submission/%d/files", id)))
+            .andExpectAll(
+                    status().isUnauthorized(),
+                    header().doesNotExist(HttpHeaders.SET_COOKIE),
+                    header().exists(AssignRequestIdFilter.REQUEST_ID_HEADER)
+            );
+  }
+
+  // ==============================================================================================
+  // ============================ POST:/api/v1/submission/{id}/feedback ===========================
+  // ==============================================================================================
+
+  /**
+   * If <b>not</b> authenticated with the shared secret, the request to {@code POST:/api/v1/submission/{id}/feedback}
+   * should <b>fail</b>
+   * <p>
+   * The following test will verify that:
+   * <ul>
+   *   <li>The HTTP Status is {@link org.springframework.http.HttpStatus.UNAUTHORIZED}</li>
+   *   <li>The request will not generate cookies</li>
+   *   <li>A `X-Request-Id` header was set in the response</li>
+   * </ul>
+   */
+  @Test
+  @DisplayName("'POST:/api/v1/submission/{id}/feedback' returns 401 when unauthenticated")
+  void uploadFeedbackShouldBeAuthenticated() throws Exception {
+    final var id = rnd.nextInt();
+    mockMvc.perform(post(format("/api/v1/submission/%d/feedback", id)))
+            .andExpectAll(
+                    status().isUnauthorized(),
+                    header().doesNotExist(HttpHeaders.SET_COOKIE),
+                    header().exists(AssignRequestIdFilter.REQUEST_ID_HEADER)
+            );
+  }
+
+}