diff options
author | Martin Polden <mpolden@mpolden.no> | 2023-02-03 15:20:23 +0100 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2023-02-03 15:35:25 +0100 |
commit | e1e94812425a487069bf33f781bec987e9e49874 (patch) | |
tree | 4a892c3b5c0a7dee2cb76f9971e538cb4aba8a16 /client/go/internal/cli/auth/token.go | |
parent | a08ae588d6035b69f0961dff596fc871fd1c4e58 (diff) |
Re-organize Go code
Diffstat (limited to 'client/go/internal/cli/auth/token.go')
-rw-r--r-- | client/go/internal/cli/auth/token.go | 74 |
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 +} |