From d0f086d5acbeb86aff3e0915f6884cc7f0efa22b Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Tue, 24 Mar 2026 00:09:35 +0530 Subject: [PATCH 01/12] feat: added toolchain to env and request params config and no detection values interactive prompting flow --- internal/auth0/quickstart.go | 430 +++++++++++++++++++++++++++++++++++ internal/cli/quickstarts.go | 302 ++++++++++++++++++++++++ 2 files changed, 732 insertions(+) diff --git a/internal/auth0/quickstart.go b/internal/auth0/quickstart.go index 60a10fee2..09c346ed0 100644 --- a/internal/auth0/quickstart.go +++ b/internal/auth0/quickstart.go @@ -174,3 +174,433 @@ func (q Quickstarts) Stacks() []string { return stacks } + +const DETECTION_SUB = "DETECTION_SUB" + +type RequestParams struct { + AppType string + Callbacks []string + AllowedLogoutURLs []string + WebOrigins []string +} + +type AppConfig struct { + EnvValues map[string]string + RequestParams RequestParams +} + +// Map key format: "type:framework:build_tool" +var QuickstartConfigs = map[string]AppConfig{ + + // ========================================== + // Single Page Applications (SPA) + // ========================================== + "spa:react:vite": { + EnvValues: map[string]string{ + "VITE_AUTH0_DOMAIN": DETECTION_SUB, + "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "spa", + Callbacks: []string{DETECTION_SUB}, // e.g., http://localhost:5173 + AllowedLogoutURLs: []string{DETECTION_SUB}, + WebOrigins: []string{DETECTION_SUB}, + }, + }, + "spa:angular:none": { + EnvValues: map[string]string{ + "domain": DETECTION_SUB, + "clientId": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "spa", + Callbacks: []string{DETECTION_SUB}, // e.g., http://localhost:4200 + AllowedLogoutURLs: []string{DETECTION_SUB}, + WebOrigins: []string{DETECTION_SUB}, + }, + }, + "spa:vue:vite": { + EnvValues: map[string]string{ + "VITE_AUTH0_DOMAIN": DETECTION_SUB, + "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "spa", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + WebOrigins: []string{DETECTION_SUB}, + }, + }, + "spa:svelte:vite": { + EnvValues: map[string]string{ + "VITE_AUTH0_DOMAIN": DETECTION_SUB, + "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "spa", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + WebOrigins: []string{DETECTION_SUB}, + }, + }, + "spa:vanilla-javascript:vite": { + EnvValues: map[string]string{ + "VITE_AUTH0_DOMAIN": DETECTION_SUB, + "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "spa", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + WebOrigins: []string{DETECTION_SUB}, + }, + }, + "spa:flutter-web:none": { + EnvValues: map[string]string{ + "domain": DETECTION_SUB, + "clientId": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "spa", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + WebOrigins: []string{DETECTION_SUB}, + }, + }, + + // ========================================== + // Regular Web Applications + // ========================================== + "regular:nextjs:none": { + EnvValues: map[string]string{ + "AUTH0_DOMAIN": DETECTION_SUB, + "AUTH0_CLIENT_ID": DETECTION_SUB, + "AUTH0_CLIENT_SECRET": DETECTION_SUB, + "AUTH0_SECRET": DETECTION_SUB, + "APP_BASE_URL": DETECTION_SUB, // e.g., http://localhost:3000 + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, // e.g., http://localhost:3000/api/auth/callback + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:nuxt:none": { + EnvValues: map[string]string{ + "NUXT_AUTH0_DOMAIN": DETECTION_SUB, + "NUXT_AUTH0_CLIENT_ID": DETECTION_SUB, + "NUXT_AUTH0_CLIENT_SECRET": DETECTION_SUB, + "NUXT_AUTH0_SESSION_SECRET": DETECTION_SUB, + "NUXT_AUTH0_APP_BASE_URL": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:fastify:none": { + EnvValues: map[string]string{ + "AUTH0_DOMAIN": DETECTION_SUB, + "AUTH0_CLIENT_ID": DETECTION_SUB, + "AUTH0_CLIENT_SECRET": DETECTION_SUB, + "SESSION_SECRET": DETECTION_SUB, + "APP_BASE_URL": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:sveltekit:none": { + EnvValues: map[string]string{ + "VITE_AUTH0_DOMAIN": DETECTION_SUB, + "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:express:none": { + EnvValues: map[string]string{ + "ISSUER_BASE_URL": DETECTION_SUB, + "CLIENT_ID": DETECTION_SUB, + "SECRET": DETECTION_SUB, + "BASE_URL": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:hono:none": { + EnvValues: map[string]string{ + "AUTH0_DOMAIN": DETECTION_SUB, + "AUTH0_CLIENT_ID": DETECTION_SUB, + "AUTH0_CLIENT_SECRET": DETECTION_SUB, + "AUTH0_SESSION_ENCRYPTION_KEY": DETECTION_SUB, + "BASE_URL": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:vanilla-python:none": { + EnvValues: map[string]string{ + "AUTH0_DOMAIN": DETECTION_SUB, + "AUTH0_CLIENT_ID": DETECTION_SUB, + "AUTH0_CLIENT_SECRET": DETECTION_SUB, + "AUTH0_SECRET": DETECTION_SUB, + "AUTH0_REDIRECT_URI": DETECTION_SUB, // e.g., http://localhost:3000/callback + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:django:none": { + EnvValues: map[string]string{ + "AUTH0_DOMAIN": DETECTION_SUB, + "AUTH0_CLIENT_ID": DETECTION_SUB, + "AUTH0_CLIENT_SECRET": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:vanilla-go:none": { + EnvValues: map[string]string{ + "AUTH0_DOMAIN": DETECTION_SUB, + "AUTH0_CLIENT_ID": DETECTION_SUB, + "AUTH0_CLIENT_SECRET": DETECTION_SUB, + "AUTH0_CALLBACK_URL": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:vanilla-java:maven": { + EnvValues: map[string]string{ + "auth0.domain": DETECTION_SUB, + "auth0.clientId": DETECTION_SUB, + "auth0.clientSecret": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:java-ee:maven": { + EnvValues: map[string]string{ + "auth0.domain": DETECTION_SUB, + "auth0.clientId": DETECTION_SUB, + "auth0.clientSecret": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:spring-boot:maven": { + EnvValues: map[string]string{ + "okta.oauth2.issuer": DETECTION_SUB, + "okta.oauth2.client-id": DETECTION_SUB, + "okta.oauth2.client-secret": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, // e.g., http://localhost:8080/login/oauth2/code/okta + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:aspnet-mvc:none": { + EnvValues: map[string]string{ + "Auth0:Domain": DETECTION_SUB, + "Auth0:ClientId": DETECTION_SUB, + "Auth0:ClientSecret": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:aspnet-blazor:none": { + EnvValues: map[string]string{ + "Auth0:Domain": DETECTION_SUB, + "Auth0:ClientId": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:aspnet-owin:none": { + EnvValues: map[string]string{ + "auth0:Domain": DETECTION_SUB, + "auth0:ClientId": DETECTION_SUB, + "auth0:ClientSecret": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:vanilla-php:composer": { + EnvValues: map[string]string{ + "AUTH0_DOMAIN": DETECTION_SUB, + "AUTH0_CLIENT_ID": DETECTION_SUB, + "AUTH0_CLIENT_SECRET": DETECTION_SUB, + "AUTH0_COOKIE_SECRET": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:laravel:composer": { + EnvValues: map[string]string{ + "AUTH0_DOMAIN": DETECTION_SUB, + "AUTH0_CLIENT_ID": DETECTION_SUB, + "AUTH0_CLIENT_SECRET": DETECTION_SUB, + "AUTH0_COOKIE_SECRET": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "regular:rails:none": { + EnvValues: map[string]string{ + "auth0_domain": DETECTION_SUB, + "auth0_client_id": DETECTION_SUB, + "auth0_client_secret": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "regular_web", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + + // ========================================== + // Native / Mobile Applications + // ========================================== + "native:flutter:none": { + EnvValues: map[string]string{ + "domain": DETECTION_SUB, + "clientId": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "native", + Callbacks: []string{DETECTION_SUB}, // Native intent, usually a custom scheme like YOUR_BUNDLE_ID://login-callback + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "native:react-native:none": { + EnvValues: map[string]string{ + "AUTH0_DOMAIN": DETECTION_SUB, + "AUTH0_CLIENT_ID": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "native", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "native:expo:none": { + EnvValues: map[string]string{ + "EXPO_PUBLIC_AUTH0_DOMAIN": DETECTION_SUB, + "EXPO_PUBLIC_AUTH0_CLIENT_ID": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "native", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "native:ionic-angular:none": { + EnvValues: map[string]string{ + "domain": DETECTION_SUB, + "clientId": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "native", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "native:ionic-react:vite": { + EnvValues: map[string]string{ + "VITE_AUTH0_DOMAIN": DETECTION_SUB, + "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "native", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "native:ionic-vue:vite": { + EnvValues: map[string]string{ + "VITE_AUTH0_DOMAIN": DETECTION_SUB, + "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "native", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "native:dotnet-mobile:none": { + EnvValues: map[string]string{ + "Auth0:Domain": DETECTION_SUB, + "Auth0:ClientId": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "native", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "native:maui:none": { + EnvValues: map[string]string{ + "Auth0:Domain": DETECTION_SUB, + "Auth0:ClientId": DETECTION_SUB, + }, + RequestParams: RequestParams{ + AppType: "native", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, + "native:wpf-winforms:none": { + EnvValues: map[string]string{ + "Auth0:Domain": DETECTION_SUB, + "Auth0:ClientId": DETECTION_SUB, + "Auth0:ClientSecret": DETECTION_SUB, // Wait, native app with a secret? Mapped as requested. + }, + RequestParams: RequestParams{ + AppType: "native", + Callbacks: []string{DETECTION_SUB}, + AllowedLogoutURLs: []string{DETECTION_SUB}, + }, + }, +} diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index d9978fc24..9b9111dd7 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -68,6 +68,7 @@ func quickstartsCmd(cli *cli) *cobra.Command { cmd.AddCommand(listQuickstartsCmd(cli)) cmd.AddCommand(downloadQuickstartCmd(cli)) cmd.AddCommand(setupQuickstartCmd(cli)) + cmd.AddCommand(setupQuickstartCmdExperimental(cli)) return cmd } @@ -656,3 +657,304 @@ func setupQuickstartCmd(cli *cli) *cobra.Command { return cmd } + +func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { + var inputs struct { + Name string + App bool + Type string + Framework string + BuildTool string + Port int + CallbackURL string + LogoutURL string + WebOriginURL string + API bool + Identifier string + Audience string + SigningAlg string + Scopes string + TokenLifetime string + OfflineAccess bool + } + + cmd := &cobra.Command{ + Use: "setup-experimental", + Args: cobra.NoArgs, + Short: "Set up Auth0 for your quickstart application", + Long: "Creates an Auth0 application and generates a .env file with the necessary configuration.\n\n" + + "The command will:\n" + + " 1. Check if you are authenticated (and prompt for login if needed)\n" + + " 2. Create an Auth0 application based on the specified type\n" + + " 3. Generate a .env file with the appropriate environment variables\n\n" + + "Supported types are dynamically loaded from the `QuickstartConfigs` map in the codebase.", + Example: ` auth0 quickstarts setup-experimental --type spa:react:vite + auth0 quickstarts setup-experimental --type regular:nextjs:none + auth0 quickstarts setup-experimental --type native:react-native:none`, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + + if err := cli.setupWithAuthentication(ctx); err != nil { + return fmt.Errorf("authentication required: %w", err) + } + + qsConfigKey, updatedInputs, err := getQuickstartConfigKey(inputs) + if err != nil { + inputs = updatedInputs + return fmt.Errorf("failed to get quickstart configuration: %w", err) + } + + // Validate the input type against QuickstartConfigs + config, exists := auth0.QuickstartConfigs[qsConfigKey] + if !exists { + return fmt.Errorf("unsupported quickstart arguments: %s. Supported types: %v", qsConfigKey, getSupportedQuickstartTypes()) + } + + // Set default values based on the selected quickstart type + if inputs.Name == "" { + inputs.Name = "My App" + } + if inputs.Port == 0 { + inputs.Port = 3000 // Default port, can be adjusted based on the type if needed + } + + baseURL := fmt.Sprintf("http://localhost:%d", inputs.Port) + + // Create the Auth0 application + cli.renderer.Infof("Creating Auth0 application '%s'...", inputs.Name) + appType := config.RequestParams.AppType + callbacks := config.RequestParams.Callbacks + logoutURLs := config.RequestParams.AllowedLogoutURLs + + oidcConformant := true + algorithm := "RS256" + metadata := map[string]interface{}{ + "created_by": "quickstart-docs-manual-cli", + } + + a := &management.Client{ + Name: &inputs.Name, + AppType: &appType, + Callbacks: &callbacks, + AllowedLogoutURLs: &logoutURLs, + OIDCConformant: &oidcConformant, + JWTConfiguration: &management.ClientJWTConfiguration{ + Algorithm: &algorithm, + }, + ClientMetadata: &metadata, + } + + if err := ansi.Waiting(func() error { + return cli.api.Client.Create(ctx, a) + }); err != nil { + return fmt.Errorf("failed to create application: %w", err) + } + + cli.renderer.Infof("Application created successfully with Client ID: %s", a.GetClientID()) + + // Generate the .env file + envFileName := ".env" + var envContent strings.Builder + for key, value := range config.EnvValues { + fmt.Fprintf(&envContent, "%s=%s\n", key, value) + } + + if err := os.WriteFile(envFileName, []byte(envContent.String()), 0600); err != nil { + return fmt.Errorf("failed to write .env file: %w", err) + } + + cli.renderer.Infof("%s file created successfully with your Auth0 configuration\n", envFileName) + cli.renderer.Infof("Next steps: \n"+ + " 1. Install dependencies: npm install \n"+ + " 2. Start your application: npm run dev\n"+ + " 3. Open your browser at %s", baseURL) + + return nil + }, + } + + cmd.Flags().StringVar(&inputs.Type, "type", "", "Type of the quickstart application (e.g., spa:react:vite, regular:nextjs:none)") + cmd.Flags().StringVar(&inputs.Name, "name", "", "Name of the Auth0 application") + cmd.Flags().IntVar(&inputs.Port, "port", 0, "Port number for the application") + + return cmd +} + +// Helper function to get supported quickstart types +func getSupportedQuickstartTypes() []string { + var types []string + for key := range auth0.QuickstartConfigs { + types = append(types, key) + } + return types +} + +// For cleaner readability, you might consider extracting this anonymous struct into a named type (e.g., type SetupInputs struct {...}) +func getQuickstartConfigKey(inputs struct { + Name string + App bool + Type string + Framework string + BuildTool string + Port int + CallbackURL string + LogoutURL string + WebOriginURL string + API bool + Identifier string + Audience string + SigningAlg string + Scopes string + TokenLifetime string + OfflineAccess bool +}) (string, struct { + Name string + App bool + Type string + Framework string + BuildTool string + Port int + CallbackURL string + LogoutURL string + WebOriginURL string + API bool + Identifier string + Audience string + SigningAlg string + Scopes string + TokenLifetime string + OfflineAccess bool +}, error) { + + // Prompt for target resource(s) when neither flag is provided. + if !inputs.App && !inputs.API { + var selections []string + + err := prompt.AskMultiSelect( + "What do you want to create? (select whatever applies)", + &selections, + "App", + "API", + ) + if err != nil { + return "", inputs, fmt.Errorf("failed to select target resource(s): %v", err) + } + + for _, selection := range selections { + switch strings.ToLower(selection) { + case "app": + inputs.App = true + case "api": + inputs.API = true + } + } + + if !inputs.App && !inputs.API { + return "", inputs, fmt.Errorf("please select at least one option: App and/or API") + } + } + + // Handle application creation inputs + if inputs.App { + // Prompt for --type if not provided + if inputs.Type == "" { + types := []string{"spa", "regular", "native", "m2m"} + // name, message, help, options, defaultValue, required + q := prompt.SelectInput("type", "Select the application type", "", types, "m2m", true) + if err := prompt.AskOne(q, &inputs.Type); err != nil { + return "", inputs, fmt.Errorf("failed to select application type: %v", err) + } + } + + // Prompt for --framework if not provided + if inputs.Framework == "" { + frameworks := []string{"react", "angular", "vue", "svelte", "nextjs", "nuxt", "flutter", "express", "django", "spring-boot", "none"} + q := prompt.SelectInput("framework", "Select the framework", "", frameworks, "none", true) + if err := prompt.AskOne(q, &inputs.Framework); err != nil { + return "", inputs, fmt.Errorf("failed to select framework: %v", err) + } + } + + // Prompt for --build-tool if not provided (optional) + if inputs.BuildTool == "" { + buildTools := []string{"vite", "webpack", "cra", "none"} + q := prompt.SelectInput("build-tool", "Select the build tool (optional)", "", buildTools, "none", false) + if err := prompt.AskOne(q, &inputs.BuildTool); err != nil { + return "", inputs, fmt.Errorf("failed to select build tool: %v", err) + } + } + + // Set default values + if inputs.Name == "" { + inputs.Name = "My App" + } + if inputs.Port == 0 { + inputs.Port = 3000 + } + if inputs.CallbackURL == "" { + inputs.CallbackURL = fmt.Sprintf("http://localhost:%d/callback", inputs.Port) + } + if inputs.LogoutURL == "" { + inputs.LogoutURL = fmt.Sprintf("http://localhost:%d/logout", inputs.Port) + } + if inputs.WebOriginURL == "" { + inputs.WebOriginURL = fmt.Sprintf("http://localhost:%d", inputs.Port) + } + } + + // Handle API creation inputs + if inputs.API { + // Prompt for --identifier or --audience if not provided + if inputs.Identifier == "" && inputs.Audience == "" { + // name, message, help, defaultValue, required + q := prompt.TextInput("identifier", "Enter the API identifier (or audience)", "", "", true) + if err := prompt.AskOne(q, &inputs.Identifier); err != nil { + return "", inputs, fmt.Errorf("failed to enter API identifier: %v", err) + } + } + + // Use --audience as an alias for --identifier if provided + if inputs.Identifier == "" { + inputs.Identifier = inputs.Audience + } + + // Prompt for --signing-alg if not provided + if inputs.SigningAlg == "" { + signingAlgs := []string{"RS256", "PS256", "HS256"} + q := prompt.SelectInput("signing-alg", "Select the signing algorithm", "", signingAlgs, "RS256", true) + if err := prompt.AskOne(q, &inputs.SigningAlg); err != nil { + return "", inputs, fmt.Errorf("failed to select signing algorithm: %v", err) + } + } + + // Prompt for --scopes if not provided + if inputs.Scopes == "" { + q := prompt.TextInput("scopes", "Enter the scopes (comma-separated)", "", "", false) + if err := prompt.AskOne(q, &inputs.Scopes); err != nil { + return "", inputs, fmt.Errorf("failed to enter scopes: %v", err) + } + } + + // Prompt for --token-lifetime if not provided + if inputs.TokenLifetime == "" { + q := prompt.TextInput("token-lifetime", "Enter the token lifetime (in seconds)", "", "86400", true) + if err := prompt.AskOne(q, &inputs.TokenLifetime); err != nil { + return "", inputs, fmt.Errorf("failed to enter token lifetime: %v", err) + } + } + + if !inputs.OfflineAccess { + inputs.OfflineAccess = false + } + } + + // Construct the key to query QuickstartConfigs + // Fallback to "none" if build tool wasn't asked/selected to match the config map keys + buildToolKey := inputs.BuildTool + if buildToolKey == "" { + buildToolKey = "none" + } + + configKey := fmt.Sprintf("%s:%s:%s", inputs.Type, inputs.Framework, buildToolKey) + return configKey, inputs, nil +} From ccfce638e304403d1028dc6bba551f19087bcb26 Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Tue, 24 Mar 2026 13:15:35 +0530 Subject: [PATCH 02/12] fix: updated the logout and callback URLs --- internal/auth0/quickstart.go | 64 ++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/internal/auth0/quickstart.go b/internal/auth0/quickstart.go index 09c346ed0..cec6b4287 100644 --- a/internal/auth0/quickstart.go +++ b/internal/auth0/quickstart.go @@ -202,8 +202,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "spa", - Callbacks: []string{DETECTION_SUB}, // e.g., http://localhost:5173 - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:5173/callback"}, + AllowedLogoutURLs: []string{"http://localhost:5173"}, WebOrigins: []string{DETECTION_SUB}, }, }, @@ -214,8 +214,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "spa", - Callbacks: []string{DETECTION_SUB}, // e.g., http://localhost:4200 - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:4200/callback"}, + AllowedLogoutURLs: []string{"http://localhost:4200"}, WebOrigins: []string{DETECTION_SUB}, }, }, @@ -226,8 +226,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "spa", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:5173/callback"}, + AllowedLogoutURLs: []string{"http://localhost:5173"}, WebOrigins: []string{DETECTION_SUB}, }, }, @@ -238,8 +238,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "spa", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:5173/callback"}, + AllowedLogoutURLs: []string{"http://localhost:5173"}, WebOrigins: []string{DETECTION_SUB}, }, }, @@ -250,8 +250,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "spa", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:5173/callback"}, + AllowedLogoutURLs: []string{"http://localhost:5173"}, WebOrigins: []string{DETECTION_SUB}, }, }, @@ -277,12 +277,12 @@ var QuickstartConfigs = map[string]AppConfig{ "AUTH0_CLIENT_ID": DETECTION_SUB, "AUTH0_CLIENT_SECRET": DETECTION_SUB, "AUTH0_SECRET": DETECTION_SUB, - "APP_BASE_URL": DETECTION_SUB, // e.g., http://localhost:3000 + "APP_BASE_URL": DETECTION_SUB, }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, // e.g., http://localhost:3000/api/auth/callback - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:3000/callback"}, + AllowedLogoutURLs: []string{"http://localhost:3000"}, }, }, "regular:nuxt:none": { @@ -295,8 +295,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:3000/callback"}, + AllowedLogoutURLs: []string{"http://localhost:3000"}, }, }, "regular:fastify:none": { @@ -309,8 +309,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:3000/callback"}, + AllowedLogoutURLs: []string{"http://localhost:3000"}, }, }, "regular:sveltekit:none": { @@ -333,8 +333,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:3000/callback"}, + AllowedLogoutURLs: []string{"http://localhost:3000"}, }, }, "regular:hono:none": { @@ -347,8 +347,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:3000/callback"}, + AllowedLogoutURLs: []string{"http://localhost:3000"}, }, }, "regular:vanilla-python:none": { @@ -357,12 +357,12 @@ var QuickstartConfigs = map[string]AppConfig{ "AUTH0_CLIENT_ID": DETECTION_SUB, "AUTH0_CLIENT_SECRET": DETECTION_SUB, "AUTH0_SECRET": DETECTION_SUB, - "AUTH0_REDIRECT_URI": DETECTION_SUB, // e.g., http://localhost:3000/callback + "AUTH0_REDIRECT_URI": DETECTION_SUB, }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:5000/callback"}, + AllowedLogoutURLs: []string{"http://localhost:5000"}, }, }, "regular:django:none": { @@ -422,8 +422,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, // e.g., http://localhost:8080/login/oauth2/code/okta - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:8000/callback"}, + AllowedLogoutURLs: []string{"http://localhost:8000"}, }, }, "regular:aspnet-mvc:none": { @@ -483,8 +483,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:8000/callback"}, + AllowedLogoutURLs: []string{"http://localhost:8000"}, }, }, "regular:rails:none": { @@ -495,8 +495,8 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{"http://localhost:3000/callback"}, + AllowedLogoutURLs: []string{"http://localhost:3000"}, }, }, @@ -510,7 +510,7 @@ var QuickstartConfigs = map[string]AppConfig{ }, RequestParams: RequestParams{ AppType: "native", - Callbacks: []string{DETECTION_SUB}, // Native intent, usually a custom scheme like YOUR_BUNDLE_ID://login-callback + Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, }, }, @@ -595,7 +595,7 @@ var QuickstartConfigs = map[string]AppConfig{ EnvValues: map[string]string{ "Auth0:Domain": DETECTION_SUB, "Auth0:ClientId": DETECTION_SUB, - "Auth0:ClientSecret": DETECTION_SUB, // Wait, native app with a secret? Mapped as requested. + "Auth0:ClientSecret": DETECTION_SUB, }, RequestParams: RequestParams{ AppType: "native", From ae304cbda4d756d5e85628024bcb15426c02f8e1 Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Tue, 24 Mar 2026 13:25:08 +0530 Subject: [PATCH 03/12] docs: updated docs to fix PR checks --- docs/auth0_quickstarts.md | 1 + docs/auth0_quickstarts_download.md | 1 + docs/auth0_quickstarts_list.md | 1 + docs/auth0_quickstarts_setup-experimental.md | 57 ++++++++++++++++++++ docs/auth0_quickstarts_setup.md | 1 + 5 files changed, 61 insertions(+) create mode 100644 docs/auth0_quickstarts_setup-experimental.md diff --git a/docs/auth0_quickstarts.md b/docs/auth0_quickstarts.md index 9ad2f2ed4..d2359e3d4 100644 --- a/docs/auth0_quickstarts.md +++ b/docs/auth0_quickstarts.md @@ -12,4 +12,5 @@ Step-by-step guides to quickly integrate Auth0 into your application. - [auth0 quickstarts download](auth0_quickstarts_download.md) - Download a Quickstart sample app for a specific tech stack - [auth0 quickstarts list](auth0_quickstarts_list.md) - List the available Quickstarts - [auth0 quickstarts setup](auth0_quickstarts_setup.md) - Set up Auth0 for your quickstart application +- [auth0 quickstarts setup-experimental](auth0_quickstarts_setup-experimental.md) - Set up Auth0 for your quickstart application diff --git a/docs/auth0_quickstarts_download.md b/docs/auth0_quickstarts_download.md index ea55fbbd4..1f3638b22 100644 --- a/docs/auth0_quickstarts_download.md +++ b/docs/auth0_quickstarts_download.md @@ -47,5 +47,6 @@ auth0 quickstarts download [flags] - [auth0 quickstarts download](auth0_quickstarts_download.md) - Download a Quickstart sample app for a specific tech stack - [auth0 quickstarts list](auth0_quickstarts_list.md) - List the available Quickstarts - [auth0 quickstarts setup](auth0_quickstarts_setup.md) - Set up Auth0 for your quickstart application +- [auth0 quickstarts setup-experimental](auth0_quickstarts_setup-experimental.md) - Set up Auth0 for your quickstart application diff --git a/docs/auth0_quickstarts_list.md b/docs/auth0_quickstarts_list.md index 8213dbbf3..4fc23e842 100644 --- a/docs/auth0_quickstarts_list.md +++ b/docs/auth0_quickstarts_list.md @@ -49,5 +49,6 @@ auth0 quickstarts list [flags] - [auth0 quickstarts download](auth0_quickstarts_download.md) - Download a Quickstart sample app for a specific tech stack - [auth0 quickstarts list](auth0_quickstarts_list.md) - List the available Quickstarts - [auth0 quickstarts setup](auth0_quickstarts_setup.md) - Set up Auth0 for your quickstart application +- [auth0 quickstarts setup-experimental](auth0_quickstarts_setup-experimental.md) - Set up Auth0 for your quickstart application diff --git a/docs/auth0_quickstarts_setup-experimental.md b/docs/auth0_quickstarts_setup-experimental.md new file mode 100644 index 000000000..7613b4f65 --- /dev/null +++ b/docs/auth0_quickstarts_setup-experimental.md @@ -0,0 +1,57 @@ +--- +layout: default +parent: auth0 quickstarts +has_toc: false +--- +# auth0 quickstarts setup-experimental + +Creates an Auth0 application and generates a .env file with the necessary configuration. + +The command will: + 1. Check if you are authenticated (and prompt for login if needed) + 2. Create an Auth0 application based on the specified type + 3. Generate a .env file with the appropriate environment variables + +Supported types are dynamically loaded from the `QuickstartConfigs` map in the codebase. + +## Usage +``` +auth0 quickstarts setup-experimental [flags] +``` + +## Examples + +``` + auth0 quickstarts setup-experimental --type spa:react:vite + auth0 quickstarts setup-experimental --type regular:nextjs:none + auth0 quickstarts setup-experimental --type native:react-native:none +``` + + +## Flags + +``` + --name string Name of the Auth0 application + --port int Port number for the application + --type string Type of the quickstart application (e.g., spa:react:vite, regular:nextjs:none) +``` + + +## Inherited Flags + +``` + --debug Enable debug mode. + --no-color Disable colors. + --no-input Disable interactivity. + --tenant string Specific tenant to use. +``` + + +## Related Commands + +- [auth0 quickstarts download](auth0_quickstarts_download.md) - Download a Quickstart sample app for a specific tech stack +- [auth0 quickstarts list](auth0_quickstarts_list.md) - List the available Quickstarts +- [auth0 quickstarts setup](auth0_quickstarts_setup.md) - Set up Auth0 for your quickstart application +- [auth0 quickstarts setup-experimental](auth0_quickstarts_setup-experimental.md) - Set up Auth0 for your quickstart application + + diff --git a/docs/auth0_quickstarts_setup.md b/docs/auth0_quickstarts_setup.md index c7a158fb1..ceb09a84e 100644 --- a/docs/auth0_quickstarts_setup.md +++ b/docs/auth0_quickstarts_setup.md @@ -61,5 +61,6 @@ auth0 quickstarts setup [flags] - [auth0 quickstarts download](auth0_quickstarts_download.md) - Download a Quickstart sample app for a specific tech stack - [auth0 quickstarts list](auth0_quickstarts_list.md) - List the available Quickstarts - [auth0 quickstarts setup](auth0_quickstarts_setup.md) - Set up Auth0 for your quickstart application +- [auth0 quickstarts setup-experimental](auth0_quickstarts_setup-experimental.md) - Set up Auth0 for your quickstart application From dd245c2eeeac65753424a77c8182e98c71bf3229 Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Tue, 24 Mar 2026 17:19:45 +0530 Subject: [PATCH 04/12] feat: added request param substitution --- internal/auth0/quickstart.go | 35 +++++ internal/cli/quickstarts.go | 269 +++++++++++++++++++++++++++-------- 2 files changed, 242 insertions(+), 62 deletions(-) diff --git a/internal/auth0/quickstart.go b/internal/auth0/quickstart.go index cec6b4287..bb3687b42 100644 --- a/internal/auth0/quickstart.go +++ b/internal/auth0/quickstart.go @@ -14,6 +14,8 @@ import ( "github.com/auth0/go-auth0/management" "github.com/auth0/auth0-cli/internal/buildinfo" + // "github.com/auth0/auth0-cli/internal/prompt" + // "github.com/auth0/auth0-cli/internal/prompt" "github.com/auth0/auth0-cli/internal/utils" ) @@ -182,6 +184,7 @@ type RequestParams struct { Callbacks []string AllowedLogoutURLs []string WebOrigins []string + Name string } type AppConfig struct { @@ -217,6 +220,7 @@ var QuickstartConfigs = map[string]AppConfig{ Callbacks: []string{"http://localhost:4200/callback"}, AllowedLogoutURLs: []string{"http://localhost:4200"}, WebOrigins: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "spa:vue:vite": { @@ -229,6 +233,7 @@ var QuickstartConfigs = map[string]AppConfig{ Callbacks: []string{"http://localhost:5173/callback"}, AllowedLogoutURLs: []string{"http://localhost:5173"}, WebOrigins: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "spa:svelte:vite": { @@ -241,6 +246,7 @@ var QuickstartConfigs = map[string]AppConfig{ Callbacks: []string{"http://localhost:5173/callback"}, AllowedLogoutURLs: []string{"http://localhost:5173"}, WebOrigins: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "spa:vanilla-javascript:vite": { @@ -253,6 +259,7 @@ var QuickstartConfigs = map[string]AppConfig{ Callbacks: []string{"http://localhost:5173/callback"}, AllowedLogoutURLs: []string{"http://localhost:5173"}, WebOrigins: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "spa:flutter-web:none": { @@ -265,6 +272,7 @@ var QuickstartConfigs = map[string]AppConfig{ Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, WebOrigins: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, @@ -283,6 +291,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, + Name: DETECTION_SUB, }, }, "regular:nuxt:none": { @@ -297,6 +306,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, + Name: DETECTION_SUB, }, }, "regular:fastify:none": { @@ -311,6 +321,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, + Name: DETECTION_SUB, }, }, "regular:sveltekit:none": { @@ -322,6 +333,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "regular:express:none": { @@ -335,6 +347,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, + Name: DETECTION_SUB, }, }, "regular:hono:none": { @@ -349,6 +362,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, + Name: DETECTION_SUB, }, }, "regular:vanilla-python:none": { @@ -363,6 +377,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{"http://localhost:5000/callback"}, AllowedLogoutURLs: []string{"http://localhost:5000"}, + Name: DETECTION_SUB, }, }, "regular:django:none": { @@ -375,6 +390,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "regular:vanilla-go:none": { @@ -388,6 +404,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "regular:vanilla-java:maven": { @@ -400,6 +417,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "regular:java-ee:maven": { @@ -412,6 +430,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "regular:spring-boot:maven": { @@ -424,6 +443,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{"http://localhost:8000/callback"}, AllowedLogoutURLs: []string{"http://localhost:8000"}, + Name: DETECTION_SUB, }, }, "regular:aspnet-mvc:none": { @@ -436,6 +456,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "regular:aspnet-blazor:none": { @@ -447,6 +468,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "regular:aspnet-owin:none": { @@ -459,6 +481,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "regular:vanilla-php:composer": { @@ -472,6 +495,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "regular:laravel:composer": { @@ -485,6 +509,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{"http://localhost:8000/callback"}, AllowedLogoutURLs: []string{"http://localhost:8000"}, + Name: DETECTION_SUB, }, }, "regular:rails:none": { @@ -497,6 +522,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, + Name: DETECTION_SUB, }, }, @@ -512,6 +538,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "native", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "native:react-native:none": { @@ -523,6 +550,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "native", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "native:expo:none": { @@ -534,6 +562,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "native", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "native:ionic-angular:none": { @@ -545,6 +574,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "native", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "native:ionic-react:vite": { @@ -555,6 +585,7 @@ var QuickstartConfigs = map[string]AppConfig{ RequestParams: RequestParams{ AppType: "native", Callbacks: []string{DETECTION_SUB}, + Name: DETECTION_SUB, AllowedLogoutURLs: []string{DETECTION_SUB}, }, }, @@ -567,6 +598,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "native", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "native:dotnet-mobile:none": { @@ -578,6 +610,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "native", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "native:maui:none": { @@ -589,6 +622,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "native", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, "native:wpf-winforms:none": { @@ -601,6 +635,7 @@ var QuickstartConfigs = map[string]AppConfig{ AppType: "native", Callbacks: []string{DETECTION_SUB}, AllowedLogoutURLs: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, }, } diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index 9b9111dd7..3877d18bc 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -676,6 +676,7 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { Scopes string TokenLifetime string OfflineAccess bool + MetaData map[string]interface{} } cmd := &cobra.Command{ @@ -711,63 +712,87 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { } // Set default values based on the selected quickstart type - if inputs.Name == "" { - inputs.Name = "My App" - } - if inputs.Port == 0 { - inputs.Port = 3000 // Default port, can be adjusted based on the type if needed - } + // if inputs.Name == "" { + // inputs.Name = "My App" + // } + // if inputs.Port == 0 { + // inputs.Port = 3000 // Default port, can be adjusted based on the type if needed + // } - baseURL := fmt.Sprintf("http://localhost:%d", inputs.Port) + // baseURL := fmt.Sprintf("http://localhost:%d", inputs.Port) // Create the Auth0 application - cli.renderer.Infof("Creating Auth0 application '%s'...", inputs.Name) - appType := config.RequestParams.AppType - callbacks := config.RequestParams.Callbacks - logoutURLs := config.RequestParams.AllowedLogoutURLs - oidcConformant := true - algorithm := "RS256" - metadata := map[string]interface{}{ - "created_by": "quickstart-docs-manual-cli", - } - - a := &management.Client{ - Name: &inputs.Name, - AppType: &appType, - Callbacks: &callbacks, - AllowedLogoutURLs: &logoutURLs, - OIDCConformant: &oidcConformant, - JWTConfiguration: &management.ClientJWTConfiguration{ - Algorithm: &algorithm, - }, - ClientMetadata: &metadata, + // cli.renderer.Infof("Creating Auth0 application '%s'...", inputs.Name) + // appType := config.RequestParams.AppType + // callbacks := config.RequestParams.Callbacks + // logoutURLs := config.RequestParams.AllowedLogoutURLs + + // oidcConformant := true + // algorithm := "RS256" + // metadata := map[string]interface{}{ + // "created_by": "quickstart-docs-manual-cli", + // } + + // a := &management.Client{ + // Name: &inputs.Name, + // AppType: &appType, + // Callbacks: &callbacks, + // AllowedLogoutURLs: &logoutURLs, + // OIDCConformant: &oidcConformant, + // JWTConfiguration: &management.ClientJWTConfiguration{ + // Algorithm: &algorithm, + // }, + // ClientMetadata: &metadata, + // } + + clients, err := generateClients(inputs, config.RequestParams) + if err != nil { + return fmt.Errorf("failed to generate clients: %w", err) } - if err := ansi.Waiting(func() error { - return cli.api.Client.Create(ctx, a) - }); err != nil { - return fmt.Errorf("failed to create application: %w", err) - } + for _, client := range clients { + err := ansi.Waiting(func() error { + return cli.api.Client.Create(ctx, client) + }) - cli.renderer.Infof("Application created successfully with Client ID: %s", a.GetClientID()) + if err != nil { + return fmt.Errorf("failed to create application: %w", err) + } else { + if client.GetAppType() == "resource_server" { + printClientDetails(client, inputs.Port, "", true) + } else { + // cli.renderer.Infof("Application created successfully with Client ID: %s", client.GetClientID()) + + // Generate the .env file + envFileName := ".env" + var envContent strings.Builder + for key, value := range config.EnvValues { + fmt.Fprintf(&envContent, "%s=%s\n", key, value) + } + + if err := os.WriteFile(envFileName, []byte(envContent.String()), 0600); err != nil { + return fmt.Errorf("failed to write .env file: %w", err) + } + + // cli.renderer.Infof("%s file created successfully with your Auth0 configuration\n", envFileName) + + printClientDetails(client, inputs.Port, envFileName, false) + } + } - // Generate the .env file - envFileName := ".env" - var envContent strings.Builder - for key, value := range config.EnvValues { - fmt.Fprintf(&envContent, "%s=%s\n", key, value) } - if err := os.WriteFile(envFileName, []byte(envContent.String()), 0600); err != nil { - return fmt.Errorf("failed to write .env file: %w", err) - } + // if err := ansi.Waiting(func() error { + // return cli.api.Client.Create(ctx, a) + // }); err != nil { + // return fmt.Errorf("failed to create application: %w", err) + // } - cli.renderer.Infof("%s file created successfully with your Auth0 configuration\n", envFileName) - cli.renderer.Infof("Next steps: \n"+ - " 1. Install dependencies: npm install \n"+ - " 2. Start your application: npm run dev\n"+ - " 3. Open your browser at %s", baseURL) + // cli.renderer.Infof("Next steps: \n"+ + // " 1. Install dependencies: npm install \n"+ + // " 2. Start your application: npm run dev\n"+ + // " 3. Open your browser at %s", baseURL) return nil }, @@ -780,6 +805,44 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { return cmd } +func printClientDetails(client *management.Client, port int, configFileLocation string, isApi bool) { + if isApi { + // Print API-related messages + fmt.Printf("✓ An API application \"%s\" has been created and registered\n\n", *client.Name) + fmt.Println("✓ You can manage your API from here:") + fmt.Printf(" https://manage.auth0.com/dashboard/#/apis/%s/settings\n", client.GetClientID()) + } else { + // Print application-related messages + fmt.Printf("✓ An application \"%s\" has been created in the management console\n", *client.Name) + fmt.Printf(" Client ID: %s\n\n", client.GetClientID()) + + // Print management console link + fmt.Println("✓ You can manage your application from here:") + fmt.Printf(" https://manage.auth0.com/dashboard/#/applications/%s/settings\n\n", client.GetClientID()) + + // Print callback URLs + if client.Callbacks != nil && len(client.GetCallbacks()) > 0 { + fmt.Println("✓ Callback URLs registered in Auth0 Dashboard:") + for _, callback := range client.GetCallbacks() { + fmt.Printf(" %s\n", callback) + } + fmt.Println() + } + + // Print logout URLs + if client.AllowedLogoutURLs != nil && len(client.GetAllowedLogoutURLs()) > 0 { + fmt.Println("✓ Logout URLs registered:") + for _, logoutURL := range client.GetAllowedLogoutURLs() { + fmt.Printf(" %s\n", logoutURL) + } + fmt.Println() + } + + // Print config file location + fmt.Printf("✓ Config file created: %s\n\n", configFileLocation) + } +} + // Helper function to get supported quickstart types func getSupportedQuickstartTypes() []string { var types []string @@ -807,6 +870,7 @@ func getQuickstartConfigKey(inputs struct { Scopes string TokenLifetime string OfflineAccess bool + MetaData map[string]interface{} }) (string, struct { Name string App bool @@ -824,6 +888,7 @@ func getQuickstartConfigKey(inputs struct { Scopes string TokenLifetime string OfflineAccess bool + MetaData map[string]interface{} }, error) { // Prompt for target resource(s) when neither flag is provided. @@ -884,22 +949,22 @@ func getQuickstartConfigKey(inputs struct { } } - // Set default values - if inputs.Name == "" { - inputs.Name = "My App" - } - if inputs.Port == 0 { - inputs.Port = 3000 - } - if inputs.CallbackURL == "" { - inputs.CallbackURL = fmt.Sprintf("http://localhost:%d/callback", inputs.Port) - } - if inputs.LogoutURL == "" { - inputs.LogoutURL = fmt.Sprintf("http://localhost:%d/logout", inputs.Port) - } - if inputs.WebOriginURL == "" { - inputs.WebOriginURL = fmt.Sprintf("http://localhost:%d", inputs.Port) - } + // // Set default values + // if inputs.Name == "" { + // inputs.Name = "My App" + // } + // if inputs.Port == 0 { + // inputs.Port = 3000 + // } + // if inputs.CallbackURL == "" { + // inputs.CallbackURL = fmt.Sprintf("http://localhost:%d/callback", inputs.Port) + // } + // if inputs.LogoutURL == "" { + // inputs.LogoutURL = fmt.Sprintf("http://localhost:%d/logout", inputs.Port) + // } + // if inputs.WebOriginURL == "" { + // inputs.WebOriginURL = fmt.Sprintf("http://localhost:%d", inputs.Port) + // } } // Handle API creation inputs @@ -958,3 +1023,83 @@ func getQuickstartConfigKey(inputs struct { configKey := fmt.Sprintf("%s:%s:%s", inputs.Type, inputs.Framework, buildToolKey) return configKey, inputs, nil } + +func generateClients(input struct { + Name string + App bool + Type string + Framework string + BuildTool string + Port int + CallbackURL string + LogoutURL string + WebOriginURL string + API bool + Identifier string + Audience string + SigningAlg string + Scopes string + TokenLifetime string + OfflineAccess bool + MetaData map[string]interface{} +}, reqParams auth0.RequestParams) ([]*management.Client, error) { + // Prompt for the Name field if missing + + if input.Name == "" { + input.Name = "My App" + } + + q := prompt.TextInput("name", "Application Name", input.Name, "", true) + if err := prompt.AskOne(q, &input.Name); err != nil { + return nil, fmt.Errorf("failed to enter application name: %v", err) + } + + // Default values for the client + input.SigningAlg = "RS256" + if input.MetaData == nil { + input.MetaData = map[string]interface{}{ + "created_by": "quickstart-docs-manual-cli", + } + } + + oidcConformant := true + // Create the base client + baseClient := &management.Client{ + Name: &input.Name, + AppType: &reqParams.AppType, + Callbacks: &reqParams.Callbacks, + AllowedLogoutURLs: &reqParams.AllowedLogoutURLs, + OIDCConformant: &oidcConformant, + JWTConfiguration: &management.ClientJWTConfiguration{ + Algorithm: &input.SigningAlg, + }, + ClientMetadata: &input.MetaData, + } + + // Generate the list of clients + var clients []*management.Client + clients = append(clients, baseClient) + + // Add an additional client if both App and Api are true + if input.API { + resourceServerAppType := "resource_server" + q := prompt.TextInput("api_identifier", "Enter API identifier(audience)", "", "", true) + if err := prompt.AskOne(q, &input.Name); err != nil { + return nil, fmt.Errorf("failed to enter application identifier: %v", err) + } + apiClient := &management.Client{ + Name: &input.Name, + AppType: &resourceServerAppType, + Callbacks: &reqParams.Callbacks, + AllowedLogoutURLs: &reqParams.AllowedLogoutURLs, + OIDCConformant: &oidcConformant, + JWTConfiguration: &management.ClientJWTConfiguration{ + Algorithm: &input.SigningAlg, + }, + ClientMetadata: &input.MetaData, + } + clients = append(clients, apiClient) + } + + return clients, nil +} From b32aefcd4d4646d8f74c8933e02fed980a803861 Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Tue, 24 Mar 2026 19:08:44 +0530 Subject: [PATCH 05/12] feat: req param parse and sub, envvalues parse and sub --- internal/auth0/quickstart.go | 41 +++++- internal/cli/quickstarts.go | 236 ++++++++++++++++++++++++++--------- 2 files changed, 219 insertions(+), 58 deletions(-) diff --git a/internal/auth0/quickstart.go b/internal/auth0/quickstart.go index bb3687b42..ffd073fa6 100644 --- a/internal/auth0/quickstart.go +++ b/internal/auth0/quickstart.go @@ -179,6 +179,11 @@ func (q Quickstarts) Stacks() []string { const DETECTION_SUB = "DETECTION_SUB" +type FileOutputStrategy struct { + Path string + Format string +} + type RequestParams struct { AppType string Callbacks []string @@ -190,9 +195,9 @@ type RequestParams struct { type AppConfig struct { EnvValues map[string]string RequestParams RequestParams + Strategy FileOutputStrategy } -// Map key format: "type:framework:build_tool" var QuickstartConfigs = map[string]AppConfig{ // ========================================== @@ -208,7 +213,9 @@ var QuickstartConfigs = map[string]AppConfig{ Callbacks: []string{"http://localhost:5173/callback"}, AllowedLogoutURLs: []string{"http://localhost:5173"}, WebOrigins: []string{DETECTION_SUB}, + Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "spa:angular:none": { EnvValues: map[string]string{ @@ -222,6 +229,7 @@ var QuickstartConfigs = map[string]AppConfig{ WebOrigins: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "src/environments/environment.ts", Format: "ts"}, }, "spa:vue:vite": { EnvValues: map[string]string{ @@ -235,6 +243,7 @@ var QuickstartConfigs = map[string]AppConfig{ WebOrigins: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "spa:svelte:vite": { EnvValues: map[string]string{ @@ -248,6 +257,7 @@ var QuickstartConfigs = map[string]AppConfig{ WebOrigins: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "spa:vanilla-javascript:vite": { EnvValues: map[string]string{ @@ -261,6 +271,7 @@ var QuickstartConfigs = map[string]AppConfig{ WebOrigins: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "spa:flutter-web:none": { EnvValues: map[string]string{ @@ -274,6 +285,7 @@ var QuickstartConfigs = map[string]AppConfig{ WebOrigins: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "lib/auth_config.dart", Format: "dart"}, }, // ========================================== @@ -293,6 +305,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{"http://localhost:3000"}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:nuxt:none": { EnvValues: map[string]string{ @@ -308,6 +321,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{"http://localhost:3000"}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:fastify:none": { EnvValues: map[string]string{ @@ -323,6 +337,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{"http://localhost:3000"}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:sveltekit:none": { EnvValues: map[string]string{ @@ -335,6 +350,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:express:none": { EnvValues: map[string]string{ @@ -349,6 +365,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{"http://localhost:3000"}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:hono:none": { EnvValues: map[string]string{ @@ -364,6 +381,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{"http://localhost:3000"}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:vanilla-python:none": { EnvValues: map[string]string{ @@ -379,6 +397,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{"http://localhost:5000"}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:django:none": { EnvValues: map[string]string{ @@ -392,6 +411,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:vanilla-go:none": { EnvValues: map[string]string{ @@ -406,6 +426,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:vanilla-java:maven": { EnvValues: map[string]string{ @@ -419,6 +440,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "src/main/resources/application.properties", Format: "properties"}, }, "regular:java-ee:maven": { EnvValues: map[string]string{ @@ -432,6 +454,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "src/main/resources/META-INF/microprofile-config.properties", Format: "properties"}, }, "regular:spring-boot:maven": { EnvValues: map[string]string{ @@ -445,6 +468,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{"http://localhost:8000"}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "src/main/resources/application.yml", Format: "yaml"}, }, "regular:aspnet-mvc:none": { EnvValues: map[string]string{ @@ -458,6 +482,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "appsettings.json", Format: "json"}, }, "regular:aspnet-blazor:none": { EnvValues: map[string]string{ @@ -470,6 +495,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "appsettings.json", Format: "json"}, }, "regular:aspnet-owin:none": { EnvValues: map[string]string{ @@ -483,6 +509,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "Web.config", Format: "xml"}, }, "regular:vanilla-php:composer": { EnvValues: map[string]string{ @@ -497,6 +524,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:laravel:composer": { EnvValues: map[string]string{ @@ -511,6 +539,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{"http://localhost:8000"}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:rails:none": { EnvValues: map[string]string{ @@ -524,6 +553,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{"http://localhost:3000"}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, // ========================================== @@ -540,6 +570,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "lib/auth_config.dart", Format: "dart"}, }, "native:react-native:none": { EnvValues: map[string]string{ @@ -552,6 +583,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "native:expo:none": { EnvValues: map[string]string{ @@ -564,6 +596,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "native:ionic-angular:none": { EnvValues: map[string]string{ @@ -576,6 +609,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "src/environments/environment.ts", Format: "ts"}, }, "native:ionic-react:vite": { EnvValues: map[string]string{ @@ -588,6 +622,7 @@ var QuickstartConfigs = map[string]AppConfig{ Name: DETECTION_SUB, AllowedLogoutURLs: []string{DETECTION_SUB}, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "native:ionic-vue:vite": { EnvValues: map[string]string{ @@ -600,6 +635,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "native:dotnet-mobile:none": { EnvValues: map[string]string{ @@ -612,6 +648,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "appsettings.json", Format: "json"}, }, "native:maui:none": { EnvValues: map[string]string{ @@ -624,6 +661,7 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "appsettings.json", Format: "json"}, }, "native:wpf-winforms:none": { EnvValues: map[string]string{ @@ -637,5 +675,6 @@ var QuickstartConfigs = map[string]AppConfig{ AllowedLogoutURLs: []string{DETECTION_SUB}, Name: DETECTION_SUB, }, + Strategy: FileOutputStrategy{Path: "appsettings.json", Format: "json"}, }, } diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index 3877d18bc..9248a35d3 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -3,6 +3,7 @@ package cli import ( "context" _ "embed" + "encoding/json" "fmt" "os" "path" @@ -711,41 +712,6 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { return fmt.Errorf("unsupported quickstart arguments: %s. Supported types: %v", qsConfigKey, getSupportedQuickstartTypes()) } - // Set default values based on the selected quickstart type - // if inputs.Name == "" { - // inputs.Name = "My App" - // } - // if inputs.Port == 0 { - // inputs.Port = 3000 // Default port, can be adjusted based on the type if needed - // } - - // baseURL := fmt.Sprintf("http://localhost:%d", inputs.Port) - - // Create the Auth0 application - - // cli.renderer.Infof("Creating Auth0 application '%s'...", inputs.Name) - // appType := config.RequestParams.AppType - // callbacks := config.RequestParams.Callbacks - // logoutURLs := config.RequestParams.AllowedLogoutURLs - - // oidcConformant := true - // algorithm := "RS256" - // metadata := map[string]interface{}{ - // "created_by": "quickstart-docs-manual-cli", - // } - - // a := &management.Client{ - // Name: &inputs.Name, - // AppType: &appType, - // Callbacks: &callbacks, - // AllowedLogoutURLs: &logoutURLs, - // OIDCConformant: &oidcConformant, - // JWTConfiguration: &management.ClientJWTConfiguration{ - // Algorithm: &algorithm, - // }, - // ClientMetadata: &metadata, - // } - clients, err := generateClients(inputs, config.RequestParams) if err != nil { return fmt.Errorf("failed to generate clients: %w", err) @@ -763,37 +729,22 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { printClientDetails(client, inputs.Port, "", true) } else { // cli.renderer.Infof("Application created successfully with Client ID: %s", client.GetClientID()) - - // Generate the .env file - envFileName := ".env" - var envContent strings.Builder - for key, value := range config.EnvValues { - fmt.Fprintf(&envContent, "%s=%s\n", key, value) + tenant, err := cli.Config.GetTenant(cli.tenant) + if err != nil { + return fmt.Errorf("failed to get tenant: %w", err) } - - if err := os.WriteFile(envFileName, []byte(envContent.String()), 0600); err != nil { - return fmt.Errorf("failed to write .env file: %w", err) + // Generate the .env file + envFileName, _, err := GenerateAndWriteQuickstartConfig(&config.Strategy, config.EnvValues, tenant.Domain, client) + if err != nil { + return fmt.Errorf("failed to generate .env file: %w", err) } - // cli.renderer.Infof("%s file created successfully with your Auth0 configuration\n", envFileName) - printClientDetails(client, inputs.Port, envFileName, false) } } } - // if err := ansi.Waiting(func() error { - // return cli.api.Client.Create(ctx, a) - // }); err != nil { - // return fmt.Errorf("failed to create application: %w", err) - // } - - // cli.renderer.Infof("Next steps: \n"+ - // " 1. Install dependencies: npm install \n"+ - // " 2. Start your application: npm run dev\n"+ - // " 3. Open your browser at %s", baseURL) - return nil }, } @@ -1103,3 +1054,174 @@ func generateClients(input struct { return clients, nil } + +func replaceDetectionSub(envValues map[string]string, tenantDomain string, client *management.Client) map[string]string { + // Create a new map to store the updated values + updatedEnvValues := make(map[string]string) + + for key, value := range envValues { + // If the value is not DETECTION_SUB, keep it as is and continue + if value != "DETECTION_SUB" { + updatedEnvValues[key] = value + continue + } + + // Group keys by the type of replacement they require + switch key { + + // ========================================== + // Tenant Domain Replacements + // ========================================== + case "VITE_AUTH0_DOMAIN", "AUTH0_DOMAIN", "domain", "NUXT_AUTH0_DOMAIN", + "auth0.domain", "Auth0:Domain", "auth0:Domain", "auth0_domain", + "EXPO_PUBLIC_AUTH0_DOMAIN": + updatedEnvValues[key] = tenantDomain + + // Express SDK specifically requires the https:// prefix + case "ISSUER_BASE_URL": + updatedEnvValues[key] = "https://" + tenantDomain + + // Spring Boot okta issuer specifically requires https:// and a trailing slash + case "okta.oauth2.issuer": + updatedEnvValues[key] = "https://" + tenantDomain + "/" + + // ========================================== + // Client ID Replacements + // ========================================== + case "VITE_AUTH0_CLIENT_ID", "AUTH0_CLIENT_ID", "clientId", "NUXT_AUTH0_CLIENT_ID", + "CLIENT_ID", "auth0.clientId", "okta.oauth2.client-id", "Auth0:ClientId", + "auth0:ClientId", "auth0_client_id", "EXPO_PUBLIC_AUTH0_CLIENT_ID": + updatedEnvValues[key] = client.GetClientID() + + // ========================================== + // Client Secret Replacements + // ========================================== + case "AUTH0_CLIENT_SECRET", "NUXT_AUTH0_CLIENT_SECRET", "auth0.clientSecret", + "okta.oauth2.client-secret", "Auth0:ClientSecret", "auth0:ClientSecret", + "auth0_client_secret": + updatedEnvValues[key] = client.GetClientSecret() + + // ========================================== + // App Secrets / Session Cookies (Placeholders) + // ========================================== + case "AUTH0_SECRET", "NUXT_AUTH0_SESSION_SECRET", "SESSION_SECRET", + "SECRET", "AUTH0_SESSION_ENCRYPTION_KEY", "AUTH0_COOKIE_SECRET": + // Inject a dummy secret placeholder for the user to replace, + // or replace this string with a crypto/rand generator if preferred. + updatedEnvValues[key] = "a_long_random_secret_string_replace_me" + + // ========================================== + // App Base URLs and Redirect URIs + // ========================================== + case "APP_BASE_URL", "NUXT_AUTH0_APP_BASE_URL", "BASE_URL": + updatedEnvValues[key] = "http://localhost:3000" // Default backend port + + case "AUTH0_REDIRECT_URI", "AUTH0_CALLBACK_URL": + updatedEnvValues[key] = "http://localhost:3000/callback" + + // ========================================== + // Fallback + // ========================================== + default: + updatedEnvValues[key] = value + } + } + + return updatedEnvValues +} + +// FileOutputStrategy defines where and how a config file should be written +// Map the config keys to their required file output definitions based on the matrix + +// GenerateAndWriteQuickstartConfig takes the selected stack, resolves the dynamic values, +// and writes them to the appropriate file in the Current Working Directory (CWD). +// GenerateAndWriteQuickstartConfig takes the selected stack, resolves the dynamic values, +// and writes them to the appropriate file in the Current Working Directory (CWD). +// It returns the generated file name, the file path, and an error (if any). +func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envValues map[string]string, tenantDomain string, client *management.Client) (string, string, error) { + // 1. Resolve the environment variables using the previously defined function + resolvedEnv := replaceDetectionSub(envValues, tenantDomain, client) + + // 2. Determine output file path and format + if strategy == nil { + // Fallback to a standard .env in the project root if for some reason it's missing + strategy = &auth0.FileOutputStrategy{Path: ".env", Format: "dotenv"} + } + + // 3. Ensure the directory path exists (e.g., creating src/environments/ if it doesn't exist) + dir := filepath.Dir(strategy.Path) + if dir != "." { + if err := os.MkdirAll(dir, 0755); err != nil { + return "", "", fmt.Errorf("failed to create directory structure %s: %w", dir, err) + } + } + + // 4. Format the file content based on the target framework's requirement + var contentBuilder strings.Builder + + switch strategy.Format { + case "dotenv", "properties": + for key, val := range resolvedEnv { + contentBuilder.WriteString(fmt.Sprintf("%s=%s\n", key, val)) + } + + case "yaml": + for key, val := range resolvedEnv { + contentBuilder.WriteString(fmt.Sprintf("%s: %s\n", key, val)) + } + + case "ts": + contentBuilder.WriteString("export const environment = {\n") + for key, val := range resolvedEnv { + contentBuilder.WriteString(fmt.Sprintf(" %s: '%s',\n", key, val)) + } + contentBuilder.WriteString("};\n") + + case "dart": + contentBuilder.WriteString("const Map authConfig = {\n") + for key, val := range resolvedEnv { + contentBuilder.WriteString(fmt.Sprintf(" '%s': '%s',\n", key, val)) + } + contentBuilder.WriteString("};\n") + + case "json": + // C# appsettings.json expects nested JSON: {"Auth0": {"Domain": "...", "ClientId": "..."}} + auth0Section := make(map[string]string) + for key, val := range resolvedEnv { + // Strip the "Auth0:" prefix used in the map to create clean JSON keys + cleanKey := strings.TrimPrefix(key, "Auth0:") + auth0Section[cleanKey] = val + } + + jsonBody := map[string]interface{}{ + "Auth0": auth0Section, + } + + bytes, err := json.MarshalIndent(jsonBody, "", " ") + if err != nil { + return "", "", fmt.Errorf("failed to marshal JSON for %s: %w", strategy.Path, err) + } + contentBuilder.Write(bytes) + + case "xml": + // ASP.NET OWIN Web.config + contentBuilder.WriteString("\n") + contentBuilder.WriteString("\n") + contentBuilder.WriteString(" \n") + for key, val := range resolvedEnv { + contentBuilder.WriteString(fmt.Sprintf(" \n", key, val)) + } + contentBuilder.WriteString(" \n") + contentBuilder.WriteString("\n") + } + + // 5. Write the generated content to disk + if err := os.WriteFile(strategy.Path, []byte(contentBuilder.String()), 0600); err != nil { + return "", "", fmt.Errorf("failed to write config file %s: %w", strategy.Path, err) + } + + // 6. Extract the base file name from the path and return both + fileName := filepath.Base(strategy.Path) + + return fileName, strategy.Path, nil +} From 99c6c02b74bcd43885bd94d367b7d3f699c6739c Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Tue, 24 Mar 2026 19:18:58 +0530 Subject: [PATCH 06/12] chore: lint fixes --- internal/auth0/quickstart.go | 350 +++++++++++++++++------------------ internal/cli/quickstarts.go | 14 +- 2 files changed, 182 insertions(+), 182 deletions(-) diff --git a/internal/auth0/quickstart.go b/internal/auth0/quickstart.go index ffd073fa6..aabed3ccf 100644 --- a/internal/auth0/quickstart.go +++ b/internal/auth0/quickstart.go @@ -177,7 +177,7 @@ func (q Quickstarts) Stacks() []string { return stacks } -const DETECTION_SUB = "DETECTION_SUB" +const DetectionSub = "DETECTION_SUB" type FileOutputStrategy struct { Path string @@ -205,85 +205,85 @@ var QuickstartConfigs = map[string]AppConfig{ // ========================================== "spa:react:vite": { EnvValues: map[string]string{ - "VITE_AUTH0_DOMAIN": DETECTION_SUB, - "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + "VITE_AUTH0_DOMAIN": DetectionSub, + "VITE_AUTH0_CLIENT_ID": DetectionSub, }, RequestParams: RequestParams{ AppType: "spa", Callbacks: []string{"http://localhost:5173/callback"}, AllowedLogoutURLs: []string{"http://localhost:5173"}, - WebOrigins: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + WebOrigins: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "spa:angular:none": { EnvValues: map[string]string{ - "domain": DETECTION_SUB, - "clientId": DETECTION_SUB, + "domain": DetectionSub, + "clientId": DetectionSub, }, RequestParams: RequestParams{ AppType: "spa", Callbacks: []string{"http://localhost:4200/callback"}, AllowedLogoutURLs: []string{"http://localhost:4200"}, - WebOrigins: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + WebOrigins: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "src/environments/environment.ts", Format: "ts"}, }, "spa:vue:vite": { EnvValues: map[string]string{ - "VITE_AUTH0_DOMAIN": DETECTION_SUB, - "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + "VITE_AUTH0_DOMAIN": DetectionSub, + "VITE_AUTH0_CLIENT_ID": DetectionSub, }, RequestParams: RequestParams{ AppType: "spa", Callbacks: []string{"http://localhost:5173/callback"}, AllowedLogoutURLs: []string{"http://localhost:5173"}, - WebOrigins: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + WebOrigins: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "spa:svelte:vite": { EnvValues: map[string]string{ - "VITE_AUTH0_DOMAIN": DETECTION_SUB, - "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + "VITE_AUTH0_DOMAIN": DetectionSub, + "VITE_AUTH0_CLIENT_ID": DetectionSub, }, RequestParams: RequestParams{ AppType: "spa", Callbacks: []string{"http://localhost:5173/callback"}, AllowedLogoutURLs: []string{"http://localhost:5173"}, - WebOrigins: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + WebOrigins: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "spa:vanilla-javascript:vite": { EnvValues: map[string]string{ - "VITE_AUTH0_DOMAIN": DETECTION_SUB, - "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + "VITE_AUTH0_DOMAIN": DetectionSub, + "VITE_AUTH0_CLIENT_ID": DetectionSub, }, RequestParams: RequestParams{ AppType: "spa", Callbacks: []string{"http://localhost:5173/callback"}, AllowedLogoutURLs: []string{"http://localhost:5173"}, - WebOrigins: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + WebOrigins: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "spa:flutter-web:none": { EnvValues: map[string]string{ - "domain": DETECTION_SUB, - "clientId": DETECTION_SUB, + "domain": DetectionSub, + "clientId": DetectionSub, }, RequestParams: RequestParams{ AppType: "spa", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - WebOrigins: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + WebOrigins: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "lib/auth_config.dart", Format: "dart"}, }, @@ -293,265 +293,265 @@ var QuickstartConfigs = map[string]AppConfig{ // ========================================== "regular:nextjs:none": { EnvValues: map[string]string{ - "AUTH0_DOMAIN": DETECTION_SUB, - "AUTH0_CLIENT_ID": DETECTION_SUB, - "AUTH0_CLIENT_SECRET": DETECTION_SUB, - "AUTH0_SECRET": DETECTION_SUB, - "APP_BASE_URL": DETECTION_SUB, + "AUTH0_DOMAIN": DetectionSub, + "AUTH0_CLIENT_ID": DetectionSub, + "AUTH0_CLIENT_SECRET": DetectionSub, + "AUTH0_SECRET": DetectionSub, + "APP_BASE_URL": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, - Name: DETECTION_SUB, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:nuxt:none": { EnvValues: map[string]string{ - "NUXT_AUTH0_DOMAIN": DETECTION_SUB, - "NUXT_AUTH0_CLIENT_ID": DETECTION_SUB, - "NUXT_AUTH0_CLIENT_SECRET": DETECTION_SUB, - "NUXT_AUTH0_SESSION_SECRET": DETECTION_SUB, - "NUXT_AUTH0_APP_BASE_URL": DETECTION_SUB, + "NUXT_AUTH0_DOMAIN": DetectionSub, + "NUXT_AUTH0_CLIENT_ID": DetectionSub, + "NUXT_AUTH0_CLIENT_SECRET": DetectionSub, + "NUXT_AUTH0_SESSION_SECRET": DetectionSub, + "NUXT_AUTH0_APP_BASE_URL": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, - Name: DETECTION_SUB, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:fastify:none": { EnvValues: map[string]string{ - "AUTH0_DOMAIN": DETECTION_SUB, - "AUTH0_CLIENT_ID": DETECTION_SUB, - "AUTH0_CLIENT_SECRET": DETECTION_SUB, - "SESSION_SECRET": DETECTION_SUB, - "APP_BASE_URL": DETECTION_SUB, + "AUTH0_DOMAIN": DetectionSub, + "AUTH0_CLIENT_ID": DetectionSub, + "AUTH0_CLIENT_SECRET": DetectionSub, + "SESSION_SECRET": DetectionSub, + "APP_BASE_URL": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, - Name: DETECTION_SUB, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:sveltekit:none": { EnvValues: map[string]string{ - "VITE_AUTH0_DOMAIN": DETECTION_SUB, - "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + "VITE_AUTH0_DOMAIN": DetectionSub, + "VITE_AUTH0_CLIENT_ID": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:express:none": { EnvValues: map[string]string{ - "ISSUER_BASE_URL": DETECTION_SUB, - "CLIENT_ID": DETECTION_SUB, - "SECRET": DETECTION_SUB, - "BASE_URL": DETECTION_SUB, + "ISSUER_BASE_URL": DetectionSub, + "CLIENT_ID": DetectionSub, + "SECRET": DetectionSub, + "BASE_URL": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, - Name: DETECTION_SUB, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:hono:none": { EnvValues: map[string]string{ - "AUTH0_DOMAIN": DETECTION_SUB, - "AUTH0_CLIENT_ID": DETECTION_SUB, - "AUTH0_CLIENT_SECRET": DETECTION_SUB, - "AUTH0_SESSION_ENCRYPTION_KEY": DETECTION_SUB, - "BASE_URL": DETECTION_SUB, + "AUTH0_DOMAIN": DetectionSub, + "AUTH0_CLIENT_ID": DetectionSub, + "AUTH0_CLIENT_SECRET": DetectionSub, + "AUTH0_SESSION_ENCRYPTION_KEY": DetectionSub, + "BASE_URL": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, - Name: DETECTION_SUB, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:vanilla-python:none": { EnvValues: map[string]string{ - "AUTH0_DOMAIN": DETECTION_SUB, - "AUTH0_CLIENT_ID": DETECTION_SUB, - "AUTH0_CLIENT_SECRET": DETECTION_SUB, - "AUTH0_SECRET": DETECTION_SUB, - "AUTH0_REDIRECT_URI": DETECTION_SUB, + "AUTH0_DOMAIN": DetectionSub, + "AUTH0_CLIENT_ID": DetectionSub, + "AUTH0_CLIENT_SECRET": DetectionSub, + "AUTH0_SECRET": DetectionSub, + "AUTH0_REDIRECT_URI": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", Callbacks: []string{"http://localhost:5000/callback"}, AllowedLogoutURLs: []string{"http://localhost:5000"}, - Name: DETECTION_SUB, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:django:none": { EnvValues: map[string]string{ - "AUTH0_DOMAIN": DETECTION_SUB, - "AUTH0_CLIENT_ID": DETECTION_SUB, - "AUTH0_CLIENT_SECRET": DETECTION_SUB, + "AUTH0_DOMAIN": DetectionSub, + "AUTH0_CLIENT_ID": DetectionSub, + "AUTH0_CLIENT_SECRET": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:vanilla-go:none": { EnvValues: map[string]string{ - "AUTH0_DOMAIN": DETECTION_SUB, - "AUTH0_CLIENT_ID": DETECTION_SUB, - "AUTH0_CLIENT_SECRET": DETECTION_SUB, - "AUTH0_CALLBACK_URL": DETECTION_SUB, + "AUTH0_DOMAIN": DetectionSub, + "AUTH0_CLIENT_ID": DetectionSub, + "AUTH0_CLIENT_SECRET": DetectionSub, + "AUTH0_CALLBACK_URL": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:vanilla-java:maven": { EnvValues: map[string]string{ - "auth0.domain": DETECTION_SUB, - "auth0.clientId": DETECTION_SUB, - "auth0.clientSecret": DETECTION_SUB, + "auth0.domain": DetectionSub, + "auth0.clientId": DetectionSub, + "auth0.clientSecret": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "src/main/resources/application.properties", Format: "properties"}, }, "regular:java-ee:maven": { EnvValues: map[string]string{ - "auth0.domain": DETECTION_SUB, - "auth0.clientId": DETECTION_SUB, - "auth0.clientSecret": DETECTION_SUB, + "auth0.domain": DetectionSub, + "auth0.clientId": DetectionSub, + "auth0.clientSecret": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "src/main/resources/META-INF/microprofile-config.properties", Format: "properties"}, }, "regular:spring-boot:maven": { EnvValues: map[string]string{ - "okta.oauth2.issuer": DETECTION_SUB, - "okta.oauth2.client-id": DETECTION_SUB, - "okta.oauth2.client-secret": DETECTION_SUB, + "okta.oauth2.issuer": DetectionSub, + "okta.oauth2.client-id": DetectionSub, + "okta.oauth2.client-secret": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", Callbacks: []string{"http://localhost:8000/callback"}, AllowedLogoutURLs: []string{"http://localhost:8000"}, - Name: DETECTION_SUB, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "src/main/resources/application.yml", Format: "yaml"}, }, "regular:aspnet-mvc:none": { EnvValues: map[string]string{ - "Auth0:Domain": DETECTION_SUB, - "Auth0:ClientId": DETECTION_SUB, - "Auth0:ClientSecret": DETECTION_SUB, + "Auth0:Domain": DetectionSub, + "Auth0:ClientId": DetectionSub, + "Auth0:ClientSecret": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "appsettings.json", Format: "json"}, }, "regular:aspnet-blazor:none": { EnvValues: map[string]string{ - "Auth0:Domain": DETECTION_SUB, - "Auth0:ClientId": DETECTION_SUB, + "Auth0:Domain": DetectionSub, + "Auth0:ClientId": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "appsettings.json", Format: "json"}, }, "regular:aspnet-owin:none": { EnvValues: map[string]string{ - "auth0:Domain": DETECTION_SUB, - "auth0:ClientId": DETECTION_SUB, - "auth0:ClientSecret": DETECTION_SUB, + "auth0:Domain": DetectionSub, + "auth0:ClientId": DetectionSub, + "auth0:ClientSecret": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "Web.config", Format: "xml"}, }, "regular:vanilla-php:composer": { EnvValues: map[string]string{ - "AUTH0_DOMAIN": DETECTION_SUB, - "AUTH0_CLIENT_ID": DETECTION_SUB, - "AUTH0_CLIENT_SECRET": DETECTION_SUB, - "AUTH0_COOKIE_SECRET": DETECTION_SUB, + "AUTH0_DOMAIN": DetectionSub, + "AUTH0_CLIENT_ID": DetectionSub, + "AUTH0_CLIENT_SECRET": DetectionSub, + "AUTH0_COOKIE_SECRET": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:laravel:composer": { EnvValues: map[string]string{ - "AUTH0_DOMAIN": DETECTION_SUB, - "AUTH0_CLIENT_ID": DETECTION_SUB, - "AUTH0_CLIENT_SECRET": DETECTION_SUB, - "AUTH0_COOKIE_SECRET": DETECTION_SUB, + "AUTH0_DOMAIN": DetectionSub, + "AUTH0_CLIENT_ID": DetectionSub, + "AUTH0_CLIENT_SECRET": DetectionSub, + "AUTH0_COOKIE_SECRET": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", Callbacks: []string{"http://localhost:8000/callback"}, AllowedLogoutURLs: []string{"http://localhost:8000"}, - Name: DETECTION_SUB, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "regular:rails:none": { EnvValues: map[string]string{ - "auth0_domain": DETECTION_SUB, - "auth0_client_id": DETECTION_SUB, - "auth0_client_secret": DETECTION_SUB, + "auth0_domain": DetectionSub, + "auth0_client_id": DetectionSub, + "auth0_client_secret": DetectionSub, }, RequestParams: RequestParams{ AppType: "regular_web", Callbacks: []string{"http://localhost:3000/callback"}, AllowedLogoutURLs: []string{"http://localhost:3000"}, - Name: DETECTION_SUB, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, @@ -561,119 +561,119 @@ var QuickstartConfigs = map[string]AppConfig{ // ========================================== "native:flutter:none": { EnvValues: map[string]string{ - "domain": DETECTION_SUB, - "clientId": DETECTION_SUB, + "domain": DetectionSub, + "clientId": DetectionSub, }, RequestParams: RequestParams{ AppType: "native", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "lib/auth_config.dart", Format: "dart"}, }, "native:react-native:none": { EnvValues: map[string]string{ - "AUTH0_DOMAIN": DETECTION_SUB, - "AUTH0_CLIENT_ID": DETECTION_SUB, + "AUTH0_DOMAIN": DetectionSub, + "AUTH0_CLIENT_ID": DetectionSub, }, RequestParams: RequestParams{ AppType: "native", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "native:expo:none": { EnvValues: map[string]string{ - "EXPO_PUBLIC_AUTH0_DOMAIN": DETECTION_SUB, - "EXPO_PUBLIC_AUTH0_CLIENT_ID": DETECTION_SUB, + "EXPO_PUBLIC_AUTH0_DOMAIN": DetectionSub, + "EXPO_PUBLIC_AUTH0_CLIENT_ID": DetectionSub, }, RequestParams: RequestParams{ AppType: "native", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "native:ionic-angular:none": { EnvValues: map[string]string{ - "domain": DETECTION_SUB, - "clientId": DETECTION_SUB, + "domain": DetectionSub, + "clientId": DetectionSub, }, RequestParams: RequestParams{ AppType: "native", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "src/environments/environment.ts", Format: "ts"}, }, "native:ionic-react:vite": { EnvValues: map[string]string{ - "VITE_AUTH0_DOMAIN": DETECTION_SUB, - "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + "VITE_AUTH0_DOMAIN": DetectionSub, + "VITE_AUTH0_CLIENT_ID": DetectionSub, }, RequestParams: RequestParams{ AppType: "native", - Callbacks: []string{DETECTION_SUB}, - Name: DETECTION_SUB, - AllowedLogoutURLs: []string{DETECTION_SUB}, + Callbacks: []string{DetectionSub}, + Name: DetectionSub, + AllowedLogoutURLs: []string{DetectionSub}, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "native:ionic-vue:vite": { EnvValues: map[string]string{ - "VITE_AUTH0_DOMAIN": DETECTION_SUB, - "VITE_AUTH0_CLIENT_ID": DETECTION_SUB, + "VITE_AUTH0_DOMAIN": DetectionSub, + "VITE_AUTH0_CLIENT_ID": DetectionSub, }, RequestParams: RequestParams{ AppType: "native", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, "native:dotnet-mobile:none": { EnvValues: map[string]string{ - "Auth0:Domain": DETECTION_SUB, - "Auth0:ClientId": DETECTION_SUB, + "Auth0:Domain": DetectionSub, + "Auth0:ClientId": DetectionSub, }, RequestParams: RequestParams{ AppType: "native", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "appsettings.json", Format: "json"}, }, "native:maui:none": { EnvValues: map[string]string{ - "Auth0:Domain": DETECTION_SUB, - "Auth0:ClientId": DETECTION_SUB, + "Auth0:Domain": DetectionSub, + "Auth0:ClientId": DetectionSub, }, RequestParams: RequestParams{ AppType: "native", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "appsettings.json", Format: "json"}, }, "native:wpf-winforms:none": { EnvValues: map[string]string{ - "Auth0:Domain": DETECTION_SUB, - "Auth0:ClientId": DETECTION_SUB, - "Auth0:ClientSecret": DETECTION_SUB, + "Auth0:Domain": DetectionSub, + "Auth0:ClientId": DetectionSub, + "Auth0:ClientSecret": DetectionSub, }, RequestParams: RequestParams{ AppType: "native", - Callbacks: []string{DETECTION_SUB}, - AllowedLogoutURLs: []string{DETECTION_SUB}, - Name: DETECTION_SUB, + Callbacks: []string{DetectionSub}, + AllowedLogoutURLs: []string{DetectionSub}, + Name: DetectionSub, }, Strategy: FileOutputStrategy{Path: "appsettings.json", Format: "json"}, }, diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index 9248a35d3..f56bc0a86 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -756,24 +756,24 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { return cmd } -func printClientDetails(client *management.Client, port int, configFileLocation string, isApi bool) { - if isApi { +func printClientDetails(client *management.Client, port int, configFileLocation string, isAPI bool) { + if isAPI { // Print API-related messages - fmt.Printf("✓ An API application \"%s\" has been created and registered\n\n", *client.Name) - fmt.Println("✓ You can manage your API from here:") + fmt.Printf(" An API application \"%s\" has been created and registered\n\n", *client.Name) + fmt.Println(" You can manage your API from here:") fmt.Printf(" https://manage.auth0.com/dashboard/#/apis/%s/settings\n", client.GetClientID()) } else { // Print application-related messages - fmt.Printf("✓ An application \"%s\" has been created in the management console\n", *client.Name) + fmt.Printf(" An application \"%s\" has been created in the management console\n", *client.Name) fmt.Printf(" Client ID: %s\n\n", client.GetClientID()) // Print management console link - fmt.Println("✓ You can manage your application from here:") + fmt.Println(" You can manage your application from here:") fmt.Printf(" https://manage.auth0.com/dashboard/#/applications/%s/settings\n\n", client.GetClientID()) // Print callback URLs if client.Callbacks != nil && len(client.GetCallbacks()) > 0 { - fmt.Println("✓ Callback URLs registered in Auth0 Dashboard:") + fmt.Println(" Callback URLs registered in Auth0 Dashboard:") for _, callback := range client.GetCallbacks() { fmt.Printf(" %s\n", callback) } From 4cefe3d728463ebc4d607a71a6000131434091cd Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Tue, 24 Mar 2026 19:30:36 +0530 Subject: [PATCH 07/12] chore: lint fixes --- internal/auth0/quickstart.go | 7 ++----- internal/cli/quickstarts.go | 37 +++++++++++++++--------------------- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/internal/auth0/quickstart.go b/internal/auth0/quickstart.go index aabed3ccf..7b8a73a76 100644 --- a/internal/auth0/quickstart.go +++ b/internal/auth0/quickstart.go @@ -14,9 +14,6 @@ import ( "github.com/auth0/go-auth0/management" "github.com/auth0/auth0-cli/internal/buildinfo" - // "github.com/auth0/auth0-cli/internal/prompt" - // "github.com/auth0/auth0-cli/internal/prompt" - "github.com/auth0/auth0-cli/internal/utils" ) @@ -202,7 +199,7 @@ var QuickstartConfigs = map[string]AppConfig{ // ========================================== // Single Page Applications (SPA) - // ========================================== + // ==========================================. "spa:react:vite": { EnvValues: map[string]string{ "VITE_AUTH0_DOMAIN": DetectionSub, @@ -290,7 +287,7 @@ var QuickstartConfigs = map[string]AppConfig{ // ========================================== // Regular Web Applications - // ========================================== + // ==========================================. "regular:nextjs:none": { EnvValues: map[string]string{ "AUTH0_DOMAIN": DetectionSub, diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index f56bc0a86..6b25fa630 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -12,12 +12,11 @@ import ( "strconv" "strings" - "github.com/auth0/go-auth0/management" - "github.com/spf13/cobra" - "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/auth0" "github.com/auth0/auth0-cli/internal/prompt" + "github.com/auth0/go-auth0/management" + "github.com/spf13/cobra" ) // QuickStart app types and defaults. @@ -724,27 +723,23 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { if err != nil { return fmt.Errorf("failed to create application: %w", err) + } + + if client.GetAppType() == "resource_server" { + printClientDetails(client, inputs.Port, "", true) } else { - if client.GetAppType() == "resource_server" { - printClientDetails(client, inputs.Port, "", true) - } else { - // cli.renderer.Infof("Application created successfully with Client ID: %s", client.GetClientID()) - tenant, err := cli.Config.GetTenant(cli.tenant) - if err != nil { - return fmt.Errorf("failed to get tenant: %w", err) - } - // Generate the .env file - envFileName, _, err := GenerateAndWriteQuickstartConfig(&config.Strategy, config.EnvValues, tenant.Domain, client) - if err != nil { - return fmt.Errorf("failed to generate .env file: %w", err) - } - // cli.renderer.Infof("%s file created successfully with your Auth0 configuration\n", envFileName) - printClientDetails(client, inputs.Port, envFileName, false) + tenant, err := cli.Config.GetTenant(cli.tenant) + if err != nil { + return fmt.Errorf("failed to get tenant: %w", err) + } + // Generate the .env file + envFileName, _, err := GenerateAndWriteQuickstartConfig(&config.Strategy, config.EnvValues, tenant.Domain, client) + if err != nil { + return fmt.Errorf("failed to generate .env file: %w", err) } + printClientDetails(client, inputs.Port, envFileName, false) } - } - return nil }, } @@ -841,7 +836,6 @@ func getQuickstartConfigKey(inputs struct { OfflineAccess bool MetaData map[string]interface{} }, error) { - // Prompt for target resource(s) when neither flag is provided. if !inputs.App && !inputs.API { var selections []string @@ -875,7 +869,6 @@ func getQuickstartConfigKey(inputs struct { // Prompt for --type if not provided if inputs.Type == "" { types := []string{"spa", "regular", "native", "m2m"} - // name, message, help, options, defaultValue, required q := prompt.SelectInput("type", "Select the application type", "", types, "m2m", true) if err := prompt.AskOne(q, &inputs.Type); err != nil { return "", inputs, fmt.Errorf("failed to select application type: %v", err) From c4a756535a575284f75a7b28e56dacdcf0e10346 Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Tue, 24 Mar 2026 19:39:39 +0530 Subject: [PATCH 08/12] chore: lint fix --- internal/auth0/quickstart.go | 4 +- internal/cli/quickstarts.go | 132 +++++++++++++---------------------- 2 files changed, 52 insertions(+), 84 deletions(-) diff --git a/internal/auth0/quickstart.go b/internal/auth0/quickstart.go index 7b8a73a76..d86b54e01 100644 --- a/internal/auth0/quickstart.go +++ b/internal/auth0/quickstart.go @@ -553,9 +553,9 @@ var QuickstartConfigs = map[string]AppConfig{ Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, - // ========================================== + // ==========================================. // Native / Mobile Applications - // ========================================== + // ==========================================. "native:flutter:none": { EnvValues: map[string]string{ "domain": DetectionSub, diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index 6b25fa630..8fed02b27 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -705,7 +705,7 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { return fmt.Errorf("failed to get quickstart configuration: %w", err) } - // Validate the input type against QuickstartConfigs + // Validate the input type against QuickstartConfigs. config, exists := auth0.QuickstartConfigs[qsConfigKey] if !exists { return fmt.Errorf("unsupported quickstart arguments: %s. Supported types: %v", qsConfigKey, getSupportedQuickstartTypes()) @@ -732,7 +732,7 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { if err != nil { return fmt.Errorf("failed to get tenant: %w", err) } - // Generate the .env file + // Generate the .env file. envFileName, _, err := GenerateAndWriteQuickstartConfig(&config.Strategy, config.EnvValues, tenant.Domain, client) if err != nil { return fmt.Errorf("failed to generate .env file: %w", err) @@ -753,20 +753,20 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { func printClientDetails(client *management.Client, port int, configFileLocation string, isAPI bool) { if isAPI { - // Print API-related messages + // Print API-related messages. fmt.Printf(" An API application \"%s\" has been created and registered\n\n", *client.Name) fmt.Println(" You can manage your API from here:") fmt.Printf(" https://manage.auth0.com/dashboard/#/apis/%s/settings\n", client.GetClientID()) } else { - // Print application-related messages + // Print application-related messages. fmt.Printf(" An application \"%s\" has been created in the management console\n", *client.Name) fmt.Printf(" Client ID: %s\n\n", client.GetClientID()) - // Print management console link + // Print management console link. fmt.Println(" You can manage your application from here:") fmt.Printf(" https://manage.auth0.com/dashboard/#/applications/%s/settings\n\n", client.GetClientID()) - // Print callback URLs + // Print callback URLs. if client.Callbacks != nil && len(client.GetCallbacks()) > 0 { fmt.Println(" Callback URLs registered in Auth0 Dashboard:") for _, callback := range client.GetCallbacks() { @@ -775,7 +775,7 @@ func printClientDetails(client *management.Client, port int, configFileLocation fmt.Println() } - // Print logout URLs + // Print logout URLs. if client.AllowedLogoutURLs != nil && len(client.GetAllowedLogoutURLs()) > 0 { fmt.Println("✓ Logout URLs registered:") for _, logoutURL := range client.GetAllowedLogoutURLs() { @@ -784,12 +784,12 @@ func printClientDetails(client *management.Client, port int, configFileLocation fmt.Println() } - // Print config file location + // Print config file location. fmt.Printf("✓ Config file created: %s\n\n", configFileLocation) } } -// Helper function to get supported quickstart types +// Helper function to get supported quickstart types. func getSupportedQuickstartTypes() []string { var types []string for key := range auth0.QuickstartConfigs { @@ -798,7 +798,7 @@ func getSupportedQuickstartTypes() []string { return types } -// For cleaner readability, you might consider extracting this anonymous struct into a named type (e.g., type SetupInputs struct {...}) +// For cleaner readability, you might consider extracting this anonymous struct into a named type (e.g., type SetupInputs struct {...}). func getQuickstartConfigKey(inputs struct { Name string App bool @@ -864,9 +864,9 @@ func getQuickstartConfigKey(inputs struct { } } - // Handle application creation inputs + // Handle application creation inputs. if inputs.App { - // Prompt for --type if not provided + // Prompt for --type if not provided. if inputs.Type == "" { types := []string{"spa", "regular", "native", "m2m"} q := prompt.SelectInput("type", "Select the application type", "", types, "m2m", true) @@ -875,7 +875,7 @@ func getQuickstartConfigKey(inputs struct { } } - // Prompt for --framework if not provided + // Prompt for --framework if not provided. if inputs.Framework == "" { frameworks := []string{"react", "angular", "vue", "svelte", "nextjs", "nuxt", "flutter", "express", "django", "spring-boot", "none"} q := prompt.SelectInput("framework", "Select the framework", "", frameworks, "none", true) @@ -884,7 +884,7 @@ func getQuickstartConfigKey(inputs struct { } } - // Prompt for --build-tool if not provided (optional) + // Prompt for --build-tool if not provided (optional). if inputs.BuildTool == "" { buildTools := []string{"vite", "webpack", "cra", "none"} q := prompt.SelectInput("build-tool", "Select the build tool (optional)", "", buildTools, "none", false) @@ -892,42 +892,25 @@ func getQuickstartConfigKey(inputs struct { return "", inputs, fmt.Errorf("failed to select build tool: %v", err) } } - - // // Set default values - // if inputs.Name == "" { - // inputs.Name = "My App" - // } - // if inputs.Port == 0 { - // inputs.Port = 3000 - // } - // if inputs.CallbackURL == "" { - // inputs.CallbackURL = fmt.Sprintf("http://localhost:%d/callback", inputs.Port) - // } - // if inputs.LogoutURL == "" { - // inputs.LogoutURL = fmt.Sprintf("http://localhost:%d/logout", inputs.Port) - // } - // if inputs.WebOriginURL == "" { - // inputs.WebOriginURL = fmt.Sprintf("http://localhost:%d", inputs.Port) - // } } - // Handle API creation inputs + // Handle API creation inputs. if inputs.API { - // Prompt for --identifier or --audience if not provided + // Prompt for --identifier or --audience if not provided. if inputs.Identifier == "" && inputs.Audience == "" { - // name, message, help, defaultValue, required + // Name, message, help, defaultValue, required. q := prompt.TextInput("identifier", "Enter the API identifier (or audience)", "", "", true) if err := prompt.AskOne(q, &inputs.Identifier); err != nil { return "", inputs, fmt.Errorf("failed to enter API identifier: %v", err) } } - // Use --audience as an alias for --identifier if provided + // Use --audience as an alias for --identifier if provided. if inputs.Identifier == "" { inputs.Identifier = inputs.Audience } - // Prompt for --signing-alg if not provided + // Prompt for --signing-alg if not provided. if inputs.SigningAlg == "" { signingAlgs := []string{"RS256", "PS256", "HS256"} q := prompt.SelectInput("signing-alg", "Select the signing algorithm", "", signingAlgs, "RS256", true) @@ -936,7 +919,7 @@ func getQuickstartConfigKey(inputs struct { } } - // Prompt for --scopes if not provided + // Prompt for --scopes if not provided. if inputs.Scopes == "" { q := prompt.TextInput("scopes", "Enter the scopes (comma-separated)", "", "", false) if err := prompt.AskOne(q, &inputs.Scopes); err != nil { @@ -944,7 +927,7 @@ func getQuickstartConfigKey(inputs struct { } } - // Prompt for --token-lifetime if not provided + // Prompt for --token-lifetime if not provided. if inputs.TokenLifetime == "" { q := prompt.TextInput("token-lifetime", "Enter the token lifetime (in seconds)", "", "86400", true) if err := prompt.AskOne(q, &inputs.TokenLifetime); err != nil { @@ -957,8 +940,7 @@ func getQuickstartConfigKey(inputs struct { } } - // Construct the key to query QuickstartConfigs - // Fallback to "none" if build tool wasn't asked/selected to match the config map keys + // Fallback to "none" if build tool wasn't asked/selected to match the config map keys. buildToolKey := inputs.BuildTool if buildToolKey == "" { buildToolKey = "none" @@ -987,7 +969,7 @@ func generateClients(input struct { OfflineAccess bool MetaData map[string]interface{} }, reqParams auth0.RequestParams) ([]*management.Client, error) { - // Prompt for the Name field if missing + // Prompt for the Name field if missing. if input.Name == "" { input.Name = "My App" @@ -998,7 +980,7 @@ func generateClients(input struct { return nil, fmt.Errorf("failed to enter application name: %v", err) } - // Default values for the client + // Default values for the client. input.SigningAlg = "RS256" if input.MetaData == nil { input.MetaData = map[string]interface{}{ @@ -1007,7 +989,7 @@ func generateClients(input struct { } oidcConformant := true - // Create the base client + // Create the base client. baseClient := &management.Client{ Name: &input.Name, AppType: &reqParams.AppType, @@ -1020,11 +1002,11 @@ func generateClients(input struct { ClientMetadata: &input.MetaData, } - // Generate the list of clients + // Generate the list of clients. var clients []*management.Client clients = append(clients, baseClient) - // Add an additional client if both App and Api are true + // Add an additional client if both App and Api are true. if input.API { resourceServerAppType := "resource_server" q := prompt.TextInput("api_identifier", "Enter API identifier(audience)", "", "", true) @@ -1049,72 +1031,59 @@ func generateClients(input struct { } func replaceDetectionSub(envValues map[string]string, tenantDomain string, client *management.Client) map[string]string { - // Create a new map to store the updated values + // Create a new map to store the updated values. updatedEnvValues := make(map[string]string) for key, value := range envValues { - // If the value is not DETECTION_SUB, keep it as is and continue + // If the value is not DETECTION_SUB, keep it as is and continue. if value != "DETECTION_SUB" { updatedEnvValues[key] = value continue } - // Group keys by the type of replacement they require + // Group keys by the type of replacement they require. switch key { - - // ========================================== - // Tenant Domain Replacements - // ========================================== + // ==========================================. case "VITE_AUTH0_DOMAIN", "AUTH0_DOMAIN", "domain", "NUXT_AUTH0_DOMAIN", "auth0.domain", "Auth0:Domain", "auth0:Domain", "auth0_domain", "EXPO_PUBLIC_AUTH0_DOMAIN": updatedEnvValues[key] = tenantDomain - // Express SDK specifically requires the https:// prefix + // Express SDK specifically requires the https:// prefix. case "ISSUER_BASE_URL": updatedEnvValues[key] = "https://" + tenantDomain - // Spring Boot okta issuer specifically requires https:// and a trailing slash + // Spring Boot okta issuer specifically requires https:// and a trailing slash. case "okta.oauth2.issuer": updatedEnvValues[key] = "https://" + tenantDomain + "/" - // ========================================== - // Client ID Replacements - // ========================================== + // ==========================================. case "VITE_AUTH0_CLIENT_ID", "AUTH0_CLIENT_ID", "clientId", "NUXT_AUTH0_CLIENT_ID", "CLIENT_ID", "auth0.clientId", "okta.oauth2.client-id", "Auth0:ClientId", "auth0:ClientId", "auth0_client_id", "EXPO_PUBLIC_AUTH0_CLIENT_ID": updatedEnvValues[key] = client.GetClientID() - // ========================================== - // Client Secret Replacements - // ========================================== + // ==========================================. case "AUTH0_CLIENT_SECRET", "NUXT_AUTH0_CLIENT_SECRET", "auth0.clientSecret", "okta.oauth2.client-secret", "Auth0:ClientSecret", "auth0:ClientSecret", "auth0_client_secret": updatedEnvValues[key] = client.GetClientSecret() - // ========================================== - // App Secrets / Session Cookies (Placeholders) - // ========================================== + // ==========================================. case "AUTH0_SECRET", "NUXT_AUTH0_SESSION_SECRET", "SESSION_SECRET", "SECRET", "AUTH0_SESSION_ENCRYPTION_KEY", "AUTH0_COOKIE_SECRET": // Inject a dummy secret placeholder for the user to replace, // or replace this string with a crypto/rand generator if preferred. updatedEnvValues[key] = "a_long_random_secret_string_replace_me" - // ========================================== - // App Base URLs and Redirect URIs - // ========================================== + // ==========================================. case "APP_BASE_URL", "NUXT_AUTH0_APP_BASE_URL", "BASE_URL": - updatedEnvValues[key] = "http://localhost:3000" // Default backend port + updatedEnvValues[key] = "http://localhost:3000" updatedEnvValues[key] = "http://localhost:3000" // Default backend port. case "AUTH0_REDIRECT_URI", "AUTH0_CALLBACK_URL": updatedEnvValues[key] = "http://localhost:3000/callback" - // ========================================== - // Fallback - // ========================================== + // ==========================================. default: updatedEnvValues[key] = value } @@ -1123,8 +1092,7 @@ func replaceDetectionSub(envValues map[string]string, tenantDomain string, clien return updatedEnvValues } -// FileOutputStrategy defines where and how a config file should be written -// Map the config keys to their required file output definitions based on the matrix +// Map the config keys to their required file output definitions based on the matrix. // GenerateAndWriteQuickstartConfig takes the selected stack, resolves the dynamic values, // and writes them to the appropriate file in the Current Working Directory (CWD). @@ -1132,16 +1100,16 @@ func replaceDetectionSub(envValues map[string]string, tenantDomain string, clien // and writes them to the appropriate file in the Current Working Directory (CWD). // It returns the generated file name, the file path, and an error (if any). func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envValues map[string]string, tenantDomain string, client *management.Client) (string, string, error) { - // 1. Resolve the environment variables using the previously defined function + // 1. Resolve the environment variables using the previously defined function. resolvedEnv := replaceDetectionSub(envValues, tenantDomain, client) - // 2. Determine output file path and format + // 2. Determine output file path and format. if strategy == nil { - // Fallback to a standard .env in the project root if for some reason it's missing + // Fallback to a standard .env in the project root if for some reason it's missing. strategy = &auth0.FileOutputStrategy{Path: ".env", Format: "dotenv"} } - // 3. Ensure the directory path exists (e.g., creating src/environments/ if it doesn't exist) + // 3. Ensure the directory path exists (e.g., creating src/environments/ if it doesn't exist). dir := filepath.Dir(strategy.Path) if dir != "." { if err := os.MkdirAll(dir, 0755); err != nil { @@ -1149,7 +1117,7 @@ func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envVal } } - // 4. Format the file content based on the target framework's requirement + // 4. Format the file content based on the target framework's requirement. var contentBuilder strings.Builder switch strategy.Format { @@ -1178,10 +1146,10 @@ func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envVal contentBuilder.WriteString("};\n") case "json": - // C# appsettings.json expects nested JSON: {"Auth0": {"Domain": "...", "ClientId": "..."}} + // C# appsettings.json expects nested JSON: {"Auth0": {"Domain": "...", "ClientId": "..."}}. auth0Section := make(map[string]string) for key, val := range resolvedEnv { - // Strip the "Auth0:" prefix used in the map to create clean JSON keys + // Strip the "Auth0:" prefix used in the map to create clean JSON keys. cleanKey := strings.TrimPrefix(key, "Auth0:") auth0Section[cleanKey] = val } @@ -1197,7 +1165,7 @@ func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envVal contentBuilder.Write(bytes) case "xml": - // ASP.NET OWIN Web.config + // ASP.NET OWIN Web.config. contentBuilder.WriteString("\n") contentBuilder.WriteString("\n") contentBuilder.WriteString(" \n") @@ -1208,12 +1176,12 @@ func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envVal contentBuilder.WriteString("\n") } - // 5. Write the generated content to disk + // 5. Write the generated content to disk. if err := os.WriteFile(strategy.Path, []byte(contentBuilder.String()), 0600); err != nil { return "", "", fmt.Errorf("failed to write config file %s: %w", strategy.Path, err) } - // 6. Extract the base file name from the path and return both + // 6. Extract the base file name from the path and return both. fileName := filepath.Base(strategy.Path) return fileName, strategy.Path, nil From 00ff9335e602c61e773b74f082576c5f15a9d1d0 Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Tue, 24 Mar 2026 19:45:53 +0530 Subject: [PATCH 09/12] fix: lint build fix --- internal/cli/quickstarts.go | 86 ++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index 8fed02b27..e58eca648 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -753,20 +753,20 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { func printClientDetails(client *management.Client, port int, configFileLocation string, isAPI bool) { if isAPI { - // Print API-related messages. + // Print API-related messages. fmt.Printf(" An API application \"%s\" has been created and registered\n\n", *client.Name) fmt.Println(" You can manage your API from here:") fmt.Printf(" https://manage.auth0.com/dashboard/#/apis/%s/settings\n", client.GetClientID()) } else { - // Print application-related messages. + // Print application-related messages. fmt.Printf(" An application \"%s\" has been created in the management console\n", *client.Name) fmt.Printf(" Client ID: %s\n\n", client.GetClientID()) - // Print management console link. + // Print management console link. fmt.Println(" You can manage your application from here:") fmt.Printf(" https://manage.auth0.com/dashboard/#/applications/%s/settings\n\n", client.GetClientID()) - // Print callback URLs. + // Print callback URLs. if client.Callbacks != nil && len(client.GetCallbacks()) > 0 { fmt.Println(" Callback URLs registered in Auth0 Dashboard:") for _, callback := range client.GetCallbacks() { @@ -775,7 +775,7 @@ func printClientDetails(client *management.Client, port int, configFileLocation fmt.Println() } - // Print logout URLs. + // Print logout URLs. if client.AllowedLogoutURLs != nil && len(client.GetAllowedLogoutURLs()) > 0 { fmt.Println("✓ Logout URLs registered:") for _, logoutURL := range client.GetAllowedLogoutURLs() { @@ -784,7 +784,7 @@ func printClientDetails(client *management.Client, port int, configFileLocation fmt.Println() } - // Print config file location. + // Print config file location. fmt.Printf("✓ Config file created: %s\n\n", configFileLocation) } } @@ -864,9 +864,9 @@ func getQuickstartConfigKey(inputs struct { } } - // Handle application creation inputs. + // Handle application creation inputs. if inputs.App { - // Prompt for --type if not provided. + // Prompt for --type if not provided. if inputs.Type == "" { types := []string{"spa", "regular", "native", "m2m"} q := prompt.SelectInput("type", "Select the application type", "", types, "m2m", true) @@ -875,7 +875,7 @@ func getQuickstartConfigKey(inputs struct { } } - // Prompt for --framework if not provided. + // Prompt for --framework if not provided. if inputs.Framework == "" { frameworks := []string{"react", "angular", "vue", "svelte", "nextjs", "nuxt", "flutter", "express", "django", "spring-boot", "none"} q := prompt.SelectInput("framework", "Select the framework", "", frameworks, "none", true) @@ -884,7 +884,7 @@ func getQuickstartConfigKey(inputs struct { } } - // Prompt for --build-tool if not provided (optional). + // Prompt for --build-tool if not provided (optional). if inputs.BuildTool == "" { buildTools := []string{"vite", "webpack", "cra", "none"} q := prompt.SelectInput("build-tool", "Select the build tool (optional)", "", buildTools, "none", false) @@ -894,9 +894,9 @@ func getQuickstartConfigKey(inputs struct { } } - // Handle API creation inputs. + // Handle API creation inputs. if inputs.API { - // Prompt for --identifier or --audience if not provided. + // Prompt for --identifier or --audience if not provided. if inputs.Identifier == "" && inputs.Audience == "" { // Name, message, help, defaultValue, required. q := prompt.TextInput("identifier", "Enter the API identifier (or audience)", "", "", true) @@ -905,12 +905,12 @@ func getQuickstartConfigKey(inputs struct { } } - // Use --audience as an alias for --identifier if provided. + // Use --audience as an alias for --identifier if provided. if inputs.Identifier == "" { inputs.Identifier = inputs.Audience } - // Prompt for --signing-alg if not provided. + // Prompt for --signing-alg if not provided. if inputs.SigningAlg == "" { signingAlgs := []string{"RS256", "PS256", "HS256"} q := prompt.SelectInput("signing-alg", "Select the signing algorithm", "", signingAlgs, "RS256", true) @@ -919,7 +919,7 @@ func getQuickstartConfigKey(inputs struct { } } - // Prompt for --scopes if not provided. + // Prompt for --scopes if not provided. if inputs.Scopes == "" { q := prompt.TextInput("scopes", "Enter the scopes (comma-separated)", "", "", false) if err := prompt.AskOne(q, &inputs.Scopes); err != nil { @@ -927,7 +927,7 @@ func getQuickstartConfigKey(inputs struct { } } - // Prompt for --token-lifetime if not provided. + // Prompt for --token-lifetime if not provided. if inputs.TokenLifetime == "" { q := prompt.TextInput("token-lifetime", "Enter the token lifetime (in seconds)", "", "86400", true) if err := prompt.AskOne(q, &inputs.TokenLifetime); err != nil { @@ -940,7 +940,7 @@ func getQuickstartConfigKey(inputs struct { } } - // Fallback to "none" if build tool wasn't asked/selected to match the config map keys. + // Fallback to "none" if build tool wasn't asked/selected to match the config map keys. buildToolKey := inputs.BuildTool if buildToolKey == "" { buildToolKey = "none" @@ -969,7 +969,7 @@ func generateClients(input struct { OfflineAccess bool MetaData map[string]interface{} }, reqParams auth0.RequestParams) ([]*management.Client, error) { - // Prompt for the Name field if missing. + // Prompt for the Name field if missing. if input.Name == "" { input.Name = "My App" @@ -980,7 +980,7 @@ func generateClients(input struct { return nil, fmt.Errorf("failed to enter application name: %v", err) } - // Default values for the client. + // Default values for the client. input.SigningAlg = "RS256" if input.MetaData == nil { input.MetaData = map[string]interface{}{ @@ -989,7 +989,7 @@ func generateClients(input struct { } oidcConformant := true - // Create the base client. + // Create the base client. baseClient := &management.Client{ Name: &input.Name, AppType: &reqParams.AppType, @@ -1002,11 +1002,11 @@ func generateClients(input struct { ClientMetadata: &input.MetaData, } - // Generate the list of clients. + // Generate the list of clients. var clients []*management.Client clients = append(clients, baseClient) - // Add an additional client if both App and Api are true. + // Add an additional client if both App and Api are true. if input.API { resourceServerAppType := "resource_server" q := prompt.TextInput("api_identifier", "Enter API identifier(audience)", "", "", true) @@ -1031,17 +1031,17 @@ func generateClients(input struct { } func replaceDetectionSub(envValues map[string]string, tenantDomain string, client *management.Client) map[string]string { - // Create a new map to store the updated values. + // Create a new map to store the updated values. updatedEnvValues := make(map[string]string) for key, value := range envValues { - // If the value is not DETECTION_SUB, keep it as is and continue. + // If the value is not DETECTION_SUB, keep it as is and continue. if value != "DETECTION_SUB" { updatedEnvValues[key] = value continue } - // Group keys by the type of replacement they require. + // Group keys by the type of replacement they require. switch key { // ==========================================. case "VITE_AUTH0_DOMAIN", "AUTH0_DOMAIN", "domain", "NUXT_AUTH0_DOMAIN", @@ -1049,41 +1049,41 @@ func replaceDetectionSub(envValues map[string]string, tenantDomain string, clien "EXPO_PUBLIC_AUTH0_DOMAIN": updatedEnvValues[key] = tenantDomain - // Express SDK specifically requires the https:// prefix. + // Express SDK specifically requires the https:// prefix. case "ISSUER_BASE_URL": updatedEnvValues[key] = "https://" + tenantDomain - // Spring Boot okta issuer specifically requires https:// and a trailing slash. + // Spring Boot okta issuer specifically requires https:// and a trailing slash. case "okta.oauth2.issuer": updatedEnvValues[key] = "https://" + tenantDomain + "/" - // ==========================================. + // ==========================================. case "VITE_AUTH0_CLIENT_ID", "AUTH0_CLIENT_ID", "clientId", "NUXT_AUTH0_CLIENT_ID", "CLIENT_ID", "auth0.clientId", "okta.oauth2.client-id", "Auth0:ClientId", "auth0:ClientId", "auth0_client_id", "EXPO_PUBLIC_AUTH0_CLIENT_ID": updatedEnvValues[key] = client.GetClientID() - // ==========================================. + // ==========================================. case "AUTH0_CLIENT_SECRET", "NUXT_AUTH0_CLIENT_SECRET", "auth0.clientSecret", "okta.oauth2.client-secret", "Auth0:ClientSecret", "auth0:ClientSecret", "auth0_client_secret": updatedEnvValues[key] = client.GetClientSecret() - // ==========================================. + // ==========================================. case "AUTH0_SECRET", "NUXT_AUTH0_SESSION_SECRET", "SESSION_SECRET", "SECRET", "AUTH0_SESSION_ENCRYPTION_KEY", "AUTH0_COOKIE_SECRET": // Inject a dummy secret placeholder for the user to replace, // or replace this string with a crypto/rand generator if preferred. updatedEnvValues[key] = "a_long_random_secret_string_replace_me" - // ==========================================. + // ==========================================. case "APP_BASE_URL", "NUXT_AUTH0_APP_BASE_URL", "BASE_URL": - updatedEnvValues[key] = "http://localhost:3000" updatedEnvValues[key] = "http://localhost:3000" // Default backend port. + updatedEnvValues[key] = "http://localhost:3000" case "AUTH0_REDIRECT_URI", "AUTH0_CALLBACK_URL": updatedEnvValues[key] = "http://localhost:3000/callback" - // ==========================================. + // ==========================================. default: updatedEnvValues[key] = value } @@ -1100,16 +1100,16 @@ func replaceDetectionSub(envValues map[string]string, tenantDomain string, clien // and writes them to the appropriate file in the Current Working Directory (CWD). // It returns the generated file name, the file path, and an error (if any). func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envValues map[string]string, tenantDomain string, client *management.Client) (string, string, error) { - // 1. Resolve the environment variables using the previously defined function. + // 1. Resolve the environment variables using the previously defined function. resolvedEnv := replaceDetectionSub(envValues, tenantDomain, client) - // 2. Determine output file path and format. + // 2. Determine output file path and format. if strategy == nil { - // Fallback to a standard .env in the project root if for some reason it's missing. + // Fallback to a standard .env in the project root if for some reason it's missing. strategy = &auth0.FileOutputStrategy{Path: ".env", Format: "dotenv"} } - // 3. Ensure the directory path exists (e.g., creating src/environments/ if it doesn't exist). + // 3. Ensure the directory path exists (e.g., creating src/environments/ if it doesn't exist). dir := filepath.Dir(strategy.Path) if dir != "." { if err := os.MkdirAll(dir, 0755); err != nil { @@ -1117,7 +1117,7 @@ func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envVal } } - // 4. Format the file content based on the target framework's requirement. + // 4. Format the file content based on the target framework's requirement. var contentBuilder strings.Builder switch strategy.Format { @@ -1146,10 +1146,10 @@ func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envVal contentBuilder.WriteString("};\n") case "json": - // C# appsettings.json expects nested JSON: {"Auth0": {"Domain": "...", "ClientId": "..."}}. + // C# appsettings.json expects nested JSON: {"Auth0": {"Domain": "...", "ClientId": "..."}}. auth0Section := make(map[string]string) for key, val := range resolvedEnv { - // Strip the "Auth0:" prefix used in the map to create clean JSON keys. + // Strip the "Auth0:" prefix used in the map to create clean JSON keys. cleanKey := strings.TrimPrefix(key, "Auth0:") auth0Section[cleanKey] = val } @@ -1165,7 +1165,7 @@ func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envVal contentBuilder.Write(bytes) case "xml": - // ASP.NET OWIN Web.config. + // ASP.NET OWIN Web.config. contentBuilder.WriteString("\n") contentBuilder.WriteString("\n") contentBuilder.WriteString(" \n") @@ -1176,12 +1176,12 @@ func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envVal contentBuilder.WriteString("\n") } - // 5. Write the generated content to disk. + // 5. Write the generated content to disk. if err := os.WriteFile(strategy.Path, []byte(contentBuilder.String()), 0600); err != nil { return "", "", fmt.Errorf("failed to write config file %s: %w", strategy.Path, err) } - // 6. Extract the base file name from the path and return both. + // 6. Extract the base file name from the path and return both. fileName := filepath.Base(strategy.Path) return fileName, strategy.Path, nil From a00466469c04dcdea46f2d8fd39d718e3d03b834 Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Tue, 24 Mar 2026 19:50:05 +0530 Subject: [PATCH 10/12] chore: lint fix --- internal/cli/quickstarts.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index e58eca648..d7b22e7a8 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -12,11 +12,12 @@ import ( "strconv" "strings" + "github.com/auth0/go-auth0/management" + "github.com/spf13/cobra" + "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/auth0" "github.com/auth0/auth0-cli/internal/prompt" - "github.com/auth0/go-auth0/management" - "github.com/spf13/cobra" ) // QuickStart app types and defaults. From 252605ea78bbbc59bf0605774217b9e650e0e23d Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Mon, 30 Mar 2026 21:54:20 +0530 Subject: [PATCH 11/12] fix: added review fixes, added none key fix for API creation --- internal/auth0/quickstart.go | 8 +- internal/cli/quickstarts.go | 479 ++++++++++++++++++----------------- 2 files changed, 253 insertions(+), 234 deletions(-) diff --git a/internal/auth0/quickstart.go b/internal/auth0/quickstart.go index d86b54e01..949109a24 100644 --- a/internal/auth0/quickstart.go +++ b/internal/auth0/quickstart.go @@ -199,7 +199,7 @@ var QuickstartConfigs = map[string]AppConfig{ // ========================================== // Single Page Applications (SPA) - // ==========================================. + // ========================================== "spa:react:vite": { EnvValues: map[string]string{ "VITE_AUTH0_DOMAIN": DetectionSub, @@ -287,7 +287,7 @@ var QuickstartConfigs = map[string]AppConfig{ // ========================================== // Regular Web Applications - // ==========================================. + // ========================================== "regular:nextjs:none": { EnvValues: map[string]string{ "AUTH0_DOMAIN": DetectionSub, @@ -553,9 +553,9 @@ var QuickstartConfigs = map[string]AppConfig{ Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, - // ==========================================. + // ========================================== // Native / Mobile Applications - // ==========================================. + // ========================================== "native:flutter:none": { EnvValues: map[string]string{ "domain": DetectionSub, diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index d7b22e7a8..f94236094 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -9,11 +9,13 @@ import ( "path" "path/filepath" "regexp" + "sort" "strconv" "strings" "github.com/auth0/go-auth0/management" "github.com/spf13/cobra" + "gopkg.in/yaml.v2" "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/auth0" @@ -440,6 +442,27 @@ var ( } ) +// SetupInputs holds the user-provided inputs for the setup-experimental command. +type SetupInputs struct { + Name string + App bool + Type string + Framework string + BuildTool string + Port int + CallbackURL string + LogoutURL string + WebOriginURL string + API bool + Identifier string + Audience string + SigningAlg string + Scopes string + TokenLifetime string + OfflineAccess bool + MetaData map[string]interface{} +} + func setupQuickstartCmd(cli *cli) *cobra.Command { var inputs struct { Type string @@ -660,25 +683,7 @@ func setupQuickstartCmd(cli *cli) *cobra.Command { } func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { - var inputs struct { - Name string - App bool - Type string - Framework string - BuildTool string - Port int - CallbackURL string - LogoutURL string - WebOriginURL string - API bool - Identifier string - Audience string - SigningAlg string - Scopes string - TokenLifetime string - OfflineAccess bool - MetaData map[string]interface{} - } + var inputs SetupInputs cmd := &cobra.Command{ Use: "setup-experimental", @@ -702,45 +707,67 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { qsConfigKey, updatedInputs, err := getQuickstartConfigKey(inputs) if err != nil { - inputs = updatedInputs return fmt.Errorf("failed to get quickstart configuration: %w", err) } + inputs = updatedInputs + + // Create the Auth0 application client if requested. + if inputs.App { + // Validate the config key only when an app is being created. + config, exists := auth0.QuickstartConfigs[qsConfigKey] + if !exists { + return fmt.Errorf("unsupported quickstart arguments: %s. Supported types: %v", qsConfigKey, getSupportedQuickstartTypes()) + } - // Validate the input type against QuickstartConfigs. - config, exists := auth0.QuickstartConfigs[qsConfigKey] - if !exists { - return fmt.Errorf("unsupported quickstart arguments: %s. Supported types: %v", qsConfigKey, getSupportedQuickstartTypes()) - } - - clients, err := generateClients(inputs, config.RequestParams) - if err != nil { - return fmt.Errorf("failed to generate clients: %w", err) - } + client, err := generateClient(inputs, config.RequestParams) + if err != nil { + return fmt.Errorf("failed to generate client: %w", err) + } - for _, client := range clients { - err := ansi.Waiting(func() error { + if err := ansi.Waiting(func() error { return cli.api.Client.Create(ctx, client) - }) + }); err != nil { + return fmt.Errorf("failed to create application: %w", err) + } + tenant, err := cli.Config.GetTenant(cli.tenant) if err != nil { - return fmt.Errorf("failed to create application: %w", err) + return fmt.Errorf("failed to get tenant: %w", err) + } + + envFileName, _, err := GenerateAndWriteQuickstartConfig(&config.Strategy, config.EnvValues, tenant.Domain, client, inputs.Port) + if err != nil { + return fmt.Errorf("failed to generate config file: %w", err) + } + printClientDetails(cli, client, inputs.Port, envFileName) + } + + // Create the Auth0 API resource server if requested. + if inputs.API { + tokenLifetime, _ := strconv.Atoi(inputs.TokenLifetime) + if tokenLifetime <= 0 { + tokenLifetime = 86400 + } + + rs := &management.ResourceServer{ + Name: &inputs.Identifier, + Identifier: &inputs.Identifier, + SigningAlgorithm: &inputs.SigningAlg, + TokenLifetime: &tokenLifetime, + } + if inputs.OfflineAccess { + allow := true + rs.AllowOfflineAccess = &allow } - if client.GetAppType() == "resource_server" { - printClientDetails(client, inputs.Port, "", true) - } else { - tenant, err := cli.Config.GetTenant(cli.tenant) - if err != nil { - return fmt.Errorf("failed to get tenant: %w", err) - } - // Generate the .env file. - envFileName, _, err := GenerateAndWriteQuickstartConfig(&config.Strategy, config.EnvValues, tenant.Domain, client) - if err != nil { - return fmt.Errorf("failed to generate .env file: %w", err) - } - printClientDetails(client, inputs.Port, envFileName, false) + if err := ansi.Waiting(func() error { + return cli.api.ResourceServer.Create(ctx, rs) + }); err != nil { + return fmt.Errorf("failed to create API: %w", err) } + printAPIDetails(cli, rs) } + return nil }, } @@ -752,91 +779,52 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { return cmd } -func printClientDetails(client *management.Client, port int, configFileLocation string, isAPI bool) { - if isAPI { - // Print API-related messages. - fmt.Printf(" An API application \"%s\" has been created and registered\n\n", *client.Name) - fmt.Println(" You can manage your API from here:") - fmt.Printf(" https://manage.auth0.com/dashboard/#/apis/%s/settings\n", client.GetClientID()) - } else { - // Print application-related messages. - fmt.Printf(" An application \"%s\" has been created in the management console\n", *client.Name) - fmt.Printf(" Client ID: %s\n\n", client.GetClientID()) - - // Print management console link. - fmt.Println(" You can manage your application from here:") - fmt.Printf(" https://manage.auth0.com/dashboard/#/applications/%s/settings\n\n", client.GetClientID()) - - // Print callback URLs. - if client.Callbacks != nil && len(client.GetCallbacks()) > 0 { - fmt.Println(" Callback URLs registered in Auth0 Dashboard:") - for _, callback := range client.GetCallbacks() { - fmt.Printf(" %s\n", callback) - } - fmt.Println() - } - - // Print logout URLs. - if client.AllowedLogoutURLs != nil && len(client.GetAllowedLogoutURLs()) > 0 { - fmt.Println("✓ Logout URLs registered:") - for _, logoutURL := range client.GetAllowedLogoutURLs() { - fmt.Printf(" %s\n", logoutURL) - } - fmt.Println() - } +func printClientDetails(cli *cli, client *management.Client, port int, configFileLocation string) { + cli.renderer.Infof("Application %q created (Client ID: %s)", client.GetName(), client.GetClientID()) + cli.renderer.Infof("Manage: https://manage.auth0.com/dashboard/#/applications/%s/settings", client.GetClientID()) - // Print config file location. - fmt.Printf("✓ Config file created: %s\n\n", configFileLocation) + if client.Callbacks != nil && len(client.GetCallbacks()) > 0 { + cli.renderer.Infof("Callback URLs: %s", strings.Join(client.GetCallbacks(), ", ")) + } + if client.AllowedLogoutURLs != nil && len(client.GetAllowedLogoutURLs()) > 0 { + cli.renderer.Infof("Logout URLs: %s", strings.Join(client.GetAllowedLogoutURLs(), ", ")) } + cli.renderer.Infof("Config file created: %s", configFileLocation) } +func printAPIDetails(cli *cli, rs *management.ResourceServer) { + cli.renderer.Infof("API %q registered (Identifier: %s)", rs.GetName(), rs.GetIdentifier()) + cli.renderer.Infof("Manage: https://manage.auth0.com/dashboard/#/apis/%s/settings", rs.GetID()) +} // Helper function to get supported quickstart types. func getSupportedQuickstartTypes() []string { var types []string for key := range auth0.QuickstartConfigs { types = append(types, key) } + sort.Strings(types) return types } -// For cleaner readability, you might consider extracting this anonymous struct into a named type (e.g., type SetupInputs struct {...}). -func getQuickstartConfigKey(inputs struct { - Name string - App bool - Type string - Framework string - BuildTool string - Port int - CallbackURL string - LogoutURL string - WebOriginURL string - API bool - Identifier string - Audience string - SigningAlg string - Scopes string - TokenLifetime string - OfflineAccess bool - MetaData map[string]interface{} -}) (string, struct { - Name string - App bool - Type string - Framework string - BuildTool string - Port int - CallbackURL string - LogoutURL string - WebOriginURL string - API bool - Identifier string - Audience string - SigningAlg string - Scopes string - TokenLifetime string - OfflineAccess bool - MetaData map[string]interface{} -}, error) { +// frameworksForType returns the list of unique frameworks available for the given app type. +func frameworksForType(qsType string) []string { + seen := make(map[string]bool) + var frameworks []string + for key := range auth0.QuickstartConfigs { + parts := strings.SplitN(key, ":", 3) + if len(parts) >= 2 && parts[0] == qsType { + fw := parts[1] + if !seen[fw] { + seen[fw] = true + frameworks = append(frameworks, fw) + } + } + } + sort.Strings(frameworks) + return frameworks +} + +func getQuickstartConfigKey(inputs SetupInputs) (string, SetupInputs, error) { // Prompt for target resource(s) when neither flag is provided. if !inputs.App && !inputs.API { var selections []string @@ -869,17 +857,20 @@ func getQuickstartConfigKey(inputs struct { if inputs.App { // Prompt for --type if not provided. if inputs.Type == "" { - types := []string{"spa", "regular", "native", "m2m"} - q := prompt.SelectInput("type", "Select the application type", "", types, "m2m", true) + types := []string{"spa", "regular", "native"} + q := prompt.SelectInput("type", "Select the application type", "", types, "spa", true) if err := prompt.AskOne(q, &inputs.Type); err != nil { return "", inputs, fmt.Errorf("failed to select application type: %v", err) } } - // Prompt for --framework if not provided. + // Prompt for --framework filtered to the selected type. if inputs.Framework == "" { - frameworks := []string{"react", "angular", "vue", "svelte", "nextjs", "nuxt", "flutter", "express", "django", "spring-boot", "none"} - q := prompt.SelectInput("framework", "Select the framework", "", frameworks, "none", true) + frameworks := frameworksForType(inputs.Type) + if len(frameworks) == 0 { + return "", inputs, fmt.Errorf("no frameworks available for type %q", inputs.Type) + } + q := prompt.SelectInput("framework", "Select the framework", "", frameworks, frameworks[0], true) if err := prompt.AskOne(q, &inputs.Framework); err != nil { return "", inputs, fmt.Errorf("failed to select framework: %v", err) } @@ -899,7 +890,6 @@ func getQuickstartConfigKey(inputs struct { if inputs.API { // Prompt for --identifier or --audience if not provided. if inputs.Identifier == "" && inputs.Audience == "" { - // Name, message, help, defaultValue, required. q := prompt.TextInput("identifier", "Enter the API identifier (or audience)", "", "", true) if err := prompt.AskOne(q, &inputs.Identifier); err != nil { return "", inputs, fmt.Errorf("failed to enter API identifier: %v", err) @@ -935,10 +925,11 @@ func getQuickstartConfigKey(inputs struct { return "", inputs, fmt.Errorf("failed to enter token lifetime: %v", err) } } + } - if !inputs.OfflineAccess { - inputs.OfflineAccess = false - } + // Config key is only meaningful when an app is being created. + if !inputs.App { + return "", inputs, nil } // Fallback to "none" if build tool wasn't asked/selected to match the config map keys. @@ -951,166 +942,196 @@ func getQuickstartConfigKey(inputs struct { return configKey, inputs, nil } -func generateClients(input struct { - Name string - App bool - Type string - Framework string - BuildTool string - Port int - CallbackURL string - LogoutURL string - WebOriginURL string - API bool - Identifier string - Audience string - SigningAlg string - Scopes string - TokenLifetime string - OfflineAccess bool - MetaData map[string]interface{} -}, reqParams auth0.RequestParams) ([]*management.Client, error) { - // Prompt for the Name field if missing. - +func generateClient(input SetupInputs, reqParams auth0.RequestParams) (*management.Client, error) { + // Prompt for name only if not already provided via flag. if input.Name == "" { input.Name = "My App" + q := prompt.TextInput("name", "Application Name", input.Name, "", true) + if err := prompt.AskOne(q, &input.Name); err != nil { + return nil, fmt.Errorf("failed to enter application name: %v", err) + } } - q := prompt.TextInput("name", "Application Name", input.Name, "", true) - if err := prompt.AskOne(q, &input.Name); err != nil { - return nil, fmt.Errorf("failed to enter application name: %v", err) - } - - // Default values for the client. - input.SigningAlg = "RS256" if input.MetaData == nil { input.MetaData = map[string]interface{}{ "created_by": "quickstart-docs-manual-cli", } } + resolved := resolveRequestParams(reqParams, input.Name, input.Port) + + algorithm := "RS256" oidcConformant := true - // Create the base client. - baseClient := &management.Client{ + client := &management.Client{ Name: &input.Name, - AppType: &reqParams.AppType, - Callbacks: &reqParams.Callbacks, - AllowedLogoutURLs: &reqParams.AllowedLogoutURLs, + AppType: &resolved.AppType, + Callbacks: &resolved.Callbacks, + AllowedLogoutURLs: &resolved.AllowedLogoutURLs, OIDCConformant: &oidcConformant, JWTConfiguration: &management.ClientJWTConfiguration{ - Algorithm: &input.SigningAlg, + Algorithm: &algorithm, }, ClientMetadata: &input.MetaData, } - // Generate the list of clients. - var clients []*management.Client - clients = append(clients, baseClient) + if len(resolved.WebOrigins) > 0 { + client.WebOrigins = &resolved.WebOrigins + } - // Add an additional client if both App and Api are true. - if input.API { - resourceServerAppType := "resource_server" - q := prompt.TextInput("api_identifier", "Enter API identifier(audience)", "", "", true) - if err := prompt.AskOne(q, &input.Name); err != nil { - return nil, fmt.Errorf("failed to enter application identifier: %v", err) + return client, nil +} + +// resolveRequestParams replaces DetectionSub placeholders in RequestParams fields +// with actual values derived from the user inputs. +func resolveRequestParams(reqParams auth0.RequestParams, name string, port int) auth0.RequestParams { + if port == 0 { + port = 3000 + } + baseURL := fmt.Sprintf("http://localhost:%d", port) + + callbacks := make([]string, len(reqParams.Callbacks)) + copy(callbacks, reqParams.Callbacks) + logoutURLs := make([]string, len(reqParams.AllowedLogoutURLs)) + copy(logoutURLs, reqParams.AllowedLogoutURLs) + webOrigins := make([]string, len(reqParams.WebOrigins)) + copy(webOrigins, reqParams.WebOrigins) + + resolvedName := reqParams.Name + if resolvedName == auth0.DetectionSub { + resolvedName = name + } + for i, cb := range callbacks { + if cb == auth0.DetectionSub { + callbacks[i] = baseURL + "/callback" } - apiClient := &management.Client{ - Name: &input.Name, - AppType: &resourceServerAppType, - Callbacks: &reqParams.Callbacks, - AllowedLogoutURLs: &reqParams.AllowedLogoutURLs, - OIDCConformant: &oidcConformant, - JWTConfiguration: &management.ClientJWTConfiguration{ - Algorithm: &input.SigningAlg, - }, - ClientMetadata: &input.MetaData, + } + for i, u := range logoutURLs { + if u == auth0.DetectionSub { + logoutURLs[i] = baseURL + } + } + for i, u := range webOrigins { + if u == auth0.DetectionSub { + webOrigins[i] = baseURL } - clients = append(clients, apiClient) } - return clients, nil + return auth0.RequestParams{ + AppType: reqParams.AppType, + Callbacks: callbacks, + AllowedLogoutURLs: logoutURLs, + WebOrigins: webOrigins, + Name: resolvedName, + } } -func replaceDetectionSub(envValues map[string]string, tenantDomain string, client *management.Client) map[string]string { - // Create a new map to store the updated values. +func replaceDetectionSub(envValues map[string]string, tenantDomain string, client *management.Client, port int) (map[string]string, error) { + if port == 0 { + port = 3000 + } + baseURL := fmt.Sprintf("http://localhost:%d", port) + updatedEnvValues := make(map[string]string) for key, value := range envValues { - // If the value is not DETECTION_SUB, keep it as is and continue. - if value != "DETECTION_SUB" { + if value != auth0.DetectionSub { updatedEnvValues[key] = value continue } - // Group keys by the type of replacement they require. switch key { - // ==========================================. case "VITE_AUTH0_DOMAIN", "AUTH0_DOMAIN", "domain", "NUXT_AUTH0_DOMAIN", "auth0.domain", "Auth0:Domain", "auth0:Domain", "auth0_domain", "EXPO_PUBLIC_AUTH0_DOMAIN": updatedEnvValues[key] = tenantDomain - // Express SDK specifically requires the https:// prefix. + // Express SDK specifically requires the https:// prefix. case "ISSUER_BASE_URL": updatedEnvValues[key] = "https://" + tenantDomain - // Spring Boot okta issuer specifically requires https:// and a trailing slash. + // Spring Boot okta issuer specifically requires https:// and a trailing slash. case "okta.oauth2.issuer": updatedEnvValues[key] = "https://" + tenantDomain + "/" - // ==========================================. case "VITE_AUTH0_CLIENT_ID", "AUTH0_CLIENT_ID", "clientId", "NUXT_AUTH0_CLIENT_ID", "CLIENT_ID", "auth0.clientId", "okta.oauth2.client-id", "Auth0:ClientId", "auth0:ClientId", "auth0_client_id", "EXPO_PUBLIC_AUTH0_CLIENT_ID": updatedEnvValues[key] = client.GetClientID() - // ==========================================. case "AUTH0_CLIENT_SECRET", "NUXT_AUTH0_CLIENT_SECRET", "auth0.clientSecret", "okta.oauth2.client-secret", "Auth0:ClientSecret", "auth0:ClientSecret", "auth0_client_secret": updatedEnvValues[key] = client.GetClientSecret() - // ==========================================. case "AUTH0_SECRET", "NUXT_AUTH0_SESSION_SECRET", "SESSION_SECRET", "SECRET", "AUTH0_SESSION_ENCRYPTION_KEY", "AUTH0_COOKIE_SECRET": - // Inject a dummy secret placeholder for the user to replace, - // or replace this string with a crypto/rand generator if preferred. - updatedEnvValues[key] = "a_long_random_secret_string_replace_me" + secret, err := generateState(32) + if err != nil { + return nil, fmt.Errorf("failed to generate secret for %s: %w", key, err) + } + updatedEnvValues[key] = secret - // ==========================================. case "APP_BASE_URL", "NUXT_AUTH0_APP_BASE_URL", "BASE_URL": - updatedEnvValues[key] = "http://localhost:3000" + updatedEnvValues[key] = baseURL case "AUTH0_REDIRECT_URI", "AUTH0_CALLBACK_URL": - updatedEnvValues[key] = "http://localhost:3000/callback" + updatedEnvValues[key] = baseURL + "/callback" - // ==========================================. default: updatedEnvValues[key] = value } } - return updatedEnvValues + return updatedEnvValues, nil } -// Map the config keys to their required file output definitions based on the matrix. +// buildNestedMap converts a flat map with dot-delimited keys into a nested map. +// e.g. {"okta.oauth2.issuer": "x"} -> {"okta": {"oauth2": {"issuer": "x"}}} +func buildNestedMap(flat map[string]string) map[string]interface{} { + result := make(map[string]interface{}) + for key, value := range flat { + parts := strings.Split(key, ".") + current := result + for i, part := range parts { + if i == len(parts)-1 { + current[part] = value + } else { + if _, exists := current[part]; !exists { + current[part] = make(map[string]interface{}) + } + current = current[part].(map[string]interface{}) + } + } + } + return result +} + +// sortedKeys returns the keys of a map in sorted order. +func sortedKeys(m map[string]string) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} -// GenerateAndWriteQuickstartConfig takes the selected stack, resolves the dynamic values, -// and writes them to the appropriate file in the Current Working Directory (CWD). // GenerateAndWriteQuickstartConfig takes the selected stack, resolves the dynamic values, // and writes them to the appropriate file in the Current Working Directory (CWD). // It returns the generated file name, the file path, and an error (if any). -func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envValues map[string]string, tenantDomain string, client *management.Client) (string, string, error) { - // 1. Resolve the environment variables using the previously defined function. - resolvedEnv := replaceDetectionSub(envValues, tenantDomain, client) +func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envValues map[string]string, tenantDomain string, client *management.Client, port int) (string, string, error) { + // 1. Resolve the environment variables. + resolvedEnv, err := replaceDetectionSub(envValues, tenantDomain, client, port) + if err != nil { + return "", "", err + } // 2. Determine output file path and format. if strategy == nil { - // Fallback to a standard .env in the project root if for some reason it's missing. strategy = &auth0.FileOutputStrategy{Path: ".env", Format: "dotenv"} } - // 3. Ensure the directory path exists (e.g., creating src/environments/ if it doesn't exist). + // 3. Ensure the directory path exists. dir := filepath.Dir(strategy.Path) if dir != "." { if err := os.MkdirAll(dir, 0755); err != nil { @@ -1123,26 +1144,30 @@ func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envVal switch strategy.Format { case "dotenv", "properties": - for key, val := range resolvedEnv { - contentBuilder.WriteString(fmt.Sprintf("%s=%s\n", key, val)) + for _, key := range sortedKeys(resolvedEnv) { + contentBuilder.WriteString(fmt.Sprintf("%s=%s\n", key, resolvedEnv[key])) } case "yaml": - for key, val := range resolvedEnv { - contentBuilder.WriteString(fmt.Sprintf("%s: %s\n", key, val)) + // Produce nested YAML from dot-delimited keys (e.g. Spring Boot application.yml). + nested := buildNestedMap(resolvedEnv) + yamlBytes, err := yaml.Marshal(nested) + if err != nil { + return "", "", fmt.Errorf("failed to marshal YAML for %s: %w", strategy.Path, err) } + contentBuilder.Write(yamlBytes) case "ts": contentBuilder.WriteString("export const environment = {\n") - for key, val := range resolvedEnv { - contentBuilder.WriteString(fmt.Sprintf(" %s: '%s',\n", key, val)) + for _, key := range sortedKeys(resolvedEnv) { + contentBuilder.WriteString(fmt.Sprintf(" %s: '%s',\n", key, resolvedEnv[key])) } contentBuilder.WriteString("};\n") case "dart": contentBuilder.WriteString("const Map authConfig = {\n") - for key, val := range resolvedEnv { - contentBuilder.WriteString(fmt.Sprintf(" '%s': '%s',\n", key, val)) + for _, key := range sortedKeys(resolvedEnv) { + contentBuilder.WriteString(fmt.Sprintf(" '%s': '%s',\n", key, resolvedEnv[key])) } contentBuilder.WriteString("};\n") @@ -1150,28 +1175,23 @@ func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envVal // C# appsettings.json expects nested JSON: {"Auth0": {"Domain": "...", "ClientId": "..."}}. auth0Section := make(map[string]string) for key, val := range resolvedEnv { - // Strip the "Auth0:" prefix used in the map to create clean JSON keys. cleanKey := strings.TrimPrefix(key, "Auth0:") auth0Section[cleanKey] = val } - - jsonBody := map[string]interface{}{ - "Auth0": auth0Section, - } - - bytes, err := json.MarshalIndent(jsonBody, "", " ") + jsonBody := map[string]interface{}{"Auth0": auth0Section} + jsonBytes, err := json.MarshalIndent(jsonBody, "", " ") if err != nil { return "", "", fmt.Errorf("failed to marshal JSON for %s: %w", strategy.Path, err) } - contentBuilder.Write(bytes) + contentBuilder.Write(jsonBytes) case "xml": // ASP.NET OWIN Web.config. contentBuilder.WriteString("\n") contentBuilder.WriteString("\n") contentBuilder.WriteString(" \n") - for key, val := range resolvedEnv { - contentBuilder.WriteString(fmt.Sprintf(" \n", key, val)) + for _, key := range sortedKeys(resolvedEnv) { + contentBuilder.WriteString(fmt.Sprintf(" \n", key, resolvedEnv[key])) } contentBuilder.WriteString(" \n") contentBuilder.WriteString("\n") @@ -1182,8 +1202,7 @@ func GenerateAndWriteQuickstartConfig(strategy *auth0.FileOutputStrategy, envVal return "", "", fmt.Errorf("failed to write config file %s: %w", strategy.Path, err) } - // 6. Extract the base file name from the path and return both. + // 6. Return the base file name and full path. fileName := filepath.Base(strategy.Path) - return fileName, strategy.Path, nil } From 1fd556d9668be508eb5a0c6d69ed003e48cc05d9 Mon Sep 17 00:00:00 2001 From: Kartik Jha Date: Tue, 31 Mar 2026 22:03:36 +0530 Subject: [PATCH 12/12] fix: lint fixes --- internal/auth0/quickstart.go | 12 +++--------- internal/cli/quickstarts.go | 9 +++++---- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/internal/auth0/quickstart.go b/internal/auth0/quickstart.go index 949109a24..a3cbd582d 100644 --- a/internal/auth0/quickstart.go +++ b/internal/auth0/quickstart.go @@ -197,9 +197,7 @@ type AppConfig struct { var QuickstartConfigs = map[string]AppConfig{ - // ========================================== - // Single Page Applications (SPA) - // ========================================== + // ==========================================. "spa:react:vite": { EnvValues: map[string]string{ "VITE_AUTH0_DOMAIN": DetectionSub, @@ -285,9 +283,7 @@ var QuickstartConfigs = map[string]AppConfig{ Strategy: FileOutputStrategy{Path: "lib/auth_config.dart", Format: "dart"}, }, - // ========================================== - // Regular Web Applications - // ========================================== + // ==========================================. "regular:nextjs:none": { EnvValues: map[string]string{ "AUTH0_DOMAIN": DetectionSub, @@ -553,9 +549,7 @@ var QuickstartConfigs = map[string]AppConfig{ Strategy: FileOutputStrategy{Path: ".env", Format: "dotenv"}, }, - // ========================================== - // Native / Mobile Applications - // ========================================== + // ==========================================. "native:flutter:none": { EnvValues: map[string]string{ "domain": DetectionSub, diff --git a/internal/cli/quickstarts.go b/internal/cli/quickstarts.go index f94236094..51d5b553d 100644 --- a/internal/cli/quickstarts.go +++ b/internal/cli/quickstarts.go @@ -456,7 +456,7 @@ type SetupInputs struct { API bool Identifier string Audience string - SigningAlg string + SigningAlg string Scopes string TokenLifetime string OfflineAccess bool @@ -750,10 +750,10 @@ func setupQuickstartCmdExperimental(cli *cli) *cobra.Command { } rs := &management.ResourceServer{ - Name: &inputs.Identifier, - Identifier: &inputs.Identifier, + Name: &inputs.Identifier, + Identifier: &inputs.Identifier, SigningAlgorithm: &inputs.SigningAlg, - TokenLifetime: &tokenLifetime, + TokenLifetime: &tokenLifetime, } if inputs.OfflineAccess { allow := true @@ -796,6 +796,7 @@ func printAPIDetails(cli *cli, rs *management.ResourceServer) { cli.renderer.Infof("API %q registered (Identifier: %s)", rs.GetName(), rs.GetIdentifier()) cli.renderer.Infof("Manage: https://manage.auth0.com/dashboard/#/apis/%s/settings", rs.GetID()) } + // Helper function to get supported quickstart types. func getSupportedQuickstartTypes() []string { var types []string