mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: generate a new session with coder login --token (#8275)
* feat: coder login --token generates a new session Makes sure /logout does not delete the inputted token * flag to enable previous behavior if needed
This commit is contained in:
+32
-9
@@ -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()
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
})
|
||||
@@ -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!")
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+3
-1
@@ -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)
|
||||
@@ -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
@@ -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.
|
||||
|
||||
+4
-1
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user