Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions docs/auth0_quickstarts_setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Supported types:
- vite: For client-side SPAs (React, Vue, Svelte, etc.)
- nextjs: For Next.js server-side applications
- fastify: For Fastify web applications
- jhipster-rwa: For JHipster regular web applications

## Usage
```
Expand All @@ -30,6 +31,7 @@ auth0 quickstarts setup [flags]
auth0 quickstarts setup --type fastify
auth0 quickstarts setup --type vite --name "My App"
auth0 quickstarts setup --type nextjs --port 8080
auth0 quickstarts setup --type jhipster-rwa
auth0 qs setup --type fastify -n "My App" -p 3000
```

Expand All @@ -38,9 +40,9 @@ auth0 quickstarts setup [flags]

```
--json Output in json format.
-n, --name string Name of the Auth0 application (defaults to current directory name)
-p, --port int Port number for the application (default: 5173 for vite, 3000 for nextjs/fastify)
-t, --type string Type of quickstart (vite, nextjs)
-n, --name string Name of the Auth0 application (default: 'My App' for vite, nextjs and fastify, 'JHipster' for jhipster-rwa)
-p, --port int Port number for the application (default: 5173 for vite, 3000 for nextjs/fastify, 8080 for jhipster-rwa)
-t, --type string Type of quickstart (vite, nextjs, fastify, jhipster-rwa)
```


Expand Down
110 changes: 62 additions & 48 deletions internal/cli/quickstarts.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"path"
"path/filepath"
"regexp"
"strconv"
"strings"

"github.com/auth0/go-auth0/management"
Expand Down Expand Up @@ -420,20 +421,20 @@ var (
Name: "Type",
LongForm: "type",
ShortForm: "t",
Help: "Type of quickstart (vite, nextjs)",
Help: "Type of quickstart (vite, nextjs, fastify, jhipster-rwa)",
IsRequired: true,
}
qsAppName = Flag{
Name: "Name",
LongForm: "name",
ShortForm: "n",
Help: "Name of the Auth0 application (defaults to current directory name)",
Help: "Name of the Auth0 application (default: 'My App' for vite, nextjs and fastify, 'JHipster' for jhipster-rwa)",
}
qsPort = Flag{
Name: "Port",
LongForm: "port",
ShortForm: "p",
Help: "Port number for the application (default: 5173 for vite, 3000 for nextjs/fastify)",
Help: "Port number for the application (default: 5173 for vite, 3000 for nextjs/fastify, 8080 for jhipster-rwa)",
}
)

Expand All @@ -456,24 +457,26 @@ func setupQuickstartCmd(cli *cli) *cobra.Command {
"Supported types:\n" +
" - vite: For client-side SPAs (React, Vue, Svelte, etc.)\n" +
" - nextjs: For Next.js server-side applications\n" +
" - fastify: For Fastify web applications",
" - fastify: For Fastify web applications\n" +
" - jhipster-rwa: For JHipster regular web applications",
Example: ` auth0 quickstarts setup --type vite
auth0 quickstarts setup --type nextjs
auth0 quickstarts setup --type fastify
auth0 quickstarts setup --type vite --name "My App"
auth0 quickstarts setup --type nextjs --port 8080
auth0 quickstarts setup --type jhipster-rwa
auth0 qs setup --type fastify -n "My App" -p 3000`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()

if inputs.Type != "" {
normalizedType := strings.ToLower(inputs.Type)
if normalizedType != "vite" && normalizedType != "nextjs" && normalizedType != "fastify" {
return fmt.Errorf("unsupported quickstart type: %s (supported types: vite, nextjs, fastify)", inputs.Type)
if normalizedType != "vite" && normalizedType != "nextjs" && normalizedType != "fastify" && normalizedType != "jhipster-rwa" {
return fmt.Errorf("unsupported quickstart type: %s (supported types: vite, nextjs, fastify, jhipster-rwa)", inputs.Type)
}
}

if err := qsType.Select(cmd, &inputs.Type, []string{"vite", "nextjs", "fastify"}, nil); err != nil {
if err := qsType.Select(cmd, &inputs.Type, []string{"vite", "nextjs", "fastify", "jhipster-rwa"}, nil); err != nil {
return err
}

Expand All @@ -482,53 +485,47 @@ func setupQuickstartCmd(cli *cli) *cobra.Command {
}

defaultName := "My App"

if err := qsAppName.Ask(cmd, &inputs.Name, &defaultName); err != nil {
return err
}

var appType, baseURL, envFileName string
var callbacks, logoutURLs, origins, webOrigins []string
var defaultPort string
var defaultPort int

switch inputs.Type {
case "vite":
appType = appTypeSPA
defaultPort = "5173"
envFileName = ".env"

defaultPort = 5173
case "nextjs", "fastify":
appType = appTypeRegularWeb
defaultPort = "3000"
envFileName = ".env"
defaultPort = 3000
case "jhipster-rwa":
defaultName = "JHipster"
defaultPort = 8080
}

// If port is not explicitly set (is 0), ask for it or use default.
if inputs.Port == 0 {
if err := qsPort.Ask(cmd, &inputs.Port, &defaultPort); err != nil {
// If name is not explicitly set (is empty), ask for it or use default.
if inputs.Name == "" {
inputs.Name = defaultName
if err := qsAppName.Ask(cmd, &inputs.Name, &defaultName); err != nil {
return err
}
}

// If port is still 0 after asking (e.g., in non-interactive mode), use the default.
// If port is not explicitly set (is 0), ask for it or use default.
if inputs.Port == 0 {
switch inputs.Type {
case "vite":
inputs.Port = 5173
case "nextjs", "fastify":
inputs.Port = 3000
inputs.Port = defaultPort
defaultPortStr := strconv.Itoa(defaultPort)
if err := qsPort.Ask(cmd, &inputs.Port, &defaultPortStr); err != nil {
return err
}
}

if inputs.Port < 1024 || inputs.Port > 65535 {
return fmt.Errorf("invalid port number: %d (must be between 1024 and 65535)", inputs.Port)
}

baseURL = fmt.Sprintf("http://localhost:%d", inputs.Port)
baseURL := fmt.Sprintf("http://localhost:%d", inputs.Port)
appType := appTypeRegularWeb
var callbacks, logoutURLs, origins, webOrigins []string

// Configure URLs based on app type.
switch inputs.Type {
case "vite":
appType = appTypeSPA
callbacks = []string{baseURL}
logoutURLs = []string{baseURL}
origins = []string{baseURL}
Expand All @@ -541,6 +538,10 @@ func setupQuickstartCmd(cli *cli) *cobra.Command {
callbackURL := fmt.Sprintf("%s/auth/callback", baseURL)
callbacks = []string{callbackURL}
logoutURLs = []string{baseURL}
case "jhipster-rwa":
callbackURL := fmt.Sprintf("%s/login/oauth2/code/oidc", baseURL)
callbacks = []string{callbackURL}
logoutURLs = []string{baseURL}
}

cli.renderer.Infof("Creating Auth0 application '%s'...", inputs.Name)
Expand Down Expand Up @@ -581,36 +582,44 @@ func setupQuickstartCmd(cli *cli) *cobra.Command {
return fmt.Errorf("failed to get tenant: %w", err)
}

envFileName := ".env"
var envContent strings.Builder

switch inputs.Type {
case "vite":
envContent.WriteString(fmt.Sprintf("VITE_AUTH0_DOMAIN=%s\n", tenant.Domain))
envContent.WriteString(fmt.Sprintf("VITE_AUTH0_CLIENT_ID=%s\n", a.GetClientID()))
fmt.Fprintf(&envContent, "VITE_AUTH0_DOMAIN=%s\n", tenant.Domain)
fmt.Fprintf(&envContent, "VITE_AUTH0_CLIENT_ID=%s\n", a.GetClientID())

case "nextjs":
secret, err := generateState(32)
if err != nil {
return fmt.Errorf("failed to generate AUTH0_SECRET: %w", err)
}

envContent.WriteString(fmt.Sprintf("AUTH0_DOMAIN=%s\n", tenant.Domain))
envContent.WriteString(fmt.Sprintf("AUTH0_CLIENT_ID=%s\n", a.GetClientID()))
envContent.WriteString(fmt.Sprintf("AUTH0_CLIENT_SECRET=%s\n", a.GetClientSecret()))
envContent.WriteString(fmt.Sprintf("AUTH0_SECRET=%s\n", secret))
envContent.WriteString(fmt.Sprintf("APP_BASE_URL=%s\n", baseURL))
fmt.Fprintf(&envContent, "AUTH0_DOMAIN=%s\n", tenant.Domain)
fmt.Fprintf(&envContent, "AUTH0_CLIENT_ID=%s\n", a.GetClientID())
fmt.Fprintf(&envContent, "AUTH0_CLIENT_SECRET=%s\n", a.GetClientSecret())
fmt.Fprintf(&envContent, "AUTH0_SECRET=%s\n", secret)
fmt.Fprintf(&envContent, "APP_BASE_URL=%s\n", baseURL)

case "fastify":
sessionSecret, err := generateState(64)
if err != nil {
return fmt.Errorf("failed to generate SESSION_SECRET: %w", err)
}

envContent.WriteString(fmt.Sprintf("AUTH0_DOMAIN=%s\n", tenant.Domain))
envContent.WriteString(fmt.Sprintf("AUTH0_CLIENT_ID=%s\n", a.GetClientID()))
envContent.WriteString(fmt.Sprintf("AUTH0_CLIENT_SECRET=%s\n", a.GetClientSecret()))
envContent.WriteString(fmt.Sprintf("SESSION_SECRET=%s\n", sessionSecret))
envContent.WriteString(fmt.Sprintf("APP_BASE_URL=%s\n", baseURL))
fmt.Fprintf(&envContent, "AUTH0_DOMAIN=%s\n", tenant.Domain)
fmt.Fprintf(&envContent, "AUTH0_CLIENT_ID=%s\n", a.GetClientID())
fmt.Fprintf(&envContent, "AUTH0_CLIENT_SECRET=%s\n", a.GetClientSecret())
fmt.Fprintf(&envContent, "SESSION_SECRET=%s\n", sessionSecret)
fmt.Fprintf(&envContent, "APP_BASE_URL=%s\n", baseURL)

case "jhipster-rwa":
envFileName = ".auth0.env"
fmt.Fprintf(&envContent, "SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI=https://%s/\n", tenant.Domain)
fmt.Fprintf(&envContent, "SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID=%s\n", a.GetClientID())
fmt.Fprintf(&envContent, "SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET=%s\n", a.GetClientSecret())
fmt.Fprintf(&envContent, "JHIPSTER_SECURITY_OAUTH2_AUDIENCE=https://%s/api/v2/\n", tenant.Domain)
}

message := fmt.Sprintf(" Proceed to overwrite '%s' file? : ", envFileName)
Expand All @@ -626,10 +635,15 @@ func setupQuickstartCmd(cli *cli) *cobra.Command {
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)
switch inputs.Type {
case "jhipster-rwa":
cli.renderer.Infof("Please refer to the JHipster documentation https://www.jhipster.tech/security/#auth0 to complete the setup")
default:
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
},
Expand Down
Loading