diff --git a/Jenkinsfile b/Jenkinsfile
index 3930b1cd1e18ebf535cd77abc6558effcd821cfb..3e7478257217b97d82661da7f76a3f80ae647239 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,5 +1,9 @@
 @Library('releng-pipeline') _
 
+withCredentials([string(credentialsId: 'gitlab-api-token', variable: 'GITLAB_API_TOKEN')]) {
+    env.GITLAB_API_TOKEN = GITLAB_API_TOKEN
+}
+
 hugo (
   appName: 'webdev.eclipse.org-spec-host',
   productionDomain: 'webdev.eclipse.org',
diff --git a/repos.yaml b/repos.yaml
index aebbfeb41946e51c25013b3d8778902a28a7a3a1..d672a68af2e3f10a1bfffc8c81f098d829ae5390 100644
--- a/repos.yaml
+++ b/repos.yaml
@@ -50,3 +50,7 @@ specs:
   - name: "eclipsefdn-info-api"
     displayName: Info API
     location: "https://gitlab.eclipse.org/eclipsefdn/it/api/eclipsefdn-info-api/-/raw/main/spec/openapi.yaml"
+  - name: eclipse-projects-api
+    displayName: Projects API
+    location: "https://gitlab.eclipse.org/api/v4/projects/1641/repository/files/spec%2Fopenapi%2Eyaml/raw"
+    isPrivate: true
diff --git a/src/index.js b/src/index.js
index a96abc20cd69392a075c38d50558bea68e8c2c3e..c38f7d66ed695406be83a19665a67f8a4e31d320 100644
--- a/src/index.js
+++ b/src/index.js
@@ -24,21 +24,27 @@ const URL_REGEX = new RegExp('^https?://(?:[^./]+.){1,3}.[a-z]{2,3}(/[^/]+)*.[a-
 const TEMP_DIR_NAME = 'tmp';
 // the const to hold the generated spec data to be output for Hugo builds
 const artificialSpecData = { items: [] };
+const PRIVATE_TOKEN = process.env.GITLAB_API_TOKEN;
 
 /**
  * Pull an external/remote spec using fetch and write it to the file system for further processing.
  *
  * @param {*} externalLocation the URL for the raw openapi spec file.
  * @param {*} localPath the location where the downloaded spec should be saved
+ * @param {boolean} isPrivate optional, whether an external spec is in a private GitLab repository and should use secret token for access
  */
-async function pullExternalSpec(externalLocation, localPath) {
+async function pullExternalSpec(externalLocation, localPath, isPrivate = false) {
   let retries = 0;
   // retry 3 times before giving up
   while (retries < 3) {
     try {
       fs.writeFileSync(
         localPath,
-        await fetch(externalLocation).then(response => {
+        await fetch(externalLocation, {
+          headers: {
+            "PRIVATE-TOKEN": isPrivate ? PRIVATE_TOKEN : ''
+          }
+        }).then(response => {
           if (!response.ok) {
             throw new Error(`HTTP error! Status: ${response.status}`);
           }
@@ -113,6 +119,7 @@ async function run() {
     const specMachineName = currentSpecDefinition['name'];
     const specDisplayName = currentSpecDefinition['displayName'] || currentSpecDefinition['name'];
     const specLocation = currentSpecDefinition['location'];
+    const isSpecPrivate = currentSpecDefinition['isPrivate'];
     const potentialLocalSpecLocation = `${initialProjectDirectory}${path.sep}${specLocation}`;
     const outputSpecLocation = `${specMachineName}${path.sep}openapi.yaml`;
 
@@ -122,7 +129,7 @@ async function run() {
     console.log(`Retrieving openapi spec for ${specDisplayName}...`);
     // prepare the spec, fetching remote specs or copying the spec for processing
     if (isExternalSpec(specLocation)) {
-      await pullExternalSpec(specLocation, outputSpecLocation);
+      await pullExternalSpec(specLocation, outputSpecLocation, isSpecPrivate);
     } else {
       fs.copyFileSync(potentialLocalSpecLocation, outputSpecLocation);
       console.log(`Copied local spec for ${specDisplayName} to output dir`);