From 033c5993e077e969e7c5ff7cedf7fd1d48bf7011 Mon Sep 17 00:00:00 2001 From: Abdalrahman Date: Thu, 14 May 2026 11:24:23 +0300 Subject: [PATCH] feat: add API token to install output (#4322) * feat: add API token to install output Add -getApiToken flag to the setting subcommand so shell scripts can retrieve the panel API token. Include the token in the install.sh completion banner for automation/deployment use. * fix(install): adapt -getApiToken CLI to multi-token service settingService.GetApiToken was removed when API tokens moved to a multi-row ApiTokenService. Switch the install-time CLI to list tokens and create one named "install" if none exist, preserving the `apiToken: ` output the install.sh grep depends on. --------- Co-authored-by: Sanaei --- install.sh | 4 ++++ main.go | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/install.sh b/install.sh index 1908c34c..63d81863 100644 --- a/install.sh +++ b/install.sh @@ -763,6 +763,9 @@ config_after_install() { prompt_and_setup_ssl "${config_port}" "${config_webBasePath}" "${server_ip}" + # Retrieve the API token for display + local config_apiToken=$(${xui_folder}/x-ui setting -getApiToken true | grep -Eo 'apiToken: .+' | awk '{print $2}') + # Display final credentials and access information echo "" echo -e "${green}═══════════════════════════════════════════${plain}" @@ -773,6 +776,7 @@ config_after_install() { echo -e "${green}Port: ${config_port}${plain}" echo -e "${green}WebBasePath: ${config_webBasePath}${plain}" echo -e "${green}Access URL: ${SSL_SCHEME}://${SSL_HOST}:${config_port}/${config_webBasePath}${plain}" + echo -e "${green}API Token: ${config_apiToken}${plain}" echo -e "${green}═══════════════════════════════════════════${plain}" echo -e "${yellow}⚠ IMPORTANT: Save these credentials securely!${plain}" if [[ "$SSL_SCHEME" == "https" ]]; then diff --git a/main.go b/main.go index 90db08da..c5ce40b9 100644 --- a/main.go +++ b/main.go @@ -391,6 +391,28 @@ func GetListenIP(getListen bool) { } } +func GetApiToken(getApiToken bool) { + if !getApiToken { + return + } + apiTokenService := service.ApiTokenService{} + tokens, err := apiTokenService.List() + if err != nil { + fmt.Println("get apiToken failed, error info:", err) + return + } + if len(tokens) > 0 { + fmt.Println("apiToken:", tokens[0].Token) + return + } + created, err := apiTokenService.Create("install") + if err != nil { + fmt.Println("create apiToken failed, error info:", err) + return + } + fmt.Println("apiToken:", created.Token) +} + // migrateDb performs database migration operations for the 3x-ui panel. func migrateDb() { inboundService := service.InboundService{} @@ -433,6 +455,7 @@ func main() { var reset bool var show bool var getCert bool + var getApiToken bool var resetTwoFactor bool settingCmd.BoolVar(&reset, "reset", false, "Reset all settings") settingCmd.BoolVar(&show, "show", false, "Display current settings") @@ -444,6 +467,7 @@ func main() { settingCmd.BoolVar(&resetTwoFactor, "resetTwoFactor", false, "Reset two-factor authentication settings") settingCmd.BoolVar(&getListen, "getListen", false, "Display current panel listenIP IP") settingCmd.BoolVar(&getCert, "getCert", false, "Display current certificate settings") + settingCmd.BoolVar(&getApiToken, "getApiToken", false, "Display current API token") settingCmd.StringVar(&webCertFile, "webCert", "", "Set path to public key file for panel") settingCmd.StringVar(&webKeyFile, "webCertKey", "", "Set path to private key file for panel") settingCmd.StringVar(&tgbottoken, "tgbottoken", "", "Set token for Telegram bot") @@ -501,6 +525,9 @@ func main() { if getCert { GetCertificate(getCert) } + if getApiToken { + GetApiToken(getApiToken) + } if (tgbottoken != "") || (tgbotchatid != "") || (tgbotRuntime != "") { updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime) }