how to solve flutter CERTIFICATE_VERIFY_FAILED error while performing a POST request?

DartFlutter

Dart Problem Overview


I am sending a post request in Dart. It is giving a response when I test it on API testing tools such as Postman. But when I run the app. It gives me the following error:-

E/flutter ( 6264): HandshakeException: Handshake error in client (OS Error: E/flutter ( 6264): 	CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:363))

Here is my code of the function -

Future getAccessToken(String url) async {
    
    try {
      http.post('url',
          body: {
            "email": "[email protected]",
            "password": "1234"
          }).then((response) {
        print("Reponse status : ${response.statusCode}");
        print("Response body : ${response.body}");
        var myresponse = jsonDecode(response.body);
        String token = myresponse["token"];
      });
    } catch (e) {
      print(e.toString());
    }

Here's the full error body:

E/flutter ( 6264): [ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception: E/flutter ( 6264): HandshakeException: Handshake error in client (OS Error: E/flutter ( 6264): 	CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:363)) E/flutter ( 6264): #0      IOClient.send (package:http/src/io_client.dart:33:23) E/flutter ( 6264): <asynchronous suspension> E/flutter ( 6264): #1      BaseClient._sendUnstreamed (package:http/src/base_client.dart:169:38) E/flutter ( 6264): <asynchronous suspension> E/flutter ( 6264): #2     BaseClient.post (package:http/src/base_client.dart:54:7) E/flutter ( 6264): #3      post.<anonymous closure> (package:http/http.dart:70:16) E/flutter ( 6264): #4      _withClient (package:http/http.dart:166:20) E/flutter ( 6264): <asynchronous suspension> E/flutter ( 6264): #5     post (package:http/http.dart:69:5) E/flutter ( 6264): #6     
_MyLoginFormState.getAccessToken (package:chart/main.dart:74:7) E/flutter ( 6264): <asynchronous suspension> E/flutter ( 6264): #7    
_MyLoginFormState.build.<anonymous closure> (package:chart/main.dart:64:29)

Dart Solutions


Solution 1 - Dart

Just for the sake of clarity specially for the newcomers to Flutter/Dart, here is what you need to do in order to enable this option globally in your project:

  1. In your main.dart file, add or import the following class:

> class MyHttpOverrides extends HttpOverrides{ > @override > HttpClient createHttpClient(SecurityContext? context){ > return super.createHttpClient(context) > ..badCertificateCallback = (X509Certificate cert, String host, int port)=> true; > } > }

  1. In your main function, add the following line after function definition:

> HttpOverrides.global = MyHttpOverrides();

This comment was very helpful to pass through this matter, and please note that...

> This should be used while in development mode, do NOT do this when you want to release to production, the aim of this answer is to > make the development a bit easier for you, for production, you need to fix your certificate issue and use it properly, look at the other answers for this as it might be helpful for your case.

Solution 2 - Dart

  1. Download cert from https://letsencrypt.org/certs/lets-encrypt-r3.pem

  2. Add this file to assets/ca/ Flutter project root directory

  3. Add assets/ca/ assets directory in pubspec.yaml

  4. Add this code on your app initialization:

    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
    
      ByteData data = await PlatformAssetBundle().load('assets/ca/lets-encrypt-r3.pem');
      SecurityContext.defaultContext.setTrustedCertificatesBytes(data.buffer.asUint8List());
    
      runApp(MyApp());
    }
    

It works with the default chain, so no changes are needed on the server. Android < 7.1.1 clients will still have access in a browser context.

Solution 3 - Dart

If you are using Dio library, just do this:

Dio dio = new Dio();
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
    (HttpClient client) {
  client.badCertificateCallback =
      (X509Certificate cert, String host, int port) => true;
  return client;
};

Solution 4 - Dart

Edit & Update Feb 2021: When this question was earlier asked there were not enough docs and developers to answer. The following answers may be more helpful than this one: Ma'moon Al-Akash Answer, Pedro Massango's Answer & Ken's Answer

If you have not found the solution in these 3 answers, you can try the solution below.

Originally Answered Jan 2019: The correct(but a bad) way to do it ,as I found out, is to allow all certificates.

HttpClient client = new HttpClient();
client.badCertificateCallback = ((X509Certificate cert, String host, int port) => true);

String url ='[email protected]';

Map map = { 
     "email" : "email" , 
     "password" : "password"
};

HttpClientRequest request = await client.postUrl(Uri.parse(url));

request.headers.set('content-type', 'application/json');

request.add(utf8.encode(json.encode(map)));

HttpClientResponse response = await request.close();

String reply = await response.transform(utf8.decoder).join();

print(reply);

Solution 5 - Dart

This Code work for me

class MyHttpOverrides extends HttpOverrides{
  @override
  HttpClient createHttpClient(SecurityContext context){
    return super.createHttpClient(context)
      ..badCertificateCallback = (X509Certificate cert, String host, int port)=> true;
  }
}

void main(){
  HttpOverrides.global = new MyHttpOverrides();
  runApp(MyApp());
}

I think it will the same for you...

Solution 6 - Dart

The best approach (I think so) is to allow certificate for trusted hosts, so if your API host is "api.my_app" you can allow certificates from this host only:

    HttpClient client = new HttpClient();
    client.badCertificateCallback = ((X509Certificate cert, String host, int port) {
     final isValidHost = host == "api.my_app";

     // Allowing multiple hosts
     // final isValidHost = host == "api.my_app" || host == "my_second_host";
     return isValidHost;
    });

If you have more hosts you can just add a new check there.

Solution 7 - Dart

import 'package:http/io_client.dart';
import 'dart:io';
import 'package:http/http.dart';
import 'dart:async';
import 'dart:convert';

    Future getAccessToken(String url) async {
      try {
        final ioc = new HttpClient();
        ioc.badCertificateCallback =
            (X509Certificate cert, String host, int port) => true;
        final http = new IOClient(ioc);
        http.post('url', body: {"email": "[email protected]", "password": "1234"}).then(
            (response) {
          print("Reponse status : ${response.statusCode}");
          print("Response body : ${response.body}");
          var myresponse = jsonDecode(response.body);
          String token = myresponse["token"];
        });
      } catch (e) {
        print(e.toString());
      }
    }

Solution 8 - Dart

Using Dio package for request on my local server with self signed certificat, i prefer to allow a specific host rather than all domains.

//import 'package:get/get.dart' hide Response;  //<-- if you use get package
import 'package:dio/dio.dart';

void main(){
  HttpOverrides.global = new MyHttpOverrides();
  runApp(MyApp());
}

class MyHttpOverrides extends HttpOverrides{
  @override
  HttpClient createHttpClient(SecurityContext context){
    return super.createHttpClient(context)
      ..badCertificateCallback = ((X509Certificate cert, String host, int port) {
        final isValidHost = ["192.168.1.67"].contains(host); // <-- allow only hosts in array
        return isValidHost;
      });
  }
}

// more example: https://github.com/flutterchina/dio/tree/master/example
void getHttp() async {
  Dio dio = new Dio();
  Response response;
  response = await dio.get("https://192.168.1.67");
  print(response.data);
}

Solution 9 - Dart

Check the device date and time in device settings. The device date and time is set to previous date.

Solution 10 - Dart

This issue happened to us as we are not using the fullchain.pem generated using let's encrypt on nginx. Once changed that it fixes this issue.

server {
    listen 443 ssl;

    ssl_certificate /var/www/letsencrypt/fullchain.pem;

For Apache, you might need to configure SSLCertificateChainFile. More discussion about the issue https://github.com/flutter/flutter/issues/50699

Solution 11 - Dart

For those who need to ignore certificate errors only for certain calls, you could use the HttpOverrides solution already mentioned by numerous answers.

However, there is no need to use it globally. You can use it only for certain calls that you know experience handshake errors by wrapping the call in HttpOverrides.runWithHttpOverrides().

class IgnoreCertificateErrorOverrides extends HttpOverrides{
  @override
  HttpClient createHttpClient(SecurityContext context){
    return super.createHttpClient(context)
      ..badCertificateCallback = ((X509Certificate cert, String host, int port) {
      return true;
    });
  }
}


Future<void> myNonSecurityCriticalApiCall() async {
  await HttpOverrides.runWithHttpOverrides(() async {
    String url = 'https://api.example.com/non/security/critical/service';
    Response response = await get(url);

    // ... do something with the response ...
  }, IgnoreCertificateErrorOverrides());
}

In my case it is an external API which does have a valid SSL certificate and works in the browser but for some reason won't work in my Flutter app.

Solution 12 - Dart

Well, I figured out that the actual root of the problem was out-of-sync time on my test device...

Solution 13 - Dart

This is for http library method. here is what you need to do in order to enable this option globally in your project. enter image description here

    class MyHttpoverrides extends HttpOverrides{
  @override 
  HttpClient createHttpClient(SecurityContext context){
    return super.createHttpClient(context)
    ..badCertificateCallback = (X509Certificate cert, String host, int port)=>true;
  }
}

//void main() => runApp(MyApp());
void main(){
  HttpOverrides.global=new MyHttpoverrides();
  runApp(MyApp());
}

for more details:https://fluttercorner.com/certificate-verify-failed-unable-to-get-local-issuer-certificate-in-flutter/

Solution 14 - Dart

For everyone landing here with a need to solve the problem and not just bypass it allowing everything.

For me the problem solved on the server side (as it should be) with no change in the code. Everything is valid now. On all the other solutions the problem still exists (eg The Postman runs but it displays a configuration error on the globe next to response status) The configuration is Centos/Apache/LetsEncrypt/Python3.8/Django3.1.5/Mod_wsgi/ but I guess that the solution is valid for most installations of Apache/LetsEncrypt

The steps to resolve are

  1. Locate the line "SSLCACertificateFile" on the Virtual Host you wish to config. For example:

> SSLCACertificateFile /etc/httpd/conf/ssl.crt/my_ca.crt

  1. Download https://letsencrypt.org/certs/lets-encrypt-r3-cross-signed.txt At the end of /etc/httpd/conf/ssl.crt/my_ca.crt (after the -----END CERTIFICATE-----) start a new line and paste from lets-encrypt-r3-cross-signed.txt everything bellow -----BEGIN CERTIFICATE----- (including -----BEGIN CERTIFICATE-----)
  2. Save /etc/httpd/conf/ssl.crt/my_ca.crt
  3. Restart Apache httpd

References: https://access.redhat.com/solutions/43575 https://letsencrypt.org/certs

Also you can check the validity of your cert in https://www.digicert.com/help/.

Solution 15 - Dart

Actually in my case I fixed it after updating the date and time on my pc. Might help someone I guess

Solution 16 - Dart

For me, it was the problem with the android emulator.

I just created a new android emulator that fixed my problem.

Solution 17 - Dart

I specifically needed to use lib/client.dart Client interface for http calls (i.e. http.Client instead of HttpClient) . This was required by ChopperClient (link).

So I could not pass HttpClient from lib/_http/http.dart directly to Chopper. ChopperClient can receive HttpClient in the constructor wrapped in ioclient.IOClient.

HttpClient webHttpClient = new HttpClient();
webHttpClient.badCertificateCallback = ((X509Certificate cert, String host, int port) => true);
dynamic ioClient = new ioclient.IOClient(webHttpClient);
final chopper = ChopperClient(
  baseUrl: "https://example.com",
  client: ioClient,
  services: [
    MfService.create()
  ],
  converter: JsonConverter(),
);
final mfService = MfService.create(chopper);

This way you can temporarily ignore CERTIFICATE_VERIFY_FAILED error in your calls. Remember - that's only for development purposes. Don't use this in production environment!

Solution 18 - Dart

Update on January 30, 2021: I know the reason, because nginx is configured with some encryption algorithms that flutter does not support! , The specific need to try.

Use tls 1.3 request URL, no problem.

Example

import 'dart:io';

main() async {
  HttpClient client = new HttpClient();
  // tls 1.2 error
//  var request = await client.getUrl(Uri.parse('https://shop.io.mi-img.com/app/shop/img?id=shop_88f929c5731967cbc8339cfae1f5f0ec.jpeg')); 
  // tls 1.3 normal
  var request = await client.getUrl(Uri.parse('https://ae01.alicdn.com/kf/Ud7cd28ffdf6e475c8dc382380d5d1976o.jpg'));
  var response = await request.close();
  print(response.headers);
  client.close(force: true);
}

Solution 19 - Dart

For me, it was because I am using HTTPS and the API uses HTTP so I just changed it to HTTP and it works.

Solution 20 - Dart

This Solution is finally worked. Thanks to Milad

    final ioc = new HttpClient();
    ioc.badCertificateCallback =
        (X509Certificate cert, String host, int port) => true;
    final http = new IOClient(ioc);
    http.post(); //Your Get or Post Request

Solution 21 - Dart

I fixed the issue by generating the full_chain.crt file.

You might have received the your_domain.crt file and your_domain.ca-bundle file. Now what you have to do is combine the crt file and ca-bundle file to generate the crt file.

cat domain.crt domain.ca-bundle >> your_domain_full_chain.crt

Then you just need to put the your_domain_full_chain.crt file in the nginx and it will start working properly.

Solution 22 - Dart

If you use Android Emulator I've found out that this occurs when there is no internet connection. Check that your emulator has a network connection!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAdil MaqusoodView Question on Stackoverflow
Solution 1 - DartMa'moon Al-AkashView Answer on Stackoverflow
Solution 2 - DartSmithView Answer on Stackoverflow
Solution 3 - DartHossein YousefpourView Answer on Stackoverflow
Solution 4 - DartAdil MaqusoodView Answer on Stackoverflow
Solution 5 - DartGrafritz DesignView Answer on Stackoverflow
Solution 6 - DartPedro MassangoView Answer on Stackoverflow
Solution 7 - DartMilad AhmadiView Answer on Stackoverflow
Solution 8 - DartZorroView Answer on Stackoverflow
Solution 9 - DartTrendyView Answer on Stackoverflow
Solution 10 - DartkenView Answer on Stackoverflow
Solution 11 - DartMagnusView Answer on Stackoverflow
Solution 12 - DartGennadiy RyabkinView Answer on Stackoverflow
Solution 13 - DartSuresh B BView Answer on Stackoverflow
Solution 14 - DartJohn AndertonView Answer on Stackoverflow
Solution 15 - Dartbhupesh shakyaView Answer on Stackoverflow
Solution 16 - DartMd. Ruhul AminView Answer on Stackoverflow
Solution 17 - Dartkosiara - Bartosz KosarzyckiView Answer on Stackoverflow
Solution 18 - DartOptimisticSeeEverythingView Answer on Stackoverflow
Solution 19 - DartKhaled MahmoudView Answer on Stackoverflow
Solution 20 - DartOmar EssamView Answer on Stackoverflow
Solution 21 - DartchiragView Answer on Stackoverflow
Solution 22 - DartF.SO7View Answer on Stackoverflow