feat(oauth): Use keyring to store oauth token#1228
feat(oauth): Use keyring to store oauth token#1228burmudar merged 17 commits intowb/add-oauth-refresh-tokenfrom
Conversation
|
This change is part of the following stack: Change managed by git-spice. |
2f24f44 to
7f2c665
Compare
278fc77 to
6f58c79
Compare
7f2c665 to
87b5732
Compare
6f58c79 to
5a355f7
Compare
87b5732 to
abd0850
Compare
5a355f7 to
0f2e720
Compare
64897ef to
7978cce
Compare
| } | ||
|
|
||
| // Put stores a key-value pair in the keyring. | ||
| func (k *keyringStore) Put(key string, data []byte) error { |
There was a problem hiding this comment.
given the underlying library is all just global function calls, why don't we just do the same and wrap them with the service name we use?
There was a problem hiding this comment.
My main motivation to keep a struct is to avoid making Get / Put param lists be "a lot" e.g.
Put(ctx context.Context, endpoint, key string, data []byte)
Get(ctx context.Context, endpoint, key string)
We also centralize the store name to only happen once Open is called. Once it is open, the user doesn't have to keep extra context about the endpoint and can just use the store.
keegancsmith
left a comment
There was a problem hiding this comment.
My main concern is hitting libsecret/etc when we don't need to. But the underlying library looks good + we only open the keyring when doing oauth. So LGTM
- rename keyring to store - make keyring struct src-cli and set label on secret
- create token struct from TokenResponse - Token converts expiresIn to a timestamp - Store the token with the endpoint suffix - OAuth transport and use when available in api client
- Add secret store that supports different backends - We use a registry map for a few secrets and the registry gets persisted as one secret to the keyring. We don't waant to create a keyring secret for every different secret - Store is opened once to load the registry. - use secretStorage to store oauth tokens
Amp-Thread-ID: https://ampcode.com/threads/T-019bea47-5179-7418-86cf-bf1d4cc93d28 Co-authored-by: Amp <amp@ampcode.com> - minor keyring refactor
- use token.ClientID during refresh - best effort store refresh token
handle oauth discovery failure and set client id on token - use SRC CLI client id as default and handle discovery failures - add clientID flag and set it on the token improve error message and panic in apiClient if no usable token - warn if we fail to store the token on login - panic if apiClient has no accessToken or OAuth token to use
- remove delete operation - remove store interface
ba0344d to
e2d7bd2
Compare
abd0850 to
f79c981
Compare
- add mutex to guard concurrent changes of token - pull refreshing of token out into `refreshToken` - additional comments
e2d7bd2 to
e8795cb
Compare
* add refresh to oauthdevice.Client * oauthdevice: add RefreshToken field and Refresh method * feat(oauth): Use keyring to store oauth token (#1228) * add refresh to oauthdevice.Client * add OAuth Transport and use it if no access token * secrets: switch to zalando/go-keyring and add context support * secrets: scope keyring by endpoint
…Auth client (#1223) * removed unused func * add refresh token to device response unmarshall * make NewClient take ClientID as param * add oauth flow and use oauth token when SRC_ACCESS_TOKEN is empty * feat(oauth): Add refresh to oauthdevice.Client (#1227) * add refresh to oauthdevice.Client * oauthdevice: add RefreshToken field and Refresh method * feat(oauth): Use keyring to store oauth token (#1228) * add refresh to oauthdevice.Client * add OAuth Transport and use it if no access token * secrets: switch to zalando/go-keyring and add context support * secrets: scope keyring by endpoint
…Auth client (#1223) * removed unused func * add refresh token to device response unmarshall * make NewClient take ClientID as param * add oauth flow and use oauth token when SRC_ACCESS_TOKEN is empty * feat(oauth): Add refresh to oauthdevice.Client (#1227) * add refresh to oauthdevice.Client * oauthdevice: add RefreshToken field and Refresh method * feat(oauth): Use keyring to store oauth token (#1228) * add refresh to oauthdevice.Client * add OAuth Transport and use it if no access token * secrets: switch to zalando/go-keyring and add context support * secrets: scope keyring by endpoint (cherry picked from commit 0bc535e)
…Auth client (#1223) * removed unused func * add refresh token to device response unmarshall * make NewClient take ClientID as param * add oauth flow and use oauth token when SRC_ACCESS_TOKEN is empty * feat(oauth): Add refresh to oauthdevice.Client (#1227) * add refresh to oauthdevice.Client * oauthdevice: add RefreshToken field and Refresh method * feat(oauth): Use keyring to store oauth token (#1228) * add refresh to oauthdevice.Client * add OAuth Transport and use it if no access token * secrets: switch to zalando/go-keyring and add context support * secrets: scope keyring by endpoint (cherry picked from commit 0bc535e)
This adds a keyring which is used to store OAuth credentials. The OAuth credentials are retrieved from the keyring whenever there is no
SRC_ACCESS_TOKENdefined.When we use an OAuth token, we also add a OAuth transport which will automatically refresh the access token using the refresh token when it is near to expiring.
Credentials are stored in the keyring with under the service "Sourcegraph CLI" and with key "src:oauth:". The reason for the endpoint being in the key name is that some clients might access multiple sourcegraph instances like dev and prod, and we can't reuse the same credentials for the different servers.
Test plan
src login --oauth https://sourcegraph.sourcegraph.comexport SRC_ENDPOINT=https://sourcegraph.sourcegraph.com; echo 'query { currentUser { username } }' | go run ./cmd/src apiSourcegraph CLIapplication and rerun previous commandPlatforms tested