diff --git a/certificates/certificates.go b/certificates/certificates.go
index baac7c33..8a8c50d8 100644
--- a/certificates/certificates.go
+++ b/certificates/certificates.go
@@ -30,16 +30,13 @@ import (
 	"math/big"
 	"net"
 	"os"
-	"strings"
 	"time"
 
-	"github.com/arduino/arduino-create-agent/utilities"
 	"github.com/arduino/go-paths-helper"
 	log "github.com/sirupsen/logrus"
 )
 
 var (
-	host      = "localhost"
 	validFrom = ""
 	validFor  = 365 * 24 * time.Hour * 2 // 2 years
 	rsaBits   = 2048
@@ -270,41 +267,16 @@ func DeleteCertificates(certDir *paths.Path) {
 	certDir.Join("cert.cer").Remove()
 }
 
-// isExpired checks if a certificate is expired or about to expire (less than 1 month)
-func isExpired() (bool, error) {
+// IsExpired checks if a certificate is expired or about to expire (less than 1 month)
+func IsExpired() (bool, error) {
 	bound := time.Now().AddDate(0, 1, 0)
-	dateS, err := GetExpirationDate()
+	date, err := GetExpirationDate()
 	if err != nil {
 		return false, err
 	}
-	date, _ := time.Parse(time.DateTime, dateS)
 	return date.Before(bound), nil
 }
 
-// PromptInstallCertsSafari prompts the user to install the HTTPS certificates if they are using Safari
-func PromptInstallCertsSafari() bool {
-	buttonPressed := utilities.UserPrompt("display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nIf you use Safari, you need to install it.\" buttons {\"Do not install\", \"Install the certificate for Safari\"} default button 2 with title \"Arduino Agent: Install certificate\"")
-	return strings.Contains(string(buttonPressed), "button returned:Install the certificate for Safari")
-}
-
-// PromptExpiredCerts prompts the user to update the HTTPS certificates if they are using Safari
-func PromptExpiredCerts(certDir *paths.Path) {
-	if expired, err := isExpired(); err != nil {
-		log.Errorf("cannot check if certificates are expired something went wrong: %s", err)
-	} else if expired {
-		buttonPressed := utilities.UserPrompt("display dialog \"The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nYour certificate is expired or close to expiration. Do you want to update it?\" buttons {\"Do not update\", \"Update the certificate for Safari\"} default button 2 with title \"Arduino Agent: Update certificate\"")
-		if strings.Contains(string(buttonPressed), "button returned:Update the certificate for Safari") {
-			err := UninstallCertificates()
-			if err != nil {
-				log.Errorf("cannot uninstall certificates something went wrong: %s", err)
-			} else {
-				DeleteCertificates(certDir)
-				GenerateAndInstallCertificates(certDir)
-			}
-		}
-	}
-}
-
 // GenerateAndInstallCertificates generates and installs the certificates
 func GenerateAndInstallCertificates(certDir *paths.Path) {
 	GenerateCertificates(certDir)
diff --git a/certificates/certificates_darwin.h b/certificates/certificates_darwin.h
new file mode 100644
index 00000000..78ba0ae5
--- /dev/null
+++ b/certificates/certificates_darwin.h
@@ -0,0 +1,7 @@
+const char *getDefaultBrowserName();
+
+const char *installCert(const char *path);
+const char *uninstallCert();
+const bool certInKeychain();
+
+const char *getExpirationDate(long *expirationDate);
\ No newline at end of file
diff --git a/certificates/certificates_darwin.m b/certificates/certificates_darwin.m
new file mode 100644
index 00000000..0ac51183
--- /dev/null
+++ b/certificates/certificates_darwin.m
@@ -0,0 +1,137 @@
+#import <Foundation/Foundation.h>
+#import <AppKit/AppKit.h>
+#include "certificates_darwin.h"
+
+// Used to return error strings (as NSString) as a C-string to the Go code.
+const char *toErrorString(NSString *errString) {
+    NSLog(@"%@", errString);
+    return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
+}
+
+// Returns a string describing the name of the default browser set for the user, nil in case of error.
+const char *getDefaultBrowserName() {
+    NSURL *defaultBrowserURL = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:[NSURL URLWithString:@"http://"]];
+    if (defaultBrowserURL) {
+        NSBundle *defaultBrowserBundle = [NSBundle bundleWithURL:defaultBrowserURL];
+        NSString *defaultBrowser = [defaultBrowserBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"];
+
+        return [defaultBrowser cStringUsingEncoding:[NSString defaultCStringEncoding]];
+    }
+
+    return "";
+}
+
+// inspired by https://stackoverflow.com/questions/12798950/ios-install-ssl-certificate-programmatically
+const char *installCert(const char *path) {
+    NSURL *url = [NSURL fileURLWithPath:@(path) isDirectory:NO];
+    NSData *rootCertData = [NSData dataWithContentsOfURL:url];
+
+    OSStatus err = noErr;
+    SecCertificateRef rootCert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef) rootCertData);
+
+    CFTypeRef result;
+
+    NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
+        (id)kSecClassCertificate, kSecClass,
+        rootCert, kSecValueRef,
+        nil];
+
+    err = SecItemAdd((CFDictionaryRef)dict, &result);
+
+    if (err == noErr) {
+        NSLog(@"Install root certificate success");
+    } else if (err == errSecDuplicateItem) {
+        NSString *errString = [@"duplicate root certificate entry. Error: " stringByAppendingFormat:@"%d", err];
+        NSLog(@"%@", errString);
+        return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
+    } else {
+        NSString *errString = [@"install root certificate failure. Error: " stringByAppendingFormat:@"%d", err];
+        NSLog(@"%@", errString);
+        return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
+    }
+
+    NSDictionary *newTrustSettings = @{(id)kSecTrustSettingsResult: [NSNumber numberWithInt:kSecTrustSettingsResultTrustRoot]};
+    err = SecTrustSettingsSetTrustSettings(rootCert, kSecTrustSettingsDomainUser, (__bridge CFTypeRef)(newTrustSettings));
+    if (err != errSecSuccess) {
+        NSString *errString = [@"Could not change the trust setting for a certificate. Error: " stringByAppendingFormat:@"%d", err];
+        NSLog(@"%@", errString);
+        return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
+    }
+
+    return "";
+}
+
+const char *uninstallCert() {
+    // Each line is a key-value of the dictionary. Note: the the inverted order, value first then key.
+    NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
+        (id)kSecClassCertificate, kSecClass,
+        CFSTR("Arduino"), kSecAttrLabel,
+        kSecMatchLimitOne, kSecMatchLimit,
+        kCFBooleanTrue, kSecReturnAttributes,
+        nil];
+
+    OSStatus err = noErr;
+    // Use this function to check for errors
+    err = SecItemCopyMatching((CFDictionaryRef)dict, nil);
+    if (err == noErr) {
+        err = SecItemDelete((CFDictionaryRef)dict);
+        if (err != noErr) {
+            NSString *errString = [@"Could not delete the certificates. Error: " stringByAppendingFormat:@"%d", err];
+            NSLog(@"%@", errString);
+            return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
+        }
+    } else if (err != errSecItemNotFound){
+        NSString *errString = [@"Error: " stringByAppendingFormat:@"%d", err];
+        NSLog(@"%@", errString);
+        return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
+    }
+    return "";
+}
+
+const bool certInKeychain() {
+    // Create a key-value dictionary used to query the Keychain and look for the "Arduino" root certificate.
+    NSDictionary *getquery = @{
+                (id)kSecClass:     (id)kSecClassCertificate,
+                (id)kSecAttrLabel: @"Arduino",
+                (id)kSecReturnRef: @YES,
+            };
+
+    OSStatus err = SecItemCopyMatching((CFDictionaryRef)getquery, nil);
+    return (err == noErr); // No error means the certificate was found, otherwise err will be "errSecItemNotFound".
+}
+
+// Returns the expiration date "kSecOIDX509V1ValidityNotAfter" of the Arduino certificate.
+// The value is returned as a CFAbsoluteTime: a long number of seconds from the date of 1 Jan 2001 00:00:00 GMT.
+const char *getExpirationDate(long *expirationDate) {
+    // Create a key-value dictionary used to query the Keychain and look for the "Arduino" root certificate.
+    NSDictionary *getquery = @{
+                (id)kSecClass:     (id)kSecClassCertificate,
+                (id)kSecAttrLabel: @"Arduino",
+                (id)kSecReturnRef: @YES,
+            };
+
+    SecCertificateRef cert = NULL;
+
+    // Search the keychain for certificates matching the query above.
+    OSStatus err = SecItemCopyMatching((CFDictionaryRef)getquery, (CFTypeRef *)&cert);
+    if (err != noErr) return toErrorString([@"Error getting the certificate: " stringByAppendingFormat:@"%d", err]);
+
+    // Get data from the certificate, as a dictionary of properties. We just need the "invalidity not after" property.
+    CFDictionaryRef certDict = SecCertificateCopyValues(cert, 
+        (__bridge CFArrayRef)@[(__bridge id)kSecOIDX509V1ValidityNotAfter], NULL);
+    if (certDict == NULL) return toErrorString(@"SecCertificateCopyValues failed");
+
+
+    // Get the "validity not after" property as a dictionary, and get the "value" key (that is a number).
+    CFDictionaryRef validityNotAfterDict = CFDictionaryGetValue(certDict, kSecOIDX509V1ValidityNotAfter);
+    if (validityNotAfterDict == NULL) return toErrorString(@"CFDictionaryGetValue (validity) failed");
+
+    CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(validityNotAfterDict, kSecPropertyKeyValue);
+    if (number == NULL) return toErrorString(@"CFDictionaryGetValue (keyValue) failed");
+
+    CFNumberGetValue(number, kCFNumberSInt64Type, expirationDate);
+    // NSLog(@"Certificate validity not after: %ld", *expirationDate);
+
+    CFRelease(certDict);
+    return ""; // No error.
+}
\ No newline at end of file
diff --git a/certificates/install_darwin.go b/certificates/install_darwin.go
index 892c390b..515c9f7d 100644
--- a/certificates/install_darwin.go
+++ b/certificates/install_darwin.go
@@ -15,146 +15,20 @@
 
 package certificates
 
-//inspired by https://stackoverflow.com/questions/12798950/ios-install-ssl-certificate-programmatically
-
 /*
 // Explicitly tell the GCC compiler that the language is Objective-C.
 #cgo CFLAGS: -x objective-c
-// Pass the list of macOS frameworks needed by this piece of Objective-C code.
-#cgo LDFLAGS: -framework Cocoa
-#import <Cocoa/Cocoa.h>
-
-const char *installCert(const char *path) {
-    NSURL *url = [NSURL fileURLWithPath:@(path) isDirectory:NO];
-    NSData *rootCertData = [NSData dataWithContentsOfURL:url];
-
-    OSStatus err = noErr;
-    SecCertificateRef rootCert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef) rootCertData);
-
-    CFTypeRef result;
-
-    NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
-        (id)kSecClassCertificate, kSecClass,
-        rootCert, kSecValueRef,
-        nil];
-
-    err = SecItemAdd((CFDictionaryRef)dict, &result);
-
-    if (err == noErr) {
-        NSLog(@"Install root certificate success");
-    } else if (err == errSecDuplicateItem) {
-        NSString *errString = [@"duplicate root certificate entry. Error: " stringByAppendingFormat:@"%d", err];
-        NSLog(@"%@", errString);
-        return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];;
-    } else {
-        NSString *errString = [@"install root certificate failure. Error: " stringByAppendingFormat:@"%d", err];
-        NSLog(@"%@", errString);
-        return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
-    }
-
-    NSDictionary *newTrustSettings = @{(id)kSecTrustSettingsResult: [NSNumber numberWithInt:kSecTrustSettingsResultTrustRoot]};
-    err = SecTrustSettingsSetTrustSettings(rootCert, kSecTrustSettingsDomainUser, (__bridge CFTypeRef)(newTrustSettings));
-    if (err != errSecSuccess) {
-        NSString *errString = [@"Could not change the trust setting for a certificate. Error: " stringByAppendingFormat:@"%d", err];
-        NSLog(@"%@", errString);
-        return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
-    }
-
-    return "";
-}
-
-const char *uninstallCert() {
-    // Each line is a key-value of the dictionary. Note: the the inverted order, value first then key.
-    NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
-        (id)kSecClassCertificate, kSecClass,
-        CFSTR("Arduino"), kSecAttrLabel,
-        kSecMatchLimitOne, kSecMatchLimit,
-        kCFBooleanTrue, kSecReturnAttributes,
-        nil];
-
-    OSStatus err = noErr;
-    // Use this function to check for errors
-    err = SecItemCopyMatching((CFDictionaryRef)dict, nil);
-    if (err == noErr) {
-        err = SecItemDelete((CFDictionaryRef)dict);
-        if (err != noErr) {
-            NSString *errString = [@"Could not delete the certificates. Error: " stringByAppendingFormat:@"%d", err];
-            NSLog(@"%@", errString);
-            return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];;
-        }
-    } else if (err != errSecItemNotFound){
-        NSString *errString = [@"Error: " stringByAppendingFormat:@"%d", err];
-        NSLog(@"%@", errString);
-        return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];;
-    }
-    return "";
-}
-
-const char *getExpirationDate(char *expirationDate){
-    // Create a key-value dictionary used to query the Keychain and look for the "Arduino" root certificate.
-    NSDictionary *getquery = @{
-                (id)kSecClass:     (id)kSecClassCertificate,
-                (id)kSecAttrLabel: @"Arduino",
-                (id)kSecReturnRef: @YES,
-            };
-
-    OSStatus err = noErr;
-    SecCertificateRef cert = NULL;
-
-    // Use this function to check for errors
-    err = SecItemCopyMatching((CFDictionaryRef)getquery, (CFTypeRef *)&cert);
-
-    if (err != noErr){
-        NSString *errString = [@"Error: " stringByAppendingFormat:@"%d", err];
-        NSLog(@"%@", errString);
-        return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
-    }
 
-    // Get data from the certificate. We just need the "invalidity date" property.
-    CFDictionaryRef valuesDict = SecCertificateCopyValues(cert, (__bridge CFArrayRef)@[(__bridge id)kSecOIDInvalidityDate], NULL);
-
-    id expirationDateValue;
-    if(valuesDict){
-        CFDictionaryRef invalidityDateDictionaryRef = CFDictionaryGetValue(valuesDict, kSecOIDInvalidityDate);
-        if(invalidityDateDictionaryRef){
-            CFTypeRef invalidityRef = CFDictionaryGetValue(invalidityDateDictionaryRef, kSecPropertyKeyValue);
-            if(invalidityRef){
-                expirationDateValue = CFBridgingRelease(invalidityRef);
-            }
-        }
-        CFRelease(valuesDict);
-    }
-
-    NSString *outputString = [@"" stringByAppendingFormat:@"%@", expirationDateValue];
-    if([outputString isEqualToString:@""]){
-        NSString *errString = @"Error: the expiration date of the certificate could not be found";
-        NSLog(@"%@", errString);
-        return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
-    }
-
-    // This workaround allows to obtain the expiration date alongside the error message
-    strncpy(expirationDate, [outputString cStringUsingEncoding:[NSString defaultCStringEncoding]], 32);
-    expirationDate[32-1] = 0;
-
-    return "";
-}
-
-const char *getDefaultBrowserName() {
-    NSURL *defaultBrowserURL = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:[NSURL URLWithString:@"http://"]];
-    if (defaultBrowserURL) {
-        NSBundle *defaultBrowserBundle = [NSBundle bundleWithURL:defaultBrowserURL];
-        NSString *defaultBrowser = [defaultBrowserBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"];
-
-        return [defaultBrowser cStringUsingEncoding:[NSString defaultCStringEncoding]];
-    }
+// Pass the list of macOS frameworks needed by this piece of Objective-C code.
+#cgo LDFLAGS: -framework Foundation -framework Security -framework AppKit
 
-    return "";
-}
+#import <Foundation/Foundation.h>
+#include "certificates_darwin.h"
 */
 import "C"
 import (
 	"errors"
-	"strings"
+	"time"
 	"unsafe"
 
 	log "github.com/sirupsen/logrus"
@@ -172,7 +46,7 @@ func InstallCertificate(cert *paths.Path) error {
 	p := C.installCert(ccert)
 	s := C.GoString(p)
 	if len(s) != 0 {
-		utilities.UserPrompt("display dialog \"" + s + "\" buttons \"OK\" with title \"Arduino Agent: Error installing certificates\"")
+		utilities.UserPrompt(s, "\"OK\"", "OK", "OK", "Arduino Agent: Error installing certificates")
 		UninstallCertificates()
 		return errors.New(s)
 	}
@@ -186,25 +60,29 @@ func UninstallCertificates() error {
 	p := C.uninstallCert()
 	s := C.GoString(p)
 	if len(s) != 0 {
-		utilities.UserPrompt("display dialog \"" + s + "\" buttons \"OK\" with title \"Arduino Agent: Error uninstalling certificates\"")
+		utilities.UserPrompt(s, "\"OK\"", "OK", "OK", "Arduino Agent: Error uninstalling certificates")
 		return errors.New(s)
 	}
 	return nil
 }
 
 // GetExpirationDate returns the expiration date of a certificate stored in the keychain
-func GetExpirationDate() (string, error) {
+func GetExpirationDate() (time.Time, error) {
 	log.Infof("Retrieving certificate's expiration date")
-	dateString := C.CString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") // 32 characters string
-	defer C.free(unsafe.Pointer(dateString))
-	p := C.getExpirationDate(dateString)
-	s := C.GoString(p)
-	if len(s) != 0 {
-		utilities.UserPrompt("display dialog \"" + s + "\" buttons \"OK\" with title \"Arduino Agent: Error retrieving expiration date\"")
-		return "", errors.New(s)
+
+	expirationDateLong := C.long(0)
+
+	err := C.getExpirationDate(&expirationDateLong)
+	errString := C.GoString(err)
+	if len(errString) > 0 {
+		utilities.UserPrompt(errString, "\"OK\"", "OK", "OK", "Arduino Agent: Error retrieving expiration date")
+		return time.Time{}, errors.New(errString)
 	}
-	date := C.GoString(dateString)
-	return strings.ReplaceAll(date, " +0000", ""), nil
+
+	// The expirationDate is the number of seconds from the date of 1 Jan 2001 00:00:00 GMT.
+	// Add 31 years to convert it to Unix Epoch.
+	expirationDate := int64(expirationDateLong)
+	return time.Unix(expirationDate, 0).AddDate(31, 0, 0), nil
 }
 
 // GetDefaultBrowserName returns the name of the default browser
@@ -213,3 +91,11 @@ func GetDefaultBrowserName() string {
 	p := C.getDefaultBrowserName()
 	return C.GoString(p)
 }
+
+// CertInKeychain checks if the certificate is stored inside the keychain
+func CertInKeychain() bool {
+	log.Infof("Checking if the Arduino certificate is in the keychain")
+
+	certInKeychain := C.certInKeychain()
+	return bool(certInKeychain)
+}
diff --git a/certificates/install_default.go b/certificates/install_default.go
index 8013c018..533574d6 100644
--- a/certificates/install_default.go
+++ b/certificates/install_default.go
@@ -19,6 +19,7 @@ package certificates
 
 import (
 	"errors"
+	"time"
 
 	log "github.com/sirupsen/logrus"
 
@@ -38,9 +39,9 @@ func UninstallCertificates() error {
 }
 
 // GetExpirationDate won't do anything on unsupported Operative Systems
-func GetExpirationDate() (string, error) {
+func GetExpirationDate() (time.Time, error) {
 	log.Warn("platform not supported for retrieving certificates expiration date")
-	return "", errors.New("platform not supported for retrieving certificates expiration date")
+	return time.Time{}, errors.New("platform not supported for retrieving certificates expiration date")
 }
 
 // GetDefaultBrowserName won't do anything on unsupported Operative Systems
@@ -48,3 +49,9 @@ func GetDefaultBrowserName() string {
 	log.Warn("platform not supported for retrieving default browser name")
 	return ""
 }
+
+// CertInKeychain won't do anything on unsupported Operative Systems
+func CertInKeychain() bool {
+	log.Warn("platform not supported for verifying the certificate existence")
+	return false
+}
diff --git a/main.go b/main.go
index 0231548d..1ca857b0 100755
--- a/main.go
+++ b/main.go
@@ -178,7 +178,7 @@ func loop() {
 	// If we are updating manually from 1.2.7 to 1.3.0 we have to uninstall the old agent manually first.
 	// This check will inform the user if he needs to run the uninstall first
 	if runtime.GOOS == "darwin" && oldInstallExists() {
-		utilities.UserPrompt("display dialog \"Old agent installation of the Arduino Create Agent found, please uninstall it before launching the new one\" buttons \"OK\" with title \"Error\"")
+		utilities.UserPrompt("Old agent installation of the Arduino Create Agent found, please uninstall it before launching the new one", "\"OK\"", "OK", "OK", "Error")
 		os.Exit(0)
 	}
 
@@ -223,25 +223,27 @@ func loop() {
 
 	// if the default browser is Safari, prompt the user to install HTTPS certificates
 	// and eventually install them
-	if runtime.GOOS == "darwin" && cert.GetDefaultBrowserName() == "Safari" {
+	if runtime.GOOS == "darwin" {
 		if exist, err := installCertsKeyExists(configPath.String()); err != nil {
 			log.Panicf("config.ini cannot be parsed: %s", err)
 		} else if !exist {
-			if config.CertsExist() {
-				err = config.SetInstallCertsIni(configPath.String(), "true")
-				if err != nil {
-					log.Panicf("config.ini cannot be parsed: %s", err)
-				}
-			} else if cert.PromptInstallCertsSafari() {
+			if cert.CertInKeychain() || config.CertsExist() {
 				err = config.SetInstallCertsIni(configPath.String(), "true")
 				if err != nil {
 					log.Panicf("config.ini cannot be parsed: %s", err)
 				}
-				cert.GenerateAndInstallCertificates(config.GetCertificatesDir())
-			} else {
-				err = config.SetInstallCertsIni(configPath.String(), "false")
-				if err != nil {
-					log.Panicf("config.ini cannot be parsed: %s", err)
+			} else if cert.GetDefaultBrowserName() == "Safari" {
+				if promptInstallCertsSafari() {
+					err = config.SetInstallCertsIni(configPath.String(), "true")
+					if err != nil {
+						log.Panicf("config.ini cannot be parsed: %s", err)
+					}
+					cert.GenerateAndInstallCertificates(config.GetCertificatesDir())
+				} else {
+					err = config.SetInstallCertsIni(configPath.String(), "false")
+					if err != nil {
+						log.Panicf("config.ini cannot be parsed: %s", err)
+					}
 				}
 			}
 		}
@@ -369,21 +371,38 @@ func loop() {
 		}
 	}
 
-	// check if the HTTPS certificates are expired and prompt the user to update them on macOS
-	if runtime.GOOS == "darwin" && cert.GetDefaultBrowserName() == "Safari" {
-		if *installCerts {
-			if config.CertsExist() {
-				cert.PromptExpiredCerts(config.GetCertificatesDir())
-			} else if cert.PromptInstallCertsSafari() {
-				// installing the certificates from scratch at this point should only happen if
-				// something went wrong during previous installation attempts
-				cert.GenerateAndInstallCertificates(config.GetCertificatesDir())
-			} else {
-				err = config.SetInstallCertsIni(configPath.String(), "false")
-				if err != nil {
-					log.Panicf("config.ini cannot be parsed: %s", err)
+	// check if the HTTPS certificates are expired or expiring and prompt the user to update them on macOS
+	if runtime.GOOS == "darwin" && *installCerts {
+		if cert.CertInKeychain() || config.CertsExist() {
+			certDir := config.GetCertificatesDir()
+			if expired, err := cert.IsExpired(); err != nil {
+				log.Errorf("cannot check if certificates are expired something went wrong: %s", err)
+			} else if expired {
+				buttonPressed := utilities.UserPrompt("The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nYour certificate is expired or close to expiration. Do you want to update it?", "{\"Do not update\", \"Update the certificate for Safari\"}", "Update the certificate for Safari", "Update the certificate for Safari", "Arduino Agent: Update certificate")
+				if buttonPressed {
+					err := cert.UninstallCertificates()
+					if err != nil {
+						log.Errorf("cannot uninstall certificates something went wrong: %s", err)
+					} else {
+						cert.DeleteCertificates(certDir)
+						cert.GenerateAndInstallCertificates(certDir)
+					}
+				} else {
+					err = config.SetInstallCertsIni(configPath.String(), "false")
+					if err != nil {
+						log.Panicf("config.ini cannot be parsed: %s", err)
+					}
 				}
 			}
+		} else if promptInstallCertsSafari() {
+			// installing the certificates from scratch at this point should only happen if
+			// something went wrong during previous installation attempts
+			cert.GenerateAndInstallCertificates(config.GetCertificatesDir())
+		} else {
+			err = config.SetInstallCertsIni(configPath.String(), "false")
+			if err != nil {
+				log.Panicf("config.ini cannot be parsed: %s", err)
+			}
 		}
 	}
 
@@ -534,3 +553,7 @@ func installCertsKeyExists(filename string) (bool, error) {
 	}
 	return cfg.Section("").HasKey("installCerts"), nil
 }
+
+func promptInstallCertsSafari() bool {
+	return utilities.UserPrompt("The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\nIf you use Safari, you need to install it.", "{\"Do not install\", \"Install the certificate for Safari\"}", "Install the certificate for Safari", "Install the certificate for Safari", "Arduino Agent: Install certificate")
+}
diff --git a/systray/systray_real.go b/systray/systray_real.go
index 503373d8..5ae79f08 100644
--- a/systray/systray_real.go
+++ b/systray/systray_real.go
@@ -22,7 +22,7 @@ package systray
 import (
 	"os"
 	"runtime"
-	"strings"
+	"time"
 
 	"fyne.io/systray"
 	cert "github.com/arduino/arduino-create-agent/certificates"
@@ -95,38 +95,42 @@ func (s *Systray) start() {
 				s.updateMenuItem(mRmCrashes, config.LogsIsEmpty())
 			case <-mManageCerts.ClickedCh:
 				infoMsg := "The Arduino Agent needs a local HTTPS certificate to work correctly with Safari.\n\nYour HTTPS certificate status:\n"
-				buttons := "{\"Install the certificate for Safari\", \"OK\"} default button \"OK\""
+				buttons := "{\"Install the certificate for Safari\", \"OK\"}"
+				toPress := "Install the certificate for Safari"
 				certDir := config.GetCertificatesDir()
-				if config.CertsExist() {
+				if cert.CertInKeychain() || config.CertsExist() {
 					expDate, err := cert.GetExpirationDate()
 					if err != nil {
 						log.Errorf("cannot get certificates expiration date, something went wrong: %s", err)
 					}
-					infoMsg = infoMsg + "- Certificate installed: Yes\n- Certificate trusted: Yes\n- Certificate expiration date: " + expDate
-					buttons = "{\"Uninstall the certificate for Safari\", \"OK\"} default button \"OK\""
-				} else {
-					infoMsg = infoMsg + "- Certificate installed: No\n- Certificate trusted: N/A\n- Certificate expiration date: N/A"
-				}
-				pressedButton := utilities.UserPrompt("display dialog \"" + infoMsg + "\" buttons " + buttons + " with title \"Arduino Agent: Manage HTTPS certificate\"")
-				if strings.Contains(pressedButton, "Install certificate for Safari") {
-					cert.GenerateAndInstallCertificates(certDir)
-					err := config.SetInstallCertsIni(s.currentConfigFilePath.String(), "true")
-					if err != nil {
-						log.Errorf("cannot set installCerts value in config.ini: %s", err)
+					infoMsg = infoMsg + "- Certificate installed:\t\tYes\n- Certificate trusted:\t\tYes\n- Certificate expiration:\t" + expDate.Format(time.DateTime)
+					buttons = "{\"Uninstall the certificate for Safari\", \"OK\"}"
+					toPress = "Uninstall the certificate for Safari"
+					pressedButton := utilities.UserPrompt(infoMsg, buttons, "OK", toPress, "Arduino Agent: Manage HTTPS certificate")
+					if pressedButton {
+						err := cert.UninstallCertificates()
+						if err != nil {
+							log.Errorf("cannot uninstall certificates something went wrong: %s", err)
+						} else {
+							cert.DeleteCertificates(certDir)
+							err = config.SetInstallCertsIni(s.currentConfigFilePath.String(), "false")
+							if err != nil {
+								log.Errorf("cannot set installCerts value in config.ini: %s", err)
+							}
+						}
+						s.Restart()
 					}
-					s.Restart()
-				} else if strings.Contains(pressedButton, "Uninstall certificate for Safari") {
-					err := cert.UninstallCertificates()
-					if err != nil {
-						log.Errorf("cannot uninstall certificates something went wrong: %s", err)
-					} else {
-						cert.DeleteCertificates(certDir)
-						err = config.SetInstallCertsIni(s.currentConfigFilePath.String(), "false")
+				} else {
+					infoMsg = infoMsg + "- Certificate installed:\t\tNo\n- Certificate trusted:\t\tN/A\n- Certificate expiration:\tN/A"
+					pressedButton := utilities.UserPrompt(infoMsg, buttons, "OK", toPress, "Arduino Agent: Manage HTTPS certificate")
+					if pressedButton {
+						cert.GenerateAndInstallCertificates(certDir)
+						err := config.SetInstallCertsIni(s.currentConfigFilePath.String(), "true")
 						if err != nil {
 							log.Errorf("cannot set installCerts value in config.ini: %s", err)
 						}
+						s.Restart()
 					}
-					s.Restart()
 				}
 			case <-mPause.ClickedCh:
 				s.Pause()
diff --git a/utilities/utilities.go b/utilities/utilities.go
index 63f09103..5979732d 100644
--- a/utilities/utilities.go
+++ b/utilities/utilities.go
@@ -151,8 +151,8 @@ func VerifyInput(input string, signature string) error {
 }
 
 // UserPrompt executes an osascript and returns the pressed button
-func UserPrompt(dialog string) string {
-	oscmd := exec.Command("osascript", "-e", dialog)
+func UserPrompt(dialog string, buttons string, defaultButton string, toPress string, title string) bool {
+	oscmd := exec.Command("osascript", "-e", "display dialog \""+dialog+"\" buttons "+buttons+" default button\""+defaultButton+"\" with title \""+title+"\"")
 	pressedButton, _ := oscmd.Output()
-	return string(pressedButton)
+	return strings.Contains(string(pressedButton), "button returned:"+toPress)
 }