aboutsummaryrefslogtreecommitdiffstats
path: root/client/go/internal/cli/auth/token.go
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2023-02-03 15:20:23 +0100
committerMartin Polden <mpolden@mpolden.no>2023-02-03 15:35:25 +0100
commite1e94812425a487069bf33f781bec987e9e49874 (patch)
tree4a892c3b5c0a7dee2cb76f9971e538cb4aba8a16 /client/go/internal/cli/auth/token.go
parenta08ae588d6035b69f0961dff596fc871fd1c4e58 (diff)
Re-organize Go code
Diffstat (limited to 'client/go/internal/cli/auth/token.go')
-rw-r--r--client/go/internal/cli/auth/token.go74
1 files changed, 74 insertions, 0 deletions
diff --git a/client/go/internal/cli/auth/token.go b/client/go/internal/cli/auth/token.go
new file mode 100644
index 00000000000..d6f5e6dfa43
--- /dev/null
+++ b/client/go/internal/cli/auth/token.go
@@ -0,0 +1,74 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+package auth
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+type TokenResponse struct {
+ AccessToken string `json:"access_token"`
+ IDToken string `json:"id_token"`
+ TokenType string `json:"token_type"`
+ ExpiresIn int `json:"expires_in"`
+}
+
+type TokenRetriever struct {
+ Authenticator *Authenticator
+ Secrets SecretStore
+ Client *http.Client
+}
+
+// Delete deletes the given system from the secrets' storage.
+func (t *TokenRetriever) Delete(system string) error {
+ return t.Secrets.Delete(SecretsNamespace, system)
+}
+
+// Refresh gets a new access token from the provided refresh token,
+// The request is used the default client_id and endpoint for device authentication.
+func (t *TokenRetriever) Refresh(ctx context.Context, system string) (TokenResponse, error) {
+ // get stored refresh token:
+ refreshToken, err := t.Secrets.Get(SecretsNamespace, system)
+ if err != nil {
+ return TokenResponse{}, fmt.Errorf("cannot get the stored refresh token: %w", err)
+ }
+ if refreshToken == "" {
+ return TokenResponse{}, errors.New("cannot use the stored refresh token: the token is empty")
+ }
+ // get access token:
+ r, err := t.Client.PostForm(t.Authenticator.OauthTokenEndpoint, url.Values{
+ "grant_type": {"refresh_token"},
+ "client_id": {t.Authenticator.ClientID},
+ "refresh_token": {refreshToken},
+ })
+ if err != nil {
+ return TokenResponse{}, fmt.Errorf("cannot get a new access token from the refresh token: %w", err)
+ }
+
+ defer r.Body.Close()
+ if r.StatusCode != http.StatusOK {
+ b, _ := io.ReadAll(r.Body)
+ res := struct {
+ Description string `json:"error_description"`
+ }{}
+ if json.Unmarshal(b, &res) == nil {
+ return TokenResponse{}, errors.New(strings.ToLower(strings.TrimSuffix(res.Description, ".")))
+ }
+ return TokenResponse{}, fmt.Errorf("cannot get a new access token from the refresh token: %s", string(b))
+ }
+
+ var res TokenResponse
+ err = json.NewDecoder(r.Body).Decode(&res)
+ if err != nil {
+ return TokenResponse{}, fmt.Errorf("cannot decode response: %w", err)
+ }
+
+ return res, nil
+}