Skip to content

Commit 4c95c34

Browse files
committed
store token in keyring
1 parent 4c65c11 commit 4c95c34

File tree

3 files changed

+53
-12
lines changed

3 files changed

+53
-12
lines changed

cmd/src/login.go

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

33
import (
44
"context"
5+
"encoding/json"
56
"flag"
67
"fmt"
78
"io"
@@ -11,7 +12,10 @@ import (
1112

1213
"github.com/sourcegraph/src-cli/internal/api"
1314
"github.com/sourcegraph/src-cli/internal/cmderrors"
15+
"github.com/sourcegraph/src-cli/internal/keyring"
1416
"github.com/sourcegraph/src-cli/internal/oauthdevice"
17+
18+
"github.com/sourcegraph/sourcegraph/lib/errors"
1519
)
1620

1721
func init() {
@@ -125,16 +129,26 @@ func loginCmd(ctx context.Context, p loginParams) error {
125129
noToken := cfg.AccessToken == ""
126130
endpointConflict := endpointArg != cfg.Endpoint
127131

132+
secretStore, err := keyring.Open()
133+
if err != nil {
134+
printProblem(fmt.Sprintf("could not open keyring for secret storage: %s", err))
135+
}
136+
137+
cfg.Endpoint = endpointArg
138+
128139
if p.useDeviceFlow {
129-
token, err := runDeviceFlow(ctx, endpointArg, out, p.deviceFlowClient)
140+
resp, err := runDeviceFlow(ctx, endpointArg, out, p.deviceFlowClient)
130141
if err != nil {
131142
printProblem(fmt.Sprintf("Device flow authentication failed: %s", err))
132143
fmt.Fprintln(out, createAccessTokenMessage)
133144
return cmderrors.ExitCode1
134145
}
135146

136-
cfg.AccessToken = token
137-
cfg.Endpoint = endpointArg
147+
if err := oauthdevice.StoreToken(secretStore, &resp.Token); err != nil {
148+
printProblem(fmt.Sprintf("Failed to store token in keyring store: %s", err))
149+
return cmderrors.ExitCode1
150+
}
151+
138152
client = cfg.apiClient(p.apiFlags, out)
139153
} else if noToken || endpointConflict {
140154
fmt.Fprintln(out)
@@ -184,10 +198,13 @@ func loginCmd(ctx context.Context, p loginParams) error {
184198
return nil
185199
}
186200

187-
func runDeviceFlow(ctx context.Context, endpoint string, out io.Writer, client oauthdevice.Client) (string, error) {
201+
func storeToken(store *keyring.Store, token *oauthdevice.Token) error {
202+
}
203+
204+
func runDeviceFlow(ctx context.Context, endpoint string, out io.Writer, client oauthdevice.Client) (*oauthdevice.TokenResponse, error) {
188205
authResp, err := client.Start(ctx, endpoint, nil)
189206
if err != nil {
190-
return "", err
207+
return nil, err
191208
}
192209

193210
fmt.Fprintln(out)
@@ -207,8 +224,8 @@ func runDeviceFlow(ctx context.Context, endpoint string, out io.Writer, client o
207224

208225
tokenResp, err := client.Poll(ctx, endpoint, authResp.DeviceCode, interval, authResp.ExpiresIn)
209226
if err != nil {
210-
return "", err
227+
return nil, err
211228
}
212229

213-
return tokenResp.AccessToken, nil
230+
return tokenResp, nil
214231
}

internal/keyring/keyring.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@ import (
66
"github.com/sourcegraph/sourcegraph/lib/errors"
77
)
88

9-
const (
10-
serviceName = "sourcegraph-cli"
11-
12-
KeyOAuth = "oauth"
13-
)
9+
const serviceName = "sourcegraph-cli"
1410

1511
// Store provides secure credential storage operations.
1612
type Store struct {

internal/oauthdevice/device_flow.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"testing"
1414
"time"
1515

16+
"github.com/sourcegraph/src-cli/internal/keyring"
17+
1618
"github.com/sourcegraph/sourcegraph/lib/errors"
1719
)
1820

@@ -23,6 +25,9 @@ const (
2325
// wellKnownPath is the path on the sourcegraph server where clients can discover OAuth configuration
2426
wellKnownPath = "/.well-known/openid-configuration"
2527

28+
// Key used to store the token in the store
29+
KeyOAuth = "oauth"
30+
2631
GrantTypeDeviceCode string = "urn:ietf:params:oauth:grant-type:device_code"
2732

2833
ScopeOpenID string = "openid"
@@ -364,3 +369,26 @@ func (c *httpClient) Refresh(ctx context.Context, endpoint, refreshToken string)
364369
return &tokenResp, nil
365370
}
366371

372+
func StoreToken(store *keyring.Store, token *Token) error {
373+
data, err := json.Marshal(token)
374+
if err != nil {
375+
return errors.Wrap(err, "failed to marshal token")
376+
}
377+
378+
// TODO(burmudar): do we need a suffix that is the endpoint? ex. oauth-sourcegraph.com
379+
return store.Set(KeyOAuth, data)
380+
}
381+
382+
func LoadToken(store *keyring.Store) (*Token, error) {
383+
var t Token
384+
data, err := store.Get(KeyOAuth)
385+
if err != nil {
386+
return nil, errors.Wrap(err, "failed to get token from store")
387+
}
388+
389+
if err := json.Unmarshal(data, &t); err != nil {
390+
return nil, errors.Wrap(err, "failed to unmarshall token")
391+
}
392+
393+
return &t, nil
394+
}

0 commit comments

Comments
 (0)