Skip to content

Commit f23459e

Browse files
appleboyclaude
andauthored
chore(deps): upgrade sdk-go to v0.2.0 (credstore API) (#14)
- Bump github.com/go-authgate/sdk-go to v0.2.0; update Go version (1.24.2 → 1.25.0) and transitive dependencies - Migrate from sdk-go/tokenstore to sdk-go/credstore throughout: - tui/types.go: TokenStorage aliases credstore.Token - main.go: tokenStore typed as credstore.Store[credstore.Token]; initTokenStore updated to credstore constructors - Save/Load call sites updated to new generic API signatures (Save takes explicit clientID + value, Load returns value not pointer) - Update tests: credstore.NewTokenFileStore, Save/Load signatures, type assertions updated to generic credstore concrete types - Document TOKEN_STORE env var in .env.example Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent bf0831b commit f23459e

6 files changed

Lines changed: 55 additions & 35 deletions

File tree

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ SCOPE=read write
1919

2020
# Token storage
2121
TOKEN_FILE=.authgate-tokens.json
22+
# Token storage backend: auto (default), file, keyring
23+
# auto = use OS keyring if available, fallback to TOKEN_FILE
24+
TOKEN_STORE=auto

go.mod

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
module github.com/go-authgate/oauth-cli
22

3-
go 1.24.2
3+
go 1.25.0
44

55
require (
66
charm.land/bubbles/v2 v2.0.0
77
charm.land/bubbletea/v2 v2.0.0
88
charm.land/lipgloss/v2 v2.0.0
99
github.com/appleboy/go-httpretry v0.11.0
10-
github.com/go-authgate/sdk-go v0.0.0-20260308143712-376f312901c8
10+
github.com/go-authgate/sdk-go v0.2.0
1111
github.com/google/uuid v1.6.0
1212
github.com/joho/godotenv v1.5.1
1313
)
1414

1515
require (
16-
al.essio.dev/pkg/shellescape v1.5.1 // indirect
16+
al.essio.dev/pkg/shellescape v1.6.0 // indirect
1717
github.com/charmbracelet/colorprofile v0.4.2 // indirect
1818
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 // indirect
1919
github.com/charmbracelet/x/ansi v0.11.6 // indirect
@@ -22,14 +22,14 @@ require (
2222
github.com/charmbracelet/x/windows v0.2.2 // indirect
2323
github.com/clipperhouse/displaywidth v0.11.0 // indirect
2424
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
25-
github.com/danieljoos/wincred v1.2.2 // indirect
26-
github.com/godbus/dbus/v5 v5.1.0 // indirect
25+
github.com/danieljoos/wincred v1.2.3 // indirect
26+
github.com/godbus/dbus/v5 v5.2.2 // indirect
2727
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
2828
github.com/mattn/go-runewidth v0.0.20 // indirect
2929
github.com/muesli/cancelreader v0.2.2 // indirect
3030
github.com/rivo/uniseg v0.4.7 // indirect
3131
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
3232
github.com/zalando/go-keyring v0.2.6 // indirect
3333
golang.org/x/sync v0.19.0 // indirect
34-
golang.org/x/sys v0.41.0 // indirect
34+
golang.org/x/sys v0.42.0 // indirect
3535
)

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXyho=
22
al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
3+
al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeXHA=
4+
al.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
35
charm.land/bubbles/v2 v2.0.0 h1:tE3eK/pHjmtrDiRdoC9uGNLgpopOd8fjhEe31B/ai5s=
46
charm.land/bubbles/v2 v2.0.0/go.mod h1:rCHoleP2XhU8um45NTuOWBPNVHxnkXKTiZqcclL/qOI=
57
charm.land/bubbletea/v2 v2.0.0 h1:p0d6CtWyJXJ9GfzMpUUqbP/XUUhhlk06+vCKWmox1wQ=
@@ -30,12 +32,18 @@ github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJ
3032
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
3133
github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0=
3234
github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8=
35+
github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ=
36+
github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs=
3337
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3438
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3539
github.com/go-authgate/sdk-go v0.0.0-20260308143712-376f312901c8 h1:cqsgCsNlvRew75W5gzXyzZcdzqpvwMxX2AizrnsT01M=
3640
github.com/go-authgate/sdk-go v0.0.0-20260308143712-376f312901c8/go.mod h1:ZRyXFKqO8HqWXIAqIwhjSxJ0DE3RckTVn9UtlX7MvJ8=
41+
github.com/go-authgate/sdk-go v0.2.0 h1:w22f+sAg/YMqnLOcS/4SAuMZXTbPurzkSQBsjb1hcbw=
42+
github.com/go-authgate/sdk-go v0.2.0/go.mod h1:RGqvrFdrPnOumndoQQV8qzu8zP1KFUZPdhX0IkWduho=
3743
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
3844
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
45+
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
46+
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
3947
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
4048
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
4149
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@@ -66,5 +74,7 @@ golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
6674
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
6775
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
6876
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
77+
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
78+
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
6979
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
7080
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

main.go

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
"time"
1919

2020
"github.com/go-authgate/oauth-cli/tui"
21-
"github.com/go-authgate/sdk-go/tokenstore"
21+
"github.com/go-authgate/sdk-go/credstore"
2222

2323
tea "charm.land/bubbletea/v2"
2424
retry "github.com/appleboy/go-httpretry"
@@ -36,7 +36,7 @@ var (
3636
scope string
3737
tokenFile string
3838
tokenStoreMode string
39-
tokenStore tokenstore.Store
39+
tokenStore credstore.Store[credstore.Token]
4040
configInitialized bool
4141
retryClient *retry.Client
4242
configWarnings []string
@@ -180,23 +180,24 @@ func initConfig() {
180180

181181
// initTokenStore creates a token store based on the given mode.
182182
// It returns the store, any warnings, and an error if the mode is invalid.
183-
func initTokenStore(mode, filePath, keyringService string) (tokenstore.Store, []string, error) {
184-
fileStore := tokenstore.NewFileStore(filePath)
183+
func initTokenStore(
184+
mode, filePath, keyringService string,
185+
) (credstore.Store[credstore.Token], []string, error) {
186+
fileStore := credstore.NewTokenFileStore(filePath)
185187
var warnings []string
186188

187189
switch mode {
188190
case "file":
189191
return fileStore, nil, nil
190192
case "keyring":
191-
return tokenstore.NewKeyringStore(keyringService), nil, nil
193+
return credstore.NewTokenKeyringStore(keyringService), nil, nil
192194
case "auto":
193-
kr := tokenstore.NewKeyringStore(keyringService)
194-
store := tokenstore.NewSecureStore(kr, fileStore)
195-
if !store.UseKeyring() {
195+
ss := credstore.DefaultTokenSecureStore(keyringService, filePath)
196+
if !ss.UseKeyring() {
196197
warnings = append(warnings,
197198
"OS keyring unavailable, falling back to file-based token storage")
198199
}
199-
return store, warnings, nil
200+
return ss, warnings, nil
200201
default:
201202
return nil, nil, fmt.Errorf(
202203
"invalid token-store value: %s (must be auto, file, or keyring)",
@@ -558,15 +559,19 @@ func main() {
558559

559560
deps := tui.Deps{
560561
LoadTokens: func() (*tui.TokenStorage, error) {
561-
return tokenStore.Load(clientID)
562+
tok, err := tokenStore.Load(clientID)
563+
if err != nil {
564+
return nil, err
565+
}
566+
return &tok, nil
562567
},
563568
RefreshToken: func(ctx context.Context, refreshToken string) (*tui.TokenStorage, string, error) {
564569
storage, err := refreshAccessToken(ctx, refreshToken)
565570
if err != nil {
566571
return nil, "", err
567572
}
568573
saveWarning := ""
569-
if saveErr := tokenStore.Save(storage); saveErr != nil {
574+
if saveErr := tokenStore.Save(storage.ClientID, *storage); saveErr != nil {
570575
saveWarning = fmt.Sprintf("Warning: Failed to save refreshed tokens: %v", saveErr)
571576
}
572577
return storage, saveWarning, nil
@@ -577,10 +582,12 @@ func main() {
577582
OpenBrowser: openBrowser,
578583
StartCallback: startCallbackServer,
579584
ExchangeCode: exchangeCode,
580-
SaveTokens: tokenStore.Save,
581-
VerifyToken: verifyToken,
582-
MakeAPICall: makeAPICallWithAutoRefresh,
583-
CallbackPort: callbackPort,
585+
SaveTokens: func(storage *tui.TokenStorage) error {
586+
return tokenStore.Save(storage.ClientID, *storage)
587+
},
588+
VerifyToken: verifyToken,
589+
MakeAPICall: makeAPICallWithAutoRefresh,
590+
CallbackPort: callbackPort,
584591
}
585592

586593
p := tea.NewProgram(

main_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"time"
77

88
"github.com/go-authgate/oauth-cli/tui"
9-
"github.com/go-authgate/sdk-go/tokenstore"
9+
"github.com/go-authgate/sdk-go/credstore"
1010
)
1111

1212
func TestValidateServerURL(t *testing.T) {
@@ -82,18 +82,18 @@ func TestValidateTokenResponse(t *testing.T) {
8282

8383
func TestSaveAndLoadTokens(t *testing.T) {
8484
// Use a non-existent path so FileStore starts fresh (empty file causes JSON parse error).
85-
store := tokenstore.NewFileStore(filepath.Join(t.TempDir(), "tokens.json"))
85+
store := credstore.NewTokenFileStore(filepath.Join(t.TempDir(), "tokens.json"))
8686
const testClientID = "test-client-id"
8787

88-
token := &tokenstore.Token{
88+
token := credstore.Token{
8989
AccessToken: "access-token-value",
9090
RefreshToken: "refresh-token-value",
9191
TokenType: "Bearer",
9292
ExpiresAt: time.Now().Add(time.Hour).UTC().Truncate(time.Second),
9393
ClientID: testClientID,
9494
}
9595

96-
if err := store.Save(token); err != nil {
96+
if err := store.Save(testClientID, token); err != nil {
9797
t.Fatalf("store.Save() error: %v", err)
9898
}
9999

@@ -114,11 +114,11 @@ func TestSaveAndLoadTokens(t *testing.T) {
114114
}
115115

116116
func TestSaveTokens_MultipleClients(t *testing.T) {
117-
store := tokenstore.NewFileStore(filepath.Join(t.TempDir(), "tokens-multi.json"))
117+
store := credstore.NewTokenFileStore(filepath.Join(t.TempDir(), "tokens-multi.json"))
118118

119119
// Save tokens for two different clients.
120120
for _, id := range []string{"client-a", "client-b"} {
121-
if err := store.Save(&tokenstore.Token{
121+
if err := store.Save(id, credstore.Token{
122122
AccessToken: "token-" + id,
123123
RefreshToken: "refresh-" + id,
124124
TokenType: "Bearer",
@@ -210,8 +210,8 @@ func TestInitTokenStore_File(t *testing.T) {
210210
if len(warnings) != 0 {
211211
t.Errorf("expected no warnings, got %v", warnings)
212212
}
213-
if _, ok := store.(*tokenstore.FileStore); !ok {
214-
t.Errorf("expected *tokenstore.FileStore, got %T", store)
213+
if _, ok := store.(*credstore.FileStore[credstore.Token]); !ok {
214+
t.Errorf("expected *credstore.FileStore[credstore.Token], got %T", store)
215215
}
216216
}
217217

@@ -227,8 +227,8 @@ func TestInitTokenStore_Keyring(t *testing.T) {
227227
if len(warnings) != 0 {
228228
t.Errorf("expected no warnings, got %v", warnings)
229229
}
230-
if _, ok := store.(*tokenstore.KeyringStore); !ok {
231-
t.Errorf("expected *tokenstore.KeyringStore, got %T", store)
230+
if _, ok := store.(*credstore.KeyringStore[credstore.Token]); !ok {
231+
t.Errorf("expected *credstore.KeyringStore[credstore.Token], got %T", store)
232232
}
233233
}
234234

@@ -241,9 +241,9 @@ func TestInitTokenStore_Auto(t *testing.T) {
241241
if err != nil {
242242
t.Fatalf("unexpected error: %v", err)
243243
}
244-
secureStore, ok := store.(*tokenstore.SecureStore)
244+
secureStore, ok := store.(*credstore.SecureStore[credstore.Token])
245245
if !ok {
246-
t.Fatalf("expected *tokenstore.SecureStore, got %T", store)
246+
t.Fatalf("expected *credstore.SecureStore[credstore.Token], got %T", store)
247247
}
248248
// In CI / test environments the OS keyring is typically unavailable,
249249
// so we expect the fallback warning. On systems with a keyring the

tui/types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ package tui
33
import (
44
"errors"
55

6-
"github.com/go-authgate/sdk-go/tokenstore"
6+
"github.com/go-authgate/sdk-go/credstore"
77
)
88

99
// ErrRefreshTokenExpired indicates the refresh token has expired or is invalid.
1010
var ErrRefreshTokenExpired = errors.New("refresh token expired or invalid")
1111

1212
// TokenStorage holds persisted OAuth tokens for one client.
13-
type TokenStorage = tokenstore.Token
13+
type TokenStorage = credstore.Token
1414

1515
// PKCEParams holds the code verifier and challenge for PKCE (RFC 7636).
1616
type PKCEParams struct {

0 commit comments

Comments
 (0)