diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 550a4c612..224d8063d 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -72,7 +72,6 @@ type cli struct { // core primitives exposed to command builders. api *auth0.API renderer *display.Renderer - // set of flags which are user specified. debug bool tenant string @@ -123,21 +122,36 @@ func (c *cli) setup(ctx context.Context) error { return err } - t, err := c.getTenant() + t, err := c.prepareTenant(ctx) if err != nil { return err } - if t.AccessToken == "" { - return errUnauthenticated + m, err := management.New(t.Domain, + management.WithStaticToken(t.AccessToken), + management.WithUserAgent(fmt.Sprintf("%v/%v", userAgent, strings.TrimPrefix(buildinfo.Version, "v")))) + if err != nil { + return err } - if scopesChanged(t) { - // required scopes changed, - // a new token is required - err = RunLogin(ctx, c, true) + c.api = auth0.NewAPI(m) + return nil +} + +// prepareTenant loads the tenant, refreshing its token if necessary. +// The tenant access token needs a refresh if: +// 1. the tenant scopes are different than the currently required scopes. +// 2. the access token is expired. +func (c *cli) prepareTenant(ctx context.Context) (tenant, error) { + t, err := c.getTenant() + if err != nil { + return tenant{}, err + } + + if t.AccessToken == "" || scopesChanged(t) { + t, err = RunLogin(ctx, c, true) if err != nil { - return err + return tenant{}, err } } else if isExpired(t.ExpiresAt, accessTokenExpThreshold) { // check if the stored access token is expired: @@ -151,9 +165,9 @@ func (c *cli) setup(ctx context.Context) error { if err != nil { // ask and guide the user through the login process: c.renderer.Errorf("failed to renew access token, %s", err) - err = RunLogin(ctx, c, true) + t, err = RunLogin(ctx, c, true) if err != nil { - return err + return tenant{}, err } } else { // persist the updated tenant with renewed access token @@ -164,24 +178,12 @@ func (c *cli) setup(ctx context.Context) error { err = c.addTenant(t) if err != nil { - return err + return tenant{}, err } } } - // continue with the command setup: - if t.AccessToken != "" { - m, err := management.New(t.Domain, - management.WithStaticToken(t.AccessToken), - management.WithUserAgent(fmt.Sprintf("%v/%v", userAgent, strings.TrimPrefix(buildinfo.Version, "v")))) - if err != nil { - return err - } - - c.api = auth0.NewAPI(m) - } - - return err + return t, nil } // isExpired is true if now() + a threshold is after the given date diff --git a/internal/cli/login.go b/internal/cli/login.go index e885c8565..eaf10b02a 100644 --- a/internal/cli/login.go +++ b/internal/cli/login.go @@ -20,7 +20,8 @@ func loginCmd(cli *cli) *cobra.Command { Long: "Sign in to your Auth0 account and authorize the CLI to access the Management API.", RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - return RunLogin(ctx, cli, false) + _, err := RunLogin(ctx, cli, false) + return err }, } @@ -31,7 +32,7 @@ func loginCmd(cli *cli) *cobra.Command { // by showing the login instructions, opening the browser. // Use `expired` to run the login from other commands setup: // this will only affect the messages. -func RunLogin(ctx context.Context, cli *cli, expired bool) error { +func RunLogin(ctx context.Context, cli *cli, expired bool) (tenant, error) { if expired { cli.renderer.Warnf("Please sign in to re-authorize the CLI.") } else { @@ -42,7 +43,7 @@ func RunLogin(ctx context.Context, cli *cli, expired bool) error { a := &auth.Authenticator{} state, err := a.Start(ctx) if err != nil { - return fmt.Errorf("could not start the authentication process: %w.", err) + return tenant{}, fmt.Errorf("could not start the authentication process: %w.", err) } fmt.Printf("Your Device Confirmation code is: %s\n\n", ansi.Bold(state.UserCode)) @@ -61,7 +62,7 @@ func RunLogin(ctx context.Context, cli *cli, expired bool) error { }) if err != nil { - return fmt.Errorf("login error: %w", err) + return tenant{}, fmt.Errorf("login error: %w", err) } fmt.Print("\n") @@ -76,7 +77,7 @@ func RunLogin(ctx context.Context, cli *cli, expired bool) error { cli.renderer.Warnf("Could not store the refresh token locally, please expect to login again once your access token expired. See https://github.com/auth0/auth0-cli/blob/main/KNOWN-ISSUES.md.") } - err = cli.addTenant(tenant{ + t := tenant{ Name: res.Tenant, Domain: res.Domain, AccessToken: res.AccessToken, @@ -84,21 +85,22 @@ func RunLogin(ctx context.Context, cli *cli, expired bool) error { time.Duration(res.ExpiresIn) * time.Second, ), Scopes: auth.RequiredScopes(), - }) + } + err = cli.addTenant(t) if err != nil { - return fmt.Errorf("Unexpected error adding tenant to config: %w", err) + return tenant{}, fmt.Errorf("Unexpected error adding tenant to config: %w", err) } if cli.config.DefaultTenant != res.Domain { promptText := fmt.Sprintf("Your default tenant is %s. Do you want to change it to %s?", cli.config.DefaultTenant, res.Domain) if confirmed := prompt.Confirm(promptText); !confirmed { - return nil + return tenant{}, nil } cli.config.DefaultTenant = res.Domain if err := cli.persistConfig(); err != nil { - return fmt.Errorf("An error occurred while setting the default tenant: %w", err) + return tenant{}, fmt.Errorf("An error occurred while setting the default tenant: %w", err) } } - return nil + return t, nil }