diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d46b935ef8551c032ebe3610432c0217fe1803f..f1155cf743510f0e7e276497f5150d58fb5c8735 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.4
+
+- support presignedPostPolicy
+
 ## 0.1.3
 
 - support presignedGetObject and presignedPutObject
diff --git a/README.md b/README.md
index cc0c02b08b19f8ed0b4cce50b0ba71274eb03782..9454ad94774ef4902b8cdd4390e19d6f0a08c02e 100644
--- a/README.md
+++ b/README.md
@@ -2,18 +2,18 @@ This is the _unofficial_ MinIO Dart Client SDK that provides simple APIs to acce
 
 ## API
 
-| Bucket operations     	| Object operations      	| Presigned operations 	| Bucket Policy & Notification operations 	|
-|-------------------------|-------------------------|-----------------------|-------------------------------------------|
-| [makeBucket]           	| [getObject]            	| [presignedUrl]       	| getBucketNotification                   	|
-| [listBuckets]          	| [getPartialObject]     	| [presignedGetObject]  | setBucketNotification                   	|
-| [bucketExists]         	| [fGetObject]           	| [presignedPutObject] 	| removeAllBucketNotification             	|
-| [removeBucket]         	| [putObject]            	| presignedPostPolicy  	| getBucketPolicy                         	|
-| [listObjects]          	| [fPutObject]           	|                      	| setBucketPolicy                         	|
-| [listObjectsV2]        	| [copyObject]           	|                      	| listenBucketNotification                	|
-| [listIncompleteUploads]	| [statObject]           	|                      	|                                         	|
-|                       	| [removeObject]         	|                      	|                                         	|
-|                       	| [removeObjects]        	|                      	|                                         	|
-|                       	| [removeIncompleteUpload]|                      	|                                         	|
+| Bucket operations       | Object operations        | Presigned operations | Bucket Policy & Notification operations |
+|-------------------------|--------------------------|----------------------|-----------------------------------------|
+| [makeBucket]            | [getObject]              | [presignedUrl]       | getBucketNotification                   |
+| [listBuckets]           | [getPartialObject]       | [presignedGetObject] | setBucketNotification                   |
+| [bucketExists]          | [fGetObject]             | [presignedPutObject] | removeAllBucketNotification             |
+| [removeBucket]          | [putObject]              | [presignedPostPolicy]| listenBucketNotification                |
+| [listObjects]           | [fPutObject]             |                      | getBucketPolicy                         |
+| [listObjectsV2]         | [copyObject]             |                      | setBucketPolicy                         |
+| [listIncompleteUploads] | [statObject]             |                      |                                         |
+|                         | [removeObject]           |                      |                                         |
+|                         | [removeObjects]          |                      |                                         |
+|                         | [removeIncompleteUpload] |                      |                                         |
 
 
 ## Usage
@@ -95,4 +95,5 @@ MIT
 [presignedUrl]: https://pub.dev/documentation/minio/latest/minio/Minio/presignedUrl.html
 [presignedGetObject]: https://pub.dev/documentation/minio/latest/minio/Minio/presignedGetObject.html
 [presignedPutObject]: https://pub.dev/documentation/minio/latest/minio/Minio/presignedPutObject.html
+[presignedPostPolicy]: https://pub.dev/documentation/minio/latest/minio/Minio/presignedPostPolicy.html
 
diff --git a/lib/src/minio.dart b/lib/src/minio.dart
index b2baeaa4ab17e619d79418e97108f11120b9699f..0772893058046c6261f725ef28a49634859cd742 100644
--- a/lib/src/minio.dart
+++ b/lib/src/minio.dart
@@ -641,6 +641,60 @@ class Minio {
     );
   }
 
+  /// presignedPostPolicy can be used in situations where we want more control on the upload than what
+  /// presignedPutObject() provides. i.e Using presignedPostPolicy we will be able to put policy restrictions
+  /// on the object's `name` `bucket` `expiry` `Content-Type`
+  Future presignedPostPolicy(PostPolicy postPolicy) async {
+    if (_client.anonymous) {
+      throw MinioAnonymousRequestError(
+          'Presigned POST policy cannot be generated for anonymous requests');
+    }
+
+    final region = await getBucketRegion(postPolicy.formData['bucket']);
+    var date = DateTime.now().toUtc();
+    var dateStr = makeDateLong(date);
+
+    if (postPolicy.policy['expiration'] == null) {
+      // 'expiration' is mandatory field for S3.
+      // Set default expiration date of 7 days.
+      var expires = DateTime.now().toUtc();
+      expires.add(Duration(days: 7));
+      postPolicy.setExpires(expires);
+    }
+
+    postPolicy.policy['conditions'].push(['eq', r'$x-amz-date', dateStr]);
+    postPolicy.formData['x-amz-date'] = dateStr;
+
+    postPolicy.policy['conditions']
+        .push(['eq', r'$x-amz-algorithm', 'AWS4-HMAC-SHA256']);
+    postPolicy.formData['x-amz-algorithm'] = 'AWS4-HMAC-SHA256';
+
+    postPolicy.policy['conditions'].push(
+        ['eq', r'$x-amz-credential', accessKey + '/' + getScope(region, date)]);
+    postPolicy.formData['x-amz-credential'] =
+        accessKey + '/' + getScope(region, date);
+
+    if (sessionToken != null) {
+      postPolicy.policy['conditions']
+          .push(['eq', r'$x-amz-security-token', sessionToken]);
+    }
+
+    final policyBase64 = jsonBase64(postPolicy.policy);
+    postPolicy.formData['policy'] = policyBase64;
+
+    final signature =
+        postPresignSignatureV4(region, date, secretKey, policyBase64);
+
+    postPolicy.formData['x-amz-signature'] = signature;
+    final url = _client
+        .getBaseRequest('POST', postPolicy.formData['bucket'], null, region,
+            null, null, null)
+        .url;
+    var portStr = (port == 80 || port == 443 || port == null) ? '' : ':$port';
+    var urlStr = '${url.scheme}://${url.host}${portStr}${url.path}';
+    return PostPolicyResult(postURL: urlStr, formData: postPolicy.formData);
+  }
+
   /// Generate a presigned URL for PUT.
   /// Using this URL, the browser can upload to S3 only with the specified object name.
   ///
diff --git a/lib/src/minio_models.dart b/lib/src/minio_models.dart
index a1e27adc6b12e282f2a785d34a20fdf58613160c..382e6dac985941aeea13dba3b48fe59e2b6626af 100644
--- a/lib/src/minio_models.dart
+++ b/lib/src/minio_models.dart
@@ -1,4 +1,5 @@
 import 'package:minio/models.dart';
+import 'package:minio/src/minio_errors.dart';
 import 'package:xml/xml.dart';
 
 class ListObjectsChunk {
@@ -113,3 +114,71 @@ class StatObjectResult {
   final DateTime lastModified;
   final Map<String, String> metaData;
 }
+
+/// Build PostPolicy object that can be signed by presignedPostPolicy
+class PostPolicy {
+  final policy = <String, dynamic>{
+    'conditions': [],
+  };
+
+  final formData = <String, String>{};
+
+  /// set expiration date
+  void setExpires(DateTime date) {
+    if (date == null) {
+      throw MinioInvalidDateError('Invalid date : cannot be null');
+    }
+    policy['expiration'] = date.toIso8601String();
+  }
+
+  /// set object name
+  void setKey(String object) {
+    MinioInvalidObjectNameError.check(object);
+    policy['conditions'].add(['eq', r'$key', object]);
+    formData['key'] = object;
+  }
+
+  /// set object name prefix, i.e policy allows any keys with this prefix
+  void setKeyStartsWith(String prefix) {
+    MinioInvalidPrefixError.check(prefix);
+    policy['conditions'].push(['starts-with', r'$key', prefix]);
+    formData['key'] = prefix;
+  }
+
+  /// set bucket name
+  void setBucket(bucket) {
+    MinioInvalidBucketNameError.check(bucket);
+    policy['conditions'].push(['eq', r'$bucket', bucket]);
+    formData['bucket'] = bucket;
+  }
+
+  /// set Content-Type
+  void setContentType(String type) {
+    if (type == null) {
+      throw MinioError('content-type cannot be null');
+    }
+    policy['conditions'].push(['eq', r'$Content-Type', type]);
+    formData['Content-Type'] = type;
+  }
+
+  /// set minimum/maximum length of what Content-Length can be.
+  void setContentLengthRange(int min, int max) {
+    if (min > max) {
+      throw MinioError('min cannot be more than max');
+    }
+    if (min < 0) {
+      throw MinioError('min should be > 0');
+    }
+    if (max < 0) {
+      throw MinioError('max should be > 0');
+    }
+    policy['conditions'].push(['content-length-range', min, max]);
+  }
+}
+
+class PostPolicyResult {
+  PostPolicyResult({this.postURL, this.formData});
+
+  final String postURL;
+  final Map<String, String> formData;
+}
diff --git a/lib/src/minio_sign.dart b/lib/src/minio_sign.dart
index c2313d6ea0b94d681f275fb30f90212a19c3af33..fee400cc21e89a3403460989de53fb0a96a7629e 100644
--- a/lib/src/minio_sign.dart
+++ b/lib/src/minio_sign.dart
@@ -146,3 +146,14 @@ String presignSignatureV4(
 
   return presignedUrl;
 }
+
+// calculate the signature of the POST policy
+String postPresignSignatureV4(
+  String region,
+  DateTime date,
+  String secretKey,
+  String policyBase64,
+) {
+  final signingKey = getSigningKey(date, region, secretKey);
+  return sha256HmacHex(policyBase64, signingKey);
+}
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 8b586e3a5e58f5e1175faa1404dcf80d893c550c..f52f794e179a4ed24812c8db44f30628e93ac55e 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -31,6 +31,10 @@ String md5Base64(String source) {
   return base64.encode(md5digest);
 }
 
+String jsonBase64(Map<String, dynamic> jsonObject) {
+  return base64.encode(utf8.encode(json.encode(jsonObject)));
+}
+
 XmlElement getNodeProp(XmlElement xml, String name) {
   final result = xml.findElements(name);
   return result.isNotEmpty ? result.first : null;
diff --git a/pubspec.yaml b/pubspec.yaml
index a7b8128f303115f68dae345ef40aeeae736f616f..1d2accc84f39945a3e789b4d11159c2479e93afa 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
 name: minio
 description: Unofficial MinIO Dart Client SDK that provides simple APIs to access any Amazon S3 compatible object storage server.
-version: 0.1.3
+version: 0.1.4
 homepage: https://github.com/xtyxtyx/minio-dart
 issue_tracker: https://github.com/xtyxtyx/minio-dart/issues