Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: generate a new session with coder login --token #8275

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 5, 2023
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
41 changes: 32 additions & 9 deletions cli/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,18 @@ func (r *RootCmd) login() *clibase.Cmd {
const firstUserTrialEnv = "CODER_FIRST_USER_TRIAL"

var (
email string
username string
password string
trial bool
email string
username string
password string
trial bool
useTokenForSession bool
)
cmd := &clibase.Cmd{
Use: "login <url>",
Short: "Authenticate with Coder deployment",
Middleware: clibase.RequireRangeArgs(0, 1),
Handler: func(inv *clibase.Invocation) error {
ctx := inv.Context()
rawURL := ""
if len(inv.Args) == 0 {
rawURL = r.clientURL.String()
Expand Down Expand Up @@ -89,7 +91,7 @@ func (r *RootCmd) login() *clibase.Cmd {
_, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Warn.Render(err.Error()))
}

hasInitialUser, err := client.HasFirstUser(inv.Context())
hasInitialUser, err := client.HasFirstUser(ctx)
if err != nil {
return xerrors.Errorf("Failed to check server %q for first user, is the URL correct and is coder accessible from your browser? Error - has initial user: %w", serverURL.String(), err)
}
Expand Down Expand Up @@ -182,7 +184,7 @@ func (r *RootCmd) login() *clibase.Cmd {
trial = v == "yes" || v == "y"
}

_, err = client.CreateFirstUser(inv.Context(), codersdk.CreateFirstUserRequest{
_, err = client.CreateFirstUser(ctx, codersdk.CreateFirstUserRequest{
Email: email,
Username: username,
Password: password,
Expand All @@ -191,7 +193,7 @@ func (r *RootCmd) login() *clibase.Cmd {
if err != nil {
return xerrors.Errorf("create initial user: %w", err)
}
resp, err := client.LoginWithPassword(inv.Context(), codersdk.LoginWithPasswordRequest{
resp, err := client.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{
Email: email,
Password: password,
})
Expand Down Expand Up @@ -235,7 +237,7 @@ func (r *RootCmd) login() *clibase.Cmd {
Secret: true,
Validate: func(token string) error {
client.SetSessionToken(token)
_, err := client.User(inv.Context(), codersdk.Me)
_, err := client.User(ctx, codersdk.Me)
if err != nil {
return xerrors.New("That's not a valid token!")
}
Expand All @@ -245,11 +247,27 @@ func (r *RootCmd) login() *clibase.Cmd {
if err != nil {
return xerrors.Errorf("paste token prompt: %w", err)
}
} else if !useTokenForSession {
// If a session token is provided on the cli, use it to generate
// a new one. This is because the cli `--token` flag provides
// a token for the command being invoked. We should not store
// this token, and `/logout` should not delete it.
// /login should generate a new token and store that.
client.SetSessionToken(sessionToken)
// Use CreateAPIKey over CreateToken because this is a session
// key that should not show on the `tokens` page. This should
// match the same behavior of the `/cli-auth` page for generating
// a session token.
key, err := client.CreateAPIKey(ctx, "me")
if err != nil {
return xerrors.Errorf("create api key: %w", err)
}
sessionToken = key.Key
}

// Login to get user data - verify it is OK before persisting
client.SetSessionToken(sessionToken)
resp, err := client.User(inv.Context(), codersdk.Me)
resp, err := client.User(ctx, codersdk.Me)
if err != nil {
return xerrors.Errorf("get user: %w", err)
}
Expand Down Expand Up @@ -293,6 +311,11 @@ func (r *RootCmd) login() *clibase.Cmd {
Description: "Specifies whether a trial license should be provisioned for the Coder deployment or not.",
Value: clibase.BoolOf(&trial),
},
{
Flag: "use-token-as-session",
Description: "By default, the CLI will generate a new session token when logging in. This flag will instead use the provided token as the session token.",
Value: clibase.BoolOf(&useTokenForSession),
},
}
return cmd
}
Expand Down
4 changes: 3 additions & 1 deletion cli/login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ func TestLogin(t *testing.T) {
<-doneChan
})

// TokenFlag should generate a new session token and store it in the session file.
t.Run("TokenFlag", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
Expand All @@ -206,6 +207,7 @@ func TestLogin(t *testing.T) {
require.NoError(t, err)
sessionFile, err := cfg.Session().Read()
require.NoError(t, err)
require.Equal(t, client.SessionToken(), sessionFile)
// This **should not be equal** to the token we passed in.
require.NotEqual(t, client.SessionToken(), sessionFile)
})
}
4 changes: 4 additions & 0 deletions cli/testdata/coder_login_--help.golden
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@ Authenticate with Coder deployment
Specifies a username to use if creating the first user for the
deployment.

--use-token-as-session bool
By default, the CLI will generate a new session token when logging in.
This flag will instead use the provided token as the session token.

---
Run `coder --help` for a list of global options.
5 changes: 4 additions & 1 deletion codersdk/apikey.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ func (c *Client) CreateToken(ctx context.Context, userID string, req CreateToken
}

// CreateAPIKey generates an API key for the user ID provided.
// DEPRECATED: use CreateToken instead.
// CreateToken should be used over CreateAPIKey. CreateToken allows better
// tracking of the token's usage and allows for custom expiration.
// Only use CreateAPIKey if you want to emulate the session created for
// a browser like login.
func (c *Client) CreateAPIKey(ctx context.Context, user string) (GenerateAPIKeyResponse, error) {
res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/users/%s/keys", user), nil)
if err != nil {
Expand Down
8 changes: 8 additions & 0 deletions docs/cli/login.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,11 @@ Specifies whether a trial license should be provisioned for the Coder deployment
| Environment | <code>$CODER_FIRST_USER_USERNAME</code> |

Specifies a username to use if creating the first user for the deployment.

### --use-token-as-session

| | |
| ---- | ----------------- |
| Type | <code>bool</code> |

By default, the CLI will generate a new session token when logging in. This flag will instead use the provided token as the session token.