Skip to content

Commit ccc55c8

Browse files
author
Ruben Hönle
authored
feat(auth): add get-access-token cmd (#598)
relates to STACKITCLI-11
1 parent ce2ad2b commit ccc55c8

File tree

7 files changed

+127
-6
lines changed

7 files changed

+127
-6
lines changed

docs/stackit_auth.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ stackit auth [flags]
3131

3232
* [stackit](./stackit.md) - Manage STACKIT resources using the command line
3333
* [stackit auth activate-service-account](./stackit_auth_activate-service-account.md) - Authenticates using a service account
34+
* [stackit auth get-access-token](./stackit_auth_get-access-token.md) - Prints a short-lived access token.
3435
* [stackit auth login](./stackit_auth_login.md) - Logs in to the STACKIT CLI
3536
* [stackit auth logout](./stackit_auth_logout.md) - Logs the user account out of the STACKIT CLI
3637

docs/stackit_auth_get-access-token.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
## stackit auth get-access-token
2+
3+
Prints a short-lived access token.
4+
5+
### Synopsis
6+
7+
Prints a short-lived access token which can be used e.g. for API calls.
8+
9+
```
10+
stackit auth get-access-token [flags]
11+
```
12+
13+
### Examples
14+
15+
```
16+
Print a short-lived access token
17+
$ stackit auth get-access-token
18+
```
19+
20+
### Options
21+
22+
```
23+
-h, --help Help for "stackit auth get-access-token"
24+
```
25+
26+
### Options inherited from parent commands
27+
28+
```
29+
-y, --assume-yes If set, skips all confirmation prompts
30+
--async If set, runs the command asynchronously
31+
-o, --output-format string Output format, one of ["json" "pretty" "none" "yaml"]
32+
-p, --project-id string Project ID
33+
--region string Target region for region-specific requests
34+
--verbosity string Verbosity of the CLI, one of ["debug" "info" "warning" "error"] (default "info")
35+
```
36+
37+
### SEE ALSO
38+
39+
* [stackit auth](./stackit_auth.md) - Authenticates the STACKIT CLI
40+

internal/cmd/auth/auth.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package auth
22

33
import (
44
activateserviceaccount "github.com/stackitcloud/stackit-cli/internal/cmd/auth/activate-service-account"
5+
getaccesstoken "github.com/stackitcloud/stackit-cli/internal/cmd/auth/get-access-token"
56
"github.com/stackitcloud/stackit-cli/internal/cmd/auth/login"
67
"github.com/stackitcloud/stackit-cli/internal/cmd/auth/logout"
78
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
@@ -27,4 +28,5 @@ func addSubcommands(cmd *cobra.Command, p *print.Printer) {
2728
cmd.AddCommand(login.NewCmd(p))
2829
cmd.AddCommand(logout.NewCmd(p))
2930
cmd.AddCommand(activateserviceaccount.NewCmd(p))
31+
cmd.AddCommand(getaccesstoken.NewCmd(p))
3032
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package getaccesstoken
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
6+
"github.com/stackitcloud/stackit-cli/internal/pkg/auth"
7+
cliErr "github.com/stackitcloud/stackit-cli/internal/pkg/errors"
8+
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
9+
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
10+
)
11+
12+
func NewCmd(p *print.Printer) *cobra.Command {
13+
cmd := &cobra.Command{
14+
Use: "get-access-token",
15+
Short: "Prints a short-lived access token.",
16+
Long: "Prints a short-lived access token which can be used e.g. for API calls.",
17+
Args: args.NoArgs,
18+
Example: examples.Build(
19+
examples.NewExample(
20+
`Print a short-lived access token`,
21+
"$ stackit auth get-access-token"),
22+
),
23+
RunE: func(_ *cobra.Command, _ []string) error {
24+
userSessionExpired, err := auth.UserSessionExpired()
25+
if err != nil {
26+
return err
27+
}
28+
if userSessionExpired {
29+
return &cliErr.SessionExpiredError{}
30+
}
31+
32+
accessToken, err := auth.GetAccessToken()
33+
if err != nil {
34+
return err
35+
}
36+
37+
accessTokenExpired, err := auth.TokenExpired(accessToken)
38+
if err != nil {
39+
return err
40+
}
41+
if accessTokenExpired {
42+
return &cliErr.AccessTokenExpiredError{}
43+
}
44+
45+
p.Info("%s\n", accessToken)
46+
return nil
47+
},
48+
}
49+
return cmd
50+
}

internal/pkg/auth/auth.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func AuthenticationConfig(p *print.Printer, reauthorizeUserRoutine func(p *print
3131
return nil, fmt.Errorf("authentication flow not set")
3232
}
3333

34-
userSessionExpired, err := userSessionExpired()
34+
userSessionExpired, err := UserSessionExpired()
3535
if err != nil {
3636
return nil, fmt.Errorf("check if user session expired: %w", err)
3737
}
@@ -42,7 +42,7 @@ func AuthenticationConfig(p *print.Printer, reauthorizeUserRoutine func(p *print
4242
if userSessionExpired {
4343
return nil, fmt.Errorf("session expired")
4444
}
45-
accessToken, err := getAccessToken()
45+
accessToken, err := GetAccessToken()
4646
if err != nil {
4747
return nil, fmt.Errorf("get service account access token: %w", err)
4848
}
@@ -73,7 +73,7 @@ func AuthenticationConfig(p *print.Printer, reauthorizeUserRoutine func(p *print
7373
return authCfgOption, nil
7474
}
7575

76-
func userSessionExpired() (bool, error) {
76+
func UserSessionExpired() (bool, error) {
7777
sessionExpiresAtString, err := GetAuthField(SESSION_EXPIRES_AT_UNIX)
7878
if err != nil {
7979
return false, fmt.Errorf("get %s: %w", SESSION_EXPIRES_AT_UNIX, err)
@@ -87,7 +87,7 @@ func userSessionExpired() (bool, error) {
8787
return now.After(sessionExpiresAt), nil
8888
}
8989

90-
func getAccessToken() (string, error) {
90+
func GetAccessToken() (string, error) {
9191
accessToken, err := GetAuthField(ACCESS_TOKEN)
9292
if err != nil {
9393
return "", fmt.Errorf("get %s: %w", ACCESS_TOKEN, err)

internal/pkg/auth/user_token_flow.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func (utf *userTokenFlow) RoundTrip(req *http.Request) (*http.Response, error) {
4444
}
4545

4646
accessTokenValid := false
47-
accessTokenExpired, err := tokenExpired(utf.accessToken)
47+
accessTokenExpired, err := TokenExpired(utf.accessToken)
4848
if err != nil {
4949
return nil, fmt.Errorf("check if access token has expired: %w", err)
5050
} else if !accessTokenExpired {
@@ -108,7 +108,7 @@ func reauthenticateUser(utf *userTokenFlow) error {
108108
return nil
109109
}
110110

111-
func tokenExpired(token string) (bool, error) {
111+
func TokenExpired(token string) (bool, error) {
112112
// We can safely use ParseUnverified because we are not authenticating the user at this point.
113113
// We're just checking the expiration time
114114
tokenParsed, _, err := jwt.NewParser().ParseUnverified(token, &jwt.RegisteredClaims{})

internal/pkg/errors/errors.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,22 @@ You can authenticate as a user by running:
3232
or use a service account by running:
3333
$ stackit auth activate-service-account`
3434

35+
SESSION_EXPIRED = `Session is expired. Please log in again first.
36+
37+
You can authenticate as a user by running:
38+
$ stackit auth login
39+
40+
or use a service account by running:
41+
$ stackit auth activate-service-account`
42+
43+
ACCESS_TOKEN_EXPIRED = `Access token is expired. Please log in again first.
44+
45+
You can authenticate as a user by running:
46+
$ stackit auth login
47+
48+
or use a service account by running:
49+
$ stackit auth activate-service-account`
50+
3551
FAILED_SERVICE_ACCOUNT_ACTIVATION = `could not setup authentication based on the provided service account credentials.
3652
Please double check if they are correctly configured.
3753
@@ -230,6 +246,18 @@ func (e *AuthError) Error() string {
230246
return FAILED_AUTH
231247
}
232248

249+
type SessionExpiredError struct{}
250+
251+
func (e *SessionExpiredError) Error() string {
252+
return SESSION_EXPIRED
253+
}
254+
255+
type AccessTokenExpiredError struct{}
256+
257+
func (e *AccessTokenExpiredError) Error() string {
258+
return ACCESS_TOKEN_EXPIRED
259+
}
260+
233261
type ActivateServiceAccountError struct{}
234262

235263
func (e *ActivateServiceAccountError) Error() string {

0 commit comments

Comments
 (0)