@@ -57,10 +57,6 @@ type LoginInputs struct {
57
57
AdditionalScopes []string
58
58
}
59
59
60
- func (i * LoginInputs ) isLoggingInAsAMachine () bool {
61
- return i .ClientID != "" || i .ClientSecret != "" || i .Domain != ""
62
- }
63
-
64
60
func (i * LoginInputs ) isLoggingInWithAdditionalScopes () bool {
65
61
return len (i .AdditionalScopes ) > 0
66
62
}
@@ -82,12 +78,65 @@ func loginCmd(cli *cli) *cobra.Command {
82
78
RunE : func (cmd * cobra.Command , args []string ) error {
83
79
var selectedLoginType string
84
80
const loginAsUser , loginAsMachine = "As a user" , "As a machine"
81
+ shouldLoginAsUser , shouldLoginAsMachine := false , false
82
+
83
+ /*
84
+ Based on the initial inputs we'd like to determine if
85
+ it's a machine login or a user login
86
+ If we successfully determine it, we don't need to prompt the user.
87
+
88
+ The --no-input flag add strict restriction that we shall not take any further input after
89
+ initial command.
90
+ Hence, the flow diverges into two based on no-input flag's value.
91
+ */
92
+ switch {
93
+ case cli .noInput :
94
+ switch {
95
+ case inputs .Domain != "" && inputs .ClientSecret != "" && inputs .ClientID != "" :
96
+ // If all three fields are passed, machine login flag is set to true.
97
+ shouldLoginAsMachine = true
98
+ case inputs .Domain != "" && inputs .ClientSecret == "" && inputs .ClientID == "" :
99
+ /*
100
+ The domain flag is common between Machine and User Login.
101
+ If domain is passed without client-id and client-secret,
102
+ it can be evaluated that it is a user login flow.
103
+ */
104
+ shouldLoginAsUser = true
105
+ case inputs .Domain != "" || inputs .ClientSecret != "" || inputs .ClientID != "" :
106
+ /*
107
+ At this point, if AT LEAST one of the three flags are passed but not ALL three,
108
+ we return an error since it's a no-input flow and it will need all three params
109
+ for successful machine flow.
110
+ Note that we already determined it's not a user login flow in the condition above.
111
+ */
112
+ return fmt .Errorf ("flags client-id, client-secret and domain are required together" )
113
+ default :
114
+ /*
115
+ If no flags are passed along with --no-input, it is defaulted to user login flow.
116
+ */
117
+ shouldLoginAsUser = true
118
+ }
119
+ default :
120
+ if inputs .ClientSecret != "" || inputs .ClientID != "" {
121
+ /*
122
+ If all three params are passed, we evaluate it as a Machine Login Flow.
123
+ Else required params are prompted for.
124
+ */
125
+ shouldLoginAsMachine = true
126
+ }
127
+ }
85
128
86
- // We want to prompt if we don't pass the following flags:
87
- // --no-input, --scopes, --client-id, --client-secret, --domain.
88
- // Because then the prompt is unnecessary as we know the login type.
89
- shouldPrompt := ! inputs .isLoggingInAsAMachine () && ! cli .noInput && ! inputs .isLoggingInWithAdditionalScopes ()
90
- if shouldPrompt {
129
+ // If additional scopes are passed we mark shouldLoginAsUser flag to be true.
130
+ if inputs .isLoggingInWithAdditionalScopes () {
131
+ shouldLoginAsUser = true
132
+ }
133
+
134
+ /*
135
+ If we are unable to determine if it's a user login or a machine login
136
+ based on all the evaluation above, we go on to prompt the user and
137
+ determine if it's LoginAsUser or LoginAsMachine
138
+ */
139
+ if ! shouldLoginAsUser && ! shouldLoginAsMachine {
91
140
cli .renderer .Output (
92
141
fmt .Sprintf (
93
142
"%s\n \n %s\n %s\n \n %s\n %s\n %s\n %s\n \n " ,
@@ -107,18 +156,16 @@ func loginCmd(cli *cli) *cobra.Command {
107
156
"Authenticating as a user is recommended if performing ad-hoc operations or working locally." ,
108
157
"Alternatively, authenticating as a machine is recommended for automated workflows (ex:CI)." ,
109
158
)
110
- input := prompt .SelectInput ("" , label , help , []string {loginAsUser , loginAsMachine }, loginAsUser , shouldPrompt )
159
+ input := prompt .SelectInput ("" , label , help , []string {loginAsUser , loginAsMachine }, loginAsUser , true )
111
160
if err := prompt .AskOne (input , & selectedLoginType ); err != nil {
112
161
return handleInputError (err )
113
162
}
114
163
}
115
164
116
165
ctx := cmd .Context ()
117
166
118
- // Allows to skip to user login if either the --no-input or --scopes flag is passed.
119
- shouldLoginAsUser := (cli .noInput && ! inputs .isLoggingInAsAMachine ()) || inputs .isLoggingInWithAdditionalScopes () || selectedLoginType == loginAsUser
120
- if shouldLoginAsUser {
121
- if _ , err := RunLoginAsUser (ctx , cli , inputs .AdditionalScopes ); err != nil {
167
+ if shouldLoginAsUser || selectedLoginType == loginAsUser {
168
+ if _ , err := RunLoginAsUser (ctx , cli , inputs .AdditionalScopes , inputs .Domain ); err != nil {
122
169
return fmt .Errorf ("failed to start the authentication process: %w" , err )
123
170
}
124
171
} else {
@@ -143,8 +190,8 @@ func loginCmd(cli *cli) *cobra.Command {
143
190
loginClientID .RegisterString (cmd , & inputs .ClientID , "" )
144
191
loginClientSecret .RegisterString (cmd , & inputs .ClientSecret , "" )
145
192
loginAdditionalScopes .RegisterStringSlice (cmd , & inputs .AdditionalScopes , []string {})
146
- cmd .MarkFlagsRequiredTogether ("client-id" , "client-secret" , "domain" )
147
193
cmd .MarkFlagsMutuallyExclusive ("client-id" , "scopes" )
194
+ cmd .MarkFlagsMutuallyExclusive ("client-secret" , "scopes" )
148
195
149
196
cmd .SetHelpFunc (func (cmd * cobra.Command , args []string ) {
150
197
_ = cmd .Flags ().MarkHidden ("tenant" )
@@ -154,10 +201,36 @@ func loginCmd(cli *cli) *cobra.Command {
154
201
return cmd
155
202
}
156
203
204
+ func ensureAuth0URL (input string ) (string , error ) {
205
+ if input == "" {
206
+ return "https://*.auth0.com/api/v2/" , nil
207
+ }
208
+ input = strings .TrimPrefix (input , "http://" )
209
+ input = strings .TrimPrefix (input , "https://" )
210
+ input = strings .TrimSuffix (input , "/api/v2" )
211
+
212
+ // Check if the input ends with auth0.com .
213
+ if ! strings .HasSuffix (input , "auth0.com" ) {
214
+ return "" , fmt .Errorf ("not a valid auth0.com domain" )
215
+ }
216
+
217
+ // Extract the domain part without any path.
218
+ domainParts := strings .Split (input , "/" )
219
+ domain := domainParts [0 ]
220
+
221
+ // Return the formatted URL.
222
+ return fmt .Sprintf ("https://%s/api/v2/" , domain ), nil
223
+ }
224
+
157
225
// RunLoginAsUser runs the login flow guiding the user through the process
158
226
// by showing the login instructions, opening the browser.
159
- func RunLoginAsUser (ctx context.Context , cli * cli , additionalScopes []string ) (config.Tenant , error ) {
160
- state , err := auth .GetDeviceCode (ctx , http .DefaultClient , additionalScopes )
227
+ func RunLoginAsUser (ctx context.Context , cli * cli , additionalScopes []string , domain string ) (config.Tenant , error ) {
228
+ domain , err := ensureAuth0URL (domain )
229
+ if err != nil {
230
+ return config.Tenant {}, err
231
+ }
232
+
233
+ state , err := auth .GetDeviceCode (ctx , http .DefaultClient , additionalScopes , domain )
161
234
if err != nil {
162
235
return config.Tenant {}, fmt .Errorf ("failed to get the device code: %w" , err )
163
236
}
0 commit comments