diff --git a/keyserver/src/push/send.js b/keyserver/src/push/send.js
--- a/keyserver/src/push/send.js
+++ b/keyserver/src/push/send.js
@@ -803,6 +803,34 @@
     );
   }
 
+  const canQueryBlobService =
+    platformDetails.codeVersion &&
+    platformDetails.codeVersion >= FUTURE_CODE_VERSION;
+
+  let blobHash, encryptionKey, blobUploadError;
+  if (canQueryBlobService) {
+    ({
+      blobHash: blobHash,
+      encryptionKey: encryptionKey,
+      blobUploadError: blobUploadError,
+    } = await blobServiceUpload(copyWithMessageInfos.compile()));
+  }
+
+  if (blobUploadError) {
+    console.warn(
+      `Failed to upload payload of notification: ${uniqueID} ` +
+        `due to error: ${blobUploadError}`,
+    );
+  }
+
+  if (blobHash && encryptionKey) {
+    notification.payload = {
+      blobHash,
+      encryptionKey,
+      ...notification.payload,
+    };
+  }
+
   const notifsWithoutMessageInfos = await prepareEncryptedIOSNotifications(
     devicesWithExcessiveSize,
     notification,
diff --git a/native/ios/NotificationService/NSEBlobServiceClient.mm b/native/ios/NotificationService/NSEBlobServiceClient.mm
--- a/native/ios/NotificationService/NSEBlobServiceClient.mm
+++ b/native/ios/NotificationService/NSEBlobServiceClient.mm
@@ -17,7 +17,7 @@
   dispatch_once(&onceToken, ^{
     NSURLSessionConfiguration *config =
         [NSURLSessionConfiguration ephemeralSessionConfiguration];
-    // TODO: put necessary authentication into session config
+
     [config setTimeoutIntervalForRequest:blobServiceQueryTimeLimit];
     NSURLSession *session =
         [NSURLSession sessionWithConfiguration:config
@@ -31,10 +31,30 @@
 
 - (void)getAndConsumeSync:(NSString *)blobHash
       withSuccessConsumer:(void (^)(NSData *))successConsumer {
+  NSError *authTokenError = nil;
+  NSString *authToken = [NSEBlobServiceClient getAuthToken:&authTokenError];
+
+  if (authTokenError) {
+    comm::Logger::log(
+        "NSE: Failed to create NSE blob service auth token. Reason: " +
+        std::string([authTokenError.localizedDescription UTF8String]));
+    return;
+  }
+
   NSString *blobUrlStr = [blobServiceAddress
       stringByAppendingString:[@"/blob/" stringByAppendingString:blobHash]];
   NSURL *blobUrl = [NSURL URLWithString:blobUrlStr];
-  NSURLRequest *blobRequest = [NSURLRequest requestWithURL:blobUrl];
+  NSMutableURLRequest *blobRequest =
+      [NSMutableURLRequest requestWithURL:blobUrl];
+
+  // This is slightly against Apple docs:
+  // https://developer.apple.com/documentation/foundation/nsurlrequest?language=objc#1776617
+  // but apparently there is no other way to
+  // do this and even Apple staff members
+  // advice to set this field manually to
+  // achieve token based authentication:
+  // https://developer.apple.com/forums/thread/89811
+  [blobRequest setValue:authToken forHTTPHeaderField:@"Authorization"];
 
   dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
   NSURLSessionDataTask *task = [self.sharedBlobServiceSession
@@ -63,4 +83,44 @@
           (int64_t)(blobServiceQueryTimeLimit * NSEC_PER_SEC)));
 }
 
++ (NSString *)getAuthToken:(NSError **)error {
+  // Authentication data are retrieved on every request
+  // since they might change while NSE process is running
+  // so we should not rely on caching them in memory.
+
+  // TODO: retrieve those values from CommSecureStore
+  NSString *userID = @"placeholder";
+  NSString *accessToken = @"placeholder";
+  NSString *deviceID = @"placeholder";
+
+  NSDictionary *jsonAuthObject = @{
+    @"userID" : userID,
+    @"accessToken" : accessToken,
+    @"deviceID" : deviceID,
+  };
+
+  NSData *binaryAuthObject = nil;
+  NSError *jsonError = nil;
+
+  @try {
+    binaryAuthObject = [NSJSONSerialization dataWithJSONObject:jsonAuthObject
+                                                       options:0
+                                                         error:&jsonError];
+  } @catch (NSException *e) {
+    *error = [NSError errorWithDomain:@"app.comm"
+                                 code:NSFormattingError
+                             userInfo:@{NSLocalizedDescriptionKey : e.reason}];
+    return nil;
+  }
+
+  if (jsonError) {
+    *error = jsonError;
+    return nil;
+  }
+
+  return [@"Bearer "
+      stringByAppendingString:[binaryAuthObject
+                                  base64EncodedStringWithOptions:0]];
+}
+
 @end