Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter web, problem making request to a server with self signed certificate

I am facing the first big problem with Flutter Web.

I have to login with oauth2 through a post call to my server that has a self signed ssl certificate.

Using http and dio clients to make the request, i receive net::ERR_CERT_AUTHORITY_INVALID. The only way that I found on the web is to use HttpClient, it works for android and IOs but dart:io is not working in web build. Is there a way to trust my ssl certificate for flutter web??

       // My simple line of code
      var response = await client.post(authorizationEndpoint.toString(), body: body, headers: headers);
      // What I am looking for 
      var response = await client.post(authorizationEndpoint.toString(), 
                               body: body, headers: headers, 
                       --->    trustanyCA: true);
like image 220
Stefano Miceli Avatar asked Feb 20 '20 20:02

Stefano Miceli


Video Answer


3 Answers

There's no way to do that in a web version. Browser's XMLHttpRequest just doesn't allow to bypass not trusted certificates, though it's possible to do that with other http clients.

If it's only needed for debugging purpose, you can try adding an SSL certificate to your system's trusted certificates (for macOS, drop it to System certificates in Keychain Access), as well as overriding browser's security options. Refer to this question to find out how to override it in Chrome.

For production use, you will still need a trusted valid certificate.

like image 79
Igor Kharakhordin Avatar answered Oct 24 '22 06:10

Igor Kharakhordin


You can use the https://pub.dev/packages/universal_io package. It supports the web in addition to Android and iOS.

dependencies:
  universal_io: ^1.0.1

Do the following import instead of dart:io:

import 'package:universal_io/io.dart';

It works the same way.

import 'package:universal_io/io.dart';

Future<void> main() async {
  final request = HttpClient().getUrl(Uri.parse('https://example.com/path'));

  if (request is BrowserHttpClientRequest) {
    request.credentialsMode = BrowserHttpClientCredentialsMode.include;
  }

  final response = await request.close();
  // ...
}

EDIT:

Try this, as it doesn't seem to work with String, try to use Bytes method and follow the path to certificate.

ByteData data = await rootBundle.load('assets/raw/certificate.crt');
SecurityContext context = SecurityContext.defaultContext;
context.setTrustedCertificatesBytes(data.buffer.asUint8List());
client = HttpClient(context: context);

EDIT2:

What if you use HttpClient.badCertificateCallback
Here is a code to accept any cert:

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

EDIT3:

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(new MyApp());
}
like image 23
Marcel Dz Avatar answered Oct 24 '22 05:10

Marcel Dz


If you're using self-signed certificates for development and testing you can set your operating system to always trust the certificate, and the browser will respect that.

Alternatively you can generate a valid certificate with Let's Encrypt and then have a local web server use that.

Finally - if you want a quick and easy solution ngrok will give you a secure tunnel to localhost that you can use for development and testing.

like image 1
ibash Avatar answered Oct 24 '22 05:10

ibash