Skip to content
Draft
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
12 changes: 8 additions & 4 deletions docs/stackit_auth_login.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Logs in to the STACKIT CLI
### Synopsis

Logs in to the STACKIT CLI using a user account.
The authentication is done via a web-based authorization flow, where the command will open a browser window in which you can login to your STACKIT account.
By default, the authentication uses a web-based authorization flow and opens a browser window where you can login to your STACKIT account. You can alternatively use the OAuth 2.0 device flow for environments where receiving a local callback is not possible.

```
stackit auth login [flags]
Expand All @@ -16,14 +16,18 @@ stackit auth login [flags]
```
Login to the STACKIT CLI. This command will open a browser window where you can login to your STACKIT account
$ stackit auth login

Login to the STACKIT CLI using OAuth 2.0 device flow
$ stackit auth login --use-device-flow
```

### Options

```
-h, --help Help for "stackit auth login"
--port int The port on which the callback server will listen to. By default, it tries to bind a port between 8000 and 8020.
When a value is specified, it will only try to use the specified port. Valid values are within the range of 8000 to 8020.
-h, --help Help for "stackit auth login"
--port int The port on which the callback server will listen to. By default, it tries to bind a port between 8000 and 8020.
When a value is specified, it will only try to use the specified port. Valid values are within the range of 8000 to 8020.
--use-device-flow Use OAuth 2.0 device authorization grant (device flow) instead of the browser callback flow.
```

### Options inherited from parent commands
Expand Down
18 changes: 14 additions & 4 deletions internal/cmd/auth/login/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import (
)

const (
portFlag = "port"
portFlag = "port"
useDeviceFlowFlag = "use-device-flow"
)

type inputModel struct {
Port *int
Port *int
UseDeviceFlow bool
}

func NewCmd(params *types.CmdParams) *cobra.Command {
Expand All @@ -27,12 +29,15 @@ func NewCmd(params *types.CmdParams) *cobra.Command {
Short: "Logs in to the STACKIT CLI",
Long: fmt.Sprintf("%s\n%s",
"Logs in to the STACKIT CLI using a user account.",
"The authentication is done via a web-based authorization flow, where the command will open a browser window in which you can login to your STACKIT account."),
"By default, the authentication uses a web-based authorization flow and opens a browser window where you can login to your STACKIT account. You can alternatively use the OAuth 2.0 device flow for environments where receiving a local callback is not possible."),
Args: args.NoArgs,
Example: examples.Build(
examples.NewExample(
`Login to the STACKIT CLI. This command will open a browser window where you can login to your STACKIT account`,
"$ stackit auth login"),
examples.NewExample(
`Login to the STACKIT CLI using OAuth 2.0 device flow`,
"$ stackit auth login --use-device-flow"),
),
RunE: func(cmd *cobra.Command, args []string) error {
model, err := parseInput(params.Printer, cmd, args)
Expand All @@ -43,6 +48,7 @@ func NewCmd(params *types.CmdParams) *cobra.Command {
err = auth.AuthorizeUser(params.Printer, auth.UserAuthConfig{
IsReauthentication: false,
Port: model.Port,
UseDeviceFlow: model.UseDeviceFlow,
})
if err != nil {
return fmt.Errorf("authorization failed: %w", err)
Expand All @@ -62,17 +68,21 @@ func configureFlags(cmd *cobra.Command) {
"The port on which the callback server will listen to. By default, it tries to bind a port between 8000 and 8020.\n"+
"When a value is specified, it will only try to use the specified port. Valid values are within the range of 8000 to 8020.",
)
cmd.Flags().Bool(useDeviceFlowFlag, false,
"Use OAuth 2.0 device authorization grant (device flow) instead of the browser callback flow.")
}

func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, error) {
port := flags.FlagToIntPointer(p, cmd, portFlag)
useDeviceFlow := flags.FlagToBoolValue(p, cmd, useDeviceFlowFlag)
// For the CLI client only callback URLs with localhost:[8000-8020] are valid. Additional callbacks must be enabled in the backend.
if port != nil && (*port < 8000 || 8020 < *port) {
return nil, fmt.Errorf("port must be between 8000 and 8020")
}

model := inputModel{
Port: port,
Port: port,
UseDeviceFlow: useDeviceFlow,
}

p.DebugInputModel(model)
Expand Down
26 changes: 21 additions & 5 deletions internal/cmd/auth/login/login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import (

func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string {
flagValues := map[string]string{
portFlag: "8010",
portFlag: "8010",
useDeviceFlowFlag: "false",
}
for _, mod := range mods {
mod(flagValues)
Expand All @@ -19,7 +20,8 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st

func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
model := &inputModel{
Port: utils.Ptr(8010),
Port: utils.Ptr(8010),
UseDeviceFlow: false,
}
for _, mod := range mods {
mod(model)
Expand All @@ -46,7 +48,19 @@ func TestParseInput(t *testing.T) {
flagValues: map[string]string{},
isValid: true,
expectedModel: &inputModel{
Port: nil,
Port: nil,
UseDeviceFlow: false,
},
},
{
description: "device flow enabled",
flagValues: map[string]string{
useDeviceFlowFlag: "true",
},
isValid: true,
expectedModel: &inputModel{
Port: nil,
UseDeviceFlow: true,
},
},
{
Expand All @@ -56,7 +70,8 @@ func TestParseInput(t *testing.T) {
},
isValid: true,
expectedModel: &inputModel{
Port: utils.Ptr(8000),
Port: utils.Ptr(8000),
UseDeviceFlow: false,
},
},
{
Expand All @@ -73,7 +88,8 @@ func TestParseInput(t *testing.T) {
},
isValid: true,
expectedModel: &inputModel{
Port: utils.Ptr(8020),
Port: utils.Ptr(8020),
UseDeviceFlow: false,
},
},
{
Expand Down
Loading
Loading