Flutter add client certificate to request using http.dart
Asked Answered
S

2

6

I'm trying to load a client certificate to a http.client from the http.dart package.

I'v seen multiple answers on how to do it using the HttpClient class, like this answer: Flutter add self signed certificate from asset folder, which basicaly suggests to do the following code

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

But I must use the http.dart package since i have a function that accepts a http.client something like this

import 'package:http/http.dart' as http;

var httpClient = http.Client();
// i'd like to configure this httpClient to use a specific client certificate

var client = MyClient(httpClient);

....

MyClient (http.Client? httpClient) {
    -- some constructor logic --
}

Is there any way to configure a http.client to use a client certificate?

Thanks.

Supremacy answered 17/1, 2022 at 12:28 Comment(1)
Remove as http and var http = Client();Argentine
U
6

Don't use the http.Client() constructor. Instead, construct an IOClient (which is a subclass of Client as can be used instead). Pass in your HttpClient.

import 'dart:io';

import 'package:http/io_client.dart';

void main() async {
  final context = SecurityContext.defaultContext;
  // modify context as needed
  final httpClient = HttpClient(context: context);
  final client = IOClient(httpClient);

  await client.get(Uri.parse('https://somewhere.io'));
}
Unlade answered 17/1, 2022 at 13:50 Comment(7)
Thank you for the answer, but i'm getting an error Unsupported operation: default SecurityContext getter running a flutter web app, it seems like dart:io is a support for non-web applications, any workaround?Supremacy
what i ended up doing was, adding a condition to check the platform (kIsWeb) and return http.Client() in a case of webSupremacy
Indeed, but I assumed that you'd be using mobile rather than web, as that might be a security hole to load a client cert from assets on web.Unlade
@Yonatan, how do you check the platform and return dynamic client?Ramie
How did you get around this error ? Unsupported operation: default SecurityContext getter running a flutter web app ? Did it ever work in web ?Buckjump
@Ramie there are several ways to detect the platform, here is an example How do you detect the host platform from Dart codeSupremacy
@PranavSawant was not able to get it to work in webSupremacy
K
2

you can use client certificates from a flutter client, thanks to DIO, which use dart.https instead of dart.http with this kind of code,

from my repo : https://github.com/ysimonx/mtls-ssl-generator

void getHttp() async {
  Dio dio = new Dio();

  ByteData clientCertificate = await rootBundle.load("assets/clientCrt.pem");
  ByteData privateKey = await rootBundle.load("assets/clientKey.pem");
  String rootCACertificate = await rootBundle.loadString("assets/caCrt.pem");

  dio.httpClientAdapter = IOHttpClientAdapter()
    ..onHttpClientCreate = (_) {
      final SecurityContext context = SecurityContext(withTrustedRoots: false);

      context.setTrustedCertificatesBytes(utf8.encode(rootCACertificate));
      context.useCertificateChainBytes(clientCertificate.buffer.asUint8List());
      context.usePrivateKeyBytes(privateKey.buffer.asUint8List());
      HttpClient httpClient = HttpClient(context: context);

      httpClient.badCertificateCallback =
          (X509Certificate cert, String host, int port) {

        if (cert.pem == rootCACertificate) {
          return true;
        }
        return false;
      };

      return httpClient;
    };

  final response = await dio.get('https://localhost:3000/');
  print(response);
}

Kelliekellina answered 24/2, 2023 at 13:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.