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

6,686

Solution 1

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.

Solution 2

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());
}

Solution 3

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.

Share:
6,686
Stefano Miceli
Author by

Stefano Miceli

Updated on December 18, 2022

Comments

  • Stefano Miceli
    Stefano Miceli over 1 year

    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);
    
  • Tom
    Tom almost 4 years
    Thx. There is a mispelling in your code, an await is missing: final request = await HttpClient().getUrl(Uri.parse('example.com/path')); And it still has the problem with self-signed certificate: Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID
  • Marcel Dz
    Marcel Dz almost 4 years
    sure, youre welcome! i edited my answer with another idea. Check it pls.
  • Tom
    Tom almost 4 years
    Thx. It throws error at var context = SecurityContext.defaultContext; Error: UnimplementedError at Object.throw_ [as throw] (localhost:62417/dart_sdk.js:4773:11)
  • Marcel Dz
    Marcel Dz almost 4 years
    do you store the .pfx file? [...]Store your PKCS12 client keystore (the pfx file) somewhere in your app, probably as an asset, and load it on startup. Create a SecurityContext and then call both useCertificateChainBytes and usePrivateKeyBytes passing the same values to both (the pfx file's contents and password).[...]
  • Tom
    Tom almost 4 years
    I can not create any security context, I always get Error: UnimplementedError. May be it is not implemented in Flutter Web? Thx
  • Marcel Dz
    Marcel Dz almost 4 years
    hm strange, check my answer I added another solution
  • Tom
    Tom almost 4 years
    httpclient is not supported on flutter web. var client = HttpClient(); throws 'Error: Unsupported operation: Platform._version'
  • Marcel Dz
    Marcel Dz almost 4 years
    yes, but universal_io has the HttpClient() which works in there
  • Tom
    Tom almost 4 years
    Yep, sorry, there are too many options :) So, I tried with it earlier, and it throws this: at HttpClient(): localhost:50477/dart_sdk.js:137199:11TypeError: Cannot read property 'Symbol(dartx.indexOf)' of null at Object._getHttpVersion (localhost:50477/dart_sdk.js:170491:24) at new _http._HttpClient.new (localhost:50477/dart_sdk.js:165842:28) at Function.new (localhost:50477/dart_sdk.js:160942:16)
  • Marcel Dz
    Marcel Dz almost 4 years
    yes, well im trying to help you with any kind of idea :D are you able to pass it using HttpClient.badCertificateCallback like I showed you ?
  • Tom
    Tom almost 4 years
    No, still Failed to load resource: net::ERR_CERT_AUTHORITY_INVALID :(
  • Marcel Dz
    Marcel Dz almost 4 years
    really strange, I edited question, could you implement edit3 for me? This is a working solution I just found propably.
  • Tom
    Tom almost 4 years
    Thanks. I get this: Error: UnimplementedError at Object.throw_ [as throw] (localhost:54722/dart_sdk.js:4773:11) at Function.startConnect (localhost:54722/packages/universal_io/src/io_impl_js/…) at http._ConnectionTarget.new.connect (localhost:54722/packages/universal_io/src/io_impl_js/…) at connect (localhost:54722/packages/universal_io/src/io_impl_js/…) at http.HttpClientImpl.new.[_getConnection]
  • Tom
    Tom almost 4 years
    Really sad news. I agree with you it should be used inly for debugging and testing purposes, but all in all, I can solve it on any platform from IOS, Android to PHP etc. Flutter web is the first in which it is mission impossible. I know it is in beta, but it is such a basic task...
  • Igor Kharakhordin
    Igor Kharakhordin almost 4 years
    @Tom It is browser's limitation, rather than Flutter framework's. The code executed in a browser can't bypass its security, unless it uses some kind of vulnerability, So it's impossible to do that in client-side javascript (but it's possible in server-side nodejs code).
  • Miftakhul Arzak
    Miftakhul Arzak about 2 years
    Yes, simple solution for debugging