Flutter: Using Self Signed SSL Certificates in Development

Flutter: Using Self Signed SSL Certificates in Development

I recently started working with Flutter during an RnD phase at work after Ionic which had been the planned direction revealed itself to be a non-viable option given the business requirement. Personally, probably professionally and potentially even for the business, that was a blessing in disguise.

That problem introduced us all to flutter, and I myself was very happy with the discovery, it was easy to use, the tutorials were abundant and coming from a Typescript Front-end environment it was both different and familiar.

It’s early days still, but so far I have only run into 1 significant problem working with it, and that was when trying to connect to my local API, which naturally has a self-signed cert. Getting around this, or more accurately working with this seemed far more complicated than I would have expected.

While many results to come through on google, unfortunately for someone 4 days into Flutter, none of the answers gave enough context for me to understand what I needed to do, many hours later and lots of reading I began to discover the context through the various code bits and posts that I read through.

This is simply the documentation of that in the hopes that the next new guy find it and gets a complete picture that is hopefully a lot easier to understand.

As far as my Google-Fu indicated, only 2 packages that I could find had support for working with bad certificates, and that is HttpCllient and Dio, I had mostly worked out my own solution by the time I got to Dio, so the following code is for HttpClient.

HttpClient has a method called badCertificateCallback, I had written a class for managing cookies for all my API calls which contain, for now, my GET and POST.

static HttpClient client = new HttpClient()
    ..badCertificateCallback = (_certificateCheck);

So when instantiating the HttpClient class, I instantiated it with the badCertificateCallback which is a function, which I wrote as:

static bool _certificateCheck(X509Certificate cert, String host, int port) => host == 'local.domain.ext';

The function itself is simply expecting a bool, many of the posts I found simply suggested having it return true, but that's unsafe, even if this were left in and made it to production, it poses a very low risk.

In simple terms this is what you need to do to get your Self Signed Cert working withing your dev environment, now to ensure complete context and maybe glean a few extra ideas, here is the current version of the Class I am using:

import 'dart:io';

import 'dart:convert';
import 'package:cookie_jar/cookie_jar.dart';


var cj = new CookieJar();

class Session {
  static HttpClient client = new HttpClient()
    ..badCertificateCallback = (_certificateCheck);


  static Future<String> apiGet(String url) async {
    HttpClientRequest request = await client.getUrl(Uri.parse(url));

    _setHeadersCookies(request, url);

    HttpClientResponse response = await request.close();

    _updateCookies(response, url);

    return await response.transform(utf8.decoder).join();
  }

  static Future<String> apiPost(String url, dynamic data) async {
    HttpClientRequest request = await client.postUrl(Uri.parse(url));

    _setHeadersCookies(request, url);

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

    HttpClientResponse response = await request.close();

    _updateCookies(response, url);

    return await response.transform(utf8.decoder).join();
  }

  static void _setHeadersCookies(HttpClientRequest request, String url) {
    request.headers.set('content-type', 'application/json');
    request.cookies.addAll(cj.loadForRequest(Uri.parse(url)));
  }

  static void _updateCookies(HttpClientResponse response, String url) {
    cj.saveFromResponse(Uri.parse(url), response.cookies);
  }

  static bool _certificateCheck(X509Certificate cert, String host, int port) =>
      host == 'local.domain.ext';
}

I have both the GET and POST, with helpers for dealing with Cookies using Cookie_Jar, so for each request, I am updating CJ with any cookies coming down from the API which is then attached to any subsequent calls.

I have not fully tested the cookie side of this Class yet, I will update the Gist if any changes are made.

I hope you found this interesting, and if you have any questions, comments, or improvements, feel free to drop a comment. Enjoy your Flutter development journey :D

If you liked it, a like would be awesome, and if you really liked it, a cup of coffee would be great.

Thanks for reading.