-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: store and use refresh token (#141)
* feat: save refresh token into kc * WIP * wip * feat: refresh token * cleanup parse payload * cleanup tenant * fix login vs refresh flow * document refresh * docs: auth readme * Update README.md
- Loading branch information
Showing
81 changed files
with
8,000 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Auth package | ||
|
||
The CLI authentication follows this approach: | ||
|
||
1. `$ auth0 login` uses **Auth0 Device Flow** to get an `acccess token` and a `refresh token` for the selected tenant. | ||
1. The access token is stored at the configuration file. | ||
1. The refresh token is stored at the OS keychain (supports macOS, Linux, and Windows thanks to https://github.com/zalando/go-keyring). | ||
1. During regular commands initialization, the access token is used to instantiate an Auth0 API client. | ||
- If the token is expired according to the value stored on the configuration file, a new one is requested using the refresh token. | ||
- In case of any error, the interactive login flow is triggered. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package auth | ||
|
||
import "github.com/zalando/go-keyring" | ||
|
||
type Keyring struct{} | ||
|
||
// Set sets the given key/value pair with the given namespace. | ||
func (k *Keyring) Set(namespace, key, value string) error { | ||
return keyring.Set(namespace, key, value) | ||
} | ||
|
||
// Get gets a value for the given namespace and key. | ||
func (k *Keyring) Get(namespace, key string) (string, error) { | ||
return keyring.Get(namespace, key) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package auth | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"net/url" | ||
) | ||
|
||
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 { | ||
Secrets SecretStore | ||
Client *http.Client | ||
} | ||
|
||
// 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, tenant string) (TokenResponse, error) { | ||
// get stored refresh token: | ||
refreshToken, err := t.Secrets.Get(secretsNamespace, tenant) | ||
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(oauthTokenEndpoint, url.Values{ | ||
"grant_type": {"refresh_token"}, | ||
"client_id": {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, _ := ioutil.ReadAll(r.Body) | ||
bodyStr := string(b) | ||
return TokenResponse{}, fmt.Errorf("cannot get a new access token from the refresh token: %s", bodyStr) | ||
} | ||
|
||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.