Skip to content

NodeRequestor fails in electron in the presence of self-signed certificates (e.g. corporate machines/networks) #299

@MichaelBelousov

Description

@MichaelBelousov

I have a user who is getting an error self signed certificate in certificate chain error when trying to login from their corporate machine.

My suspicion is that when you use the openid node requestor on this line, it fails there as the default fetch and http/https packages in electron do not support using the user's certificate store. Electron's (new) electron.net.fetch function however does use those certificates.

As such, I have the following main/Client.js patch I'm using locally to workaround this.
Note that for brevity I have neglected to show the parts of the patch replacing other node_requestor usages, but those should be replaced too.

+
+
+/// START ELECTRON REQUESTOR PATCH IMPL
+const { AppAuthError } = require('@openid/appauth/built/errors.js');
+const { log } = require('@openid/appauth/built/logger.js');
+const { Requestor } = require('@openid/appauth/built/xhr.js');
+
+/** @type {import("electron").net.fetch} */
+const fetch = require('electron').net.fetch;
+
+/**
+ * An electron.net.fetch HTTP client (to support user certificates)
+ */
+class ElectronRequestor extends Requestor {
+  /**
+   * @template T
+   * @param {JQueryAjaxSettings} settings
+   * @returns {Promise<T>} settings
+   */
+  async xhr(settings) {
+    // implementing a subset that is required.
+
+    /** @type {Response} */
+    let resp;
+    try {
+      resp = await fetch(
+        settings.url,
+        {
+          method: settings.data ? "POST" : undefined,
+          headers: {
+            ...settings.headers,
+            // THIS seems to cause electron's use of chromium's fetch to return Uncaught Error: net::ERR_INVALID_ARGUMENT
+            // so just let it do it automatically
+            //...settings.data && {
+              //'Content-Length': String(settings.data.toString().length),
+            //},
+          },
+          body: settings.data,
+        },
+      );
+    } catch (err) {
+      log('Request throw an error ', err); 
+      console.error("REQUEST ERROR", err)
+      throw err;
+    }
+
+    if (resp.status !== 200) {
+      log('Request ended with an error ', resp.status); 
+      throw new AppAuthError(resp.statusText);
+    }
+
+    if (settings.dataType === "json") {
+      // NOTE: NodeRequestor implementation logged JSON parse errors here
+      return resp.json();
+    } else {
+      return resp.text();
+    }
+  }
+}
+/// END ELECTRON REQUESTOR PATCH IMPL
+
 /**
  * Utility to generate OIDC/OAuth tokens for Desktop Applications
  * @beta
@@ -167,7 +229,7 @@ class ElectronMainAuthorization {
      */
     async signIn() {
         if (!this._configuration) {
-            const tokenRequestor = new node_support_1.NodeRequestor(); // the Node.js based HTTP client
+            const tokenRequestor = new ElectronRequestor();
             this._configuration =
                 await appauth_1.AuthorizationServiceConfiguration.fetchFromIssuer(this._issuerUrl, tokenRequestor);
             core_bentley_1.Logger.logTrace(loggerCategory, "Initialized service configuration", () => ({ configuration: this._configuration }));
@@ -186,11 +248,13 @@ class ElectronMainAuthorization {

I will reply if there were any issues after my user tests it. I just don't want to forget about it so I am already posting it as a known issue.

More information on electron.net.fetch issues here
electron/electron#45674

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions