diff --git a/apps/ssi-abstraction/package.json b/apps/ssi-abstraction/package.json
index f7770f308e79f6b5d2bcdaa9e11656d3302695a0..3bbea7c653d57e8e8dcf25a8ce994dcef3fcd7c9 100644
--- a/apps/ssi-abstraction/package.json
+++ b/apps/ssi-abstraction/package.json
@@ -34,8 +34,8 @@
     "@ocm/shared": "workspace:*",
     "axios": "^1.6.2",
     "express": "^4.17.3",
-    "form-data": "^4.0.0",
     "joi": "^17.6.0",
+    "minio": "^7.1.3",
     "nats": "^2.18.0",
     "rxjs": "^7.2.0",
     "winston": "^3.11.0"
diff --git a/apps/ssi-abstraction/src/agent/revocation/TailsFileService.ts b/apps/ssi-abstraction/src/agent/revocation/TailsFileService.ts
index 9938242e0ca4c19d0098762a6f03c14f7bd92ce1..2c3dbb831c33aee773c713f35f54d0d8bd6a8b37 100644
--- a/apps/ssi-abstraction/src/agent/revocation/TailsFileService.ts
+++ b/apps/ssi-abstraction/src/agent/revocation/TailsFileService.ts
@@ -2,52 +2,8 @@ import type { AnonCredsRevocationRegistryDefinition } from '@credo-ts/anoncreds'
 import type { AgentContext } from '@credo-ts/core';
 
 import { BasicTailsFileService } from '@credo-ts/anoncreds';
-import FormData from 'form-data';
 import fs from 'fs';
-
-export type UploadToS3Options = {
-  s3Url: string;
-  bucketName: string;
-  fileId: string;
-  content: Uint8Array;
-  accessKey: string;
-  secret: string;
-};
-
-// Upload to S3 and return the URL to fetch it from
-export const uploadToS3 = async ({
-  s3Url,
-  content,
-  fileId,
-  bucketName,
-  accessKey,
-  secret,
-}: UploadToS3Options) => {
-  // TODO: double check all headers
-  const headers = new Headers();
-  headers.set('Host', s3Url);
-  headers.set('Date', generateRfc1123Date());
-  headers.set('Content-Type', 'application/octet-stream');
-  headers.set('Authorization', accessKey);
-  headers.set('Secret', secret);
-
-  const sanitizedUrl = s3Url.endsWith('/')
-    ? s3Url.slice(0, s3Url.length - 1)
-    : s3Url;
-
-  const url = `${sanitizedUrl}/${bucketName}/${fileId}`;
-
-  // TODO: check whether we need to include the sig or not
-  const result = await axios.put(url, content, {
-    headers,
-  });
-
-  if (result.status > 299) {
-    throw new Error(`Error uploading to S3. Error: ${JSON.stringify(result)}`);
-  }
-
-  return url;
-};
+import { Client } from 'minio';
 
 export class S3TailsFileService extends BasicTailsFileService {
   private tailsServerBaseUrl: string;
@@ -79,64 +35,35 @@ export class S3TailsFileService extends BasicTailsFileService {
       revocationRegistryDefinition: AnonCredsRevocationRegistryDefinition;
     },
   ) {
-    const headers = this.prepareS3Headers(
-      this.tailsServerBaseUrl,
-      this.s3Secrets.s3AccessKey,
-      this.s3Secrets.s3Secret,
-    );
+    const url = new URL(this.tailsServerBaseUrl);
+    const useSSL = url.protocol === 'https:';
+    const [endPoint, port] = url.host.split(':');
+
+    const client = new Client({
+      endPoint,
+      port: port ? Number(port) : undefined,
+      useSSL,
+      accessKey: this.s3Secrets.s3AccessKey,
+      secretKey: this.s3Secrets.s3Secret,
+    });
+
     const revocationRegistryDefinition = options.revocationRegistryDefinition;
     const localTailsFilePath = revocationRegistryDefinition.value.tailsLocation;
     const pathParts = localTailsFilePath.split('/');
     const tailsFileId = pathParts[pathParts.length - 1];
 
-    const data = new FormData();
     const readStream = fs.createReadStream(localTailsFilePath);
-    data.append('file', readStream);
 
     const tailsFileUrl = `${this.tailsServerBaseUrl}/${this.tailsServerBucketName}/${tailsFileId}`;
 
-    const response = await agentContext.config.agentDependencies.fetch(
-      tailsFileUrl,
-      {
-        method: 'PUT',
-        body: data,
-        headers,
-      },
+    agentContext.config.logger.debug(
+      `Uploading tails file to: ${tailsFileUrl}`,
     );
 
-    if (response.status !== 200) {
-      throw new Error('Cannot upload tails file');
-    }
+    await client.putObject(this.tailsServerBucketName, tailsFileId, readStream);
 
     return {
       tailsFileUrl,
     };
   }
-
-  private prepareS3Headers(url: string, accessKey: string, secret: string) {
-    const rfc1123Date =
-      new Date()
-        .toLocaleString('en-GB', {
-          timeZone: 'UTC',
-          hour12: false,
-          weekday: 'short',
-          year: 'numeric',
-          month: 'short',
-          day: '2-digit',
-          hour: '2-digit',
-          minute: '2-digit',
-          second: '2-digit',
-        })
-        .replace(/(?:(\d),)/, '$1') + ' GMT';
-
-    // TODO: double check all headers
-    const headers = new Headers();
-    headers.set('Host', url);
-    headers.set('Date', rfc1123Date);
-    headers.set('Content-Type', 'application/octet-stream');
-    headers.set('Authorization', accessKey);
-    headers.set('Secret', secret);
-
-    return headers;
-  }
 }
diff --git a/apps/ssi-abstraction/src/config/__tests__/mockConfig.ts b/apps/ssi-abstraction/src/config/__tests__/mockConfig.ts
index fdb409391071acaee0554ee8ff53505cf589359c..18e219098fdcdd2ab954d67904608df8fe193abb 100644
--- a/apps/ssi-abstraction/src/config/__tests__/mockConfig.ts
+++ b/apps/ssi-abstraction/src/config/__tests__/mockConfig.ts
@@ -9,12 +9,12 @@ const mockConfig = (port: number = 3001, withLedger = false): AppConfig => ({
   agentHost: '',
   port: 3000,
   s3: {
-    secret: 'some-secret',
-    accessKey: 'some-access-key',
+    secret: 'very-long-secret-key',
+    accessKey: 'ssi-abstraction',
   },
   tailsServer: {
-    baseUrl: 'http://localhost:8080',
-    bucketName: 'tails',
+    baseUrl: 'http://localhost:9000',
+    bucketName: 'ssi',
   },
   jwtSecret: '',
   nats: {
diff --git a/docker-compose.yml b/docker-compose.yml
index 4fd70a2f301fd0d9e32a8548769498da073ec7f3..6422563cd76462d503bb270acc6dc38737663c28 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,13 +6,17 @@ services:
     ports:
       - '4222:4222' #Nats server port
       - '8222:8222' #Nats server Monitoring port
-    command: [
-      "--config", "nats-server.conf",
-      "--debug",
-      "--trace",
-      "--user", "nats_user",
-      "--pass", "Rw+dYIymAQm9H6ELLNwSuGo1812jqQ=="
-    ]
+    command:
+      [
+        '--config',
+        'nats-server.conf',
+        '--debug',
+        '--trace',
+        '--user',
+        'nats_user',
+        '--pass',
+        'Rw+dYIymAQm9H6ELLNwSuGo1812jqQ==',
+      ]
 
   s3:
     image: minio/minio
@@ -22,7 +26,7 @@ services:
     environment:
       MINIO_ROOT_USER: minio
       MINIO_ROOT_PASSWORD: minio123
-    command: ["server", "/data", "--console-address", ":9001"]
+    command: ['server', '/data', '--console-address', ':9001']
     volumes:
       - /data
 
@@ -33,6 +37,8 @@ services:
         /usr/bin/mc config host add ssi-s3 http://s3:9000 minio minio123;
         /usr/bin/mc mb --ignore-existing ssi-s3/ssi;
         /usr/bin/mc anonymous set download ssi-s3/ssi;
+        /usr/bin/mc admin user add ssi-s3 ssi-abstraction very-long-secret-key;
+        /usr/bin/mc admin policy attach ssi-s3 readwrite --user=ssi-abstraction;
         exit 0;
       "
     depends_on:
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 93bc4abab406c98c62000d7cbcaed1d892f15513..84ed5d7c81df6e198a90e030b08b9b2dfe2af5c7 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -583,12 +583,12 @@ importers:
       express:
         specifier: ^4.17.3
         version: 4.18.2
-      form-data:
-        specifier: ^4.0.0
-        version: 4.0.0
       joi:
         specifier: ^17.6.0
         version: 17.11.1
+      minio:
+        specifier: ^7.1.3
+        version: 7.1.3
       nats:
         specifier: ^2.18.0
         version: 2.19.0
@@ -5847,6 +5847,12 @@ packages:
     resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==}
     dev: true
 
+  /@zxing/text-encoding@0.9.0:
+    resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==}
+    requiresBuild: true
+    dev: false
+    optional: true
+
   /JSONStream@1.3.5:
     resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
     hasBin: true
@@ -6497,6 +6503,12 @@ packages:
       inherits: 2.0.4
       readable-stream: 3.6.2
 
+  /block-stream2@2.1.0:
+    resolution: {integrity: sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==}
+    dependencies:
+      readable-stream: 3.6.2
+    dev: false
+
   /blueimp-md5@2.19.0:
     resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==}
     dev: false
@@ -6612,6 +6624,10 @@ packages:
     dependencies:
       fill-range: 7.0.1
 
+  /browser-or-node@2.1.1:
+    resolution: {integrity: sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==}
+    dev: false
+
   /browserslist@4.22.2:
     resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==}
     engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@@ -6647,6 +6663,10 @@ packages:
     dev: false
     optional: true
 
+  /buffer-crc32@0.2.13:
+    resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
+    dev: false
+
   /buffer-fill@1.0.0:
     resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==}
     dev: false
@@ -8556,7 +8576,6 @@ packages:
     dependencies:
       strnum: 1.0.5
     dev: false
-    optional: true
 
   /fastq@1.16.0:
     resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==}
@@ -9584,6 +9603,19 @@ packages:
     resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
     engines: {node: '>= 0.10'}
 
+  /ipaddr.js@2.1.0:
+    resolution: {integrity: sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==}
+    engines: {node: '>= 10'}
+    dev: false
+
+  /is-arguments@1.1.1:
+    resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.5
+      has-tostringtag: 1.0.0
+    dev: false
+
   /is-array-buffer@3.0.2:
     resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
     dependencies:
@@ -9687,6 +9719,13 @@ packages:
     engines: {node: '>=6'}
     dev: true
 
+  /is-generator-function@1.0.10:
+    resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      has-tostringtag: 1.0.0
+    dev: false
+
   /is-glob@2.0.1:
     resolution: {integrity: sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==}
     engines: {node: '>=0.10.0'}
@@ -10497,6 +10536,10 @@ packages:
     resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
     dev: true
 
+  /json-stream@1.0.0:
+    resolution: {integrity: sha512-H/ZGY0nIAg3QcOwE1QN/rK/Fa7gJn7Ii5obwp6zyPO4xiPNwpIMjqy2gwjBEGqzkF/vSWEIBQCBuN19hYiL6Qg==}
+    dev: false
+
   /json-text-sequence@0.3.0:
     resolution: {integrity: sha512-7khKIYPKwXQem4lWXfpIN/FEnhztCeRPSxH4qm3fVlqulwujrRDD54xAwDDn/qVKpFtV550+QAkcWJcufzqQuA==}
     engines: {node: '>=10.18.0'}
@@ -11482,6 +11525,26 @@ packages:
   /minimist@1.2.8:
     resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
 
+  /minio@7.1.3:
+    resolution: {integrity: sha512-xPrLjWkTT5E7H7VnzOjF//xBp9I40jYB4aWhb2xTFopXXfw+Wo82DDWngdUju7Doy3Wk7R8C4LAgwhLHHnf0wA==}
+    engines: {node: ^16 || ^18 || >=20}
+    dependencies:
+      async: 3.2.5
+      block-stream2: 2.1.0
+      browser-or-node: 2.1.1
+      buffer-crc32: 0.2.13
+      fast-xml-parser: 4.3.3
+      ipaddr.js: 2.1.0
+      json-stream: 1.0.0
+      lodash: 4.17.21
+      mime-types: 2.1.35
+      query-string: 7.1.3
+      through2: 4.0.2
+      web-encoding: 1.1.5
+      xml: 1.0.1
+      xml2js: 0.5.0
+    dev: false
+
   /minipass-collect@1.0.2:
     resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==}
     engines: {node: '>= 8'}
@@ -13091,7 +13154,6 @@ packages:
   /sax@1.3.0:
     resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==}
     dev: false
-    optional: true
 
   /scheduler@0.24.0-canary-efb381bbf-20230505:
     resolution: {integrity: sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA==}
@@ -13663,7 +13725,6 @@ packages:
   /strnum@1.0.5:
     resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
     dev: false
-    optional: true
 
   /strtok3@7.0.0:
     resolution: {integrity: sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==}
@@ -13964,7 +14025,6 @@ packages:
     resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==}
     dependencies:
       readable-stream: 3.6.2
-    dev: true
 
   /through@2.3.8:
     resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
@@ -14427,6 +14487,16 @@ packages:
   /util-deprecate@1.0.2:
     resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
 
+  /util@0.12.5:
+    resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==}
+    dependencies:
+      inherits: 2.0.4
+      is-arguments: 1.1.1
+      is-generator-function: 1.0.10
+      is-typed-array: 1.1.12
+      which-typed-array: 1.1.13
+    dev: false
+
   /utils-merge@1.0.1:
     resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
     engines: {node: '>= 0.4.0'}
@@ -14593,6 +14663,14 @@ packages:
       - encoding
     dev: false
 
+  /web-encoding@1.1.5:
+    resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==}
+    dependencies:
+      util: 0.12.5
+    optionalDependencies:
+      '@zxing/text-encoding': 0.9.0
+    dev: false
+
   /web-streams-polyfill@3.3.2:
     resolution: {integrity: sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ==}
     engines: {node: '>= 8'}
@@ -14906,6 +14984,14 @@ packages:
     dev: false
     optional: true
 
+  /xml2js@0.5.0:
+    resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==}
+    engines: {node: '>=4.0.0'}
+    dependencies:
+      sax: 1.3.0
+      xmlbuilder: 11.0.1
+    dev: false
+
   /xml2js@0.6.0:
     resolution: {integrity: sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==}
     engines: {node: '>=4.0.0'}
@@ -14915,11 +15001,14 @@ packages:
     dev: false
     optional: true
 
+  /xml@1.0.1:
+    resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==}
+    dev: false
+
   /xmlbuilder@11.0.1:
     resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
     engines: {node: '>=4.0'}
     dev: false
-    optional: true
 
   /xmlbuilder@14.0.0:
     resolution: {integrity: sha512-ts+B2rSe4fIckR6iquDjsKbQFK2NlUk6iG5nf14mDEyldgoc2nEKZ3jZWMPTxGQwVgToSjt6VGIho1H8/fNFTg==}