Skip to content

Commit bc7f683

Browse files
committed
fix: store separate access token per profile
1 parent b63c9d4 commit bc7f683

File tree

4 files changed

+36
-20
lines changed

4 files changed

+36
-20
lines changed

internal/login/login_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestLoginCommand(t *testing.T) {
4040
Token: token,
4141
Fsys: afero.NewMemMapFs(),
4242
}))
43-
saved, err := credentials.StoreProvider.Get(utils.AccessTokenKey)
43+
saved, err := credentials.StoreProvider.Get(utils.CurrentProfile.Name)
4444
assert.NoError(t, err)
4545
assert.Equal(t, token, saved)
4646
})
@@ -83,7 +83,7 @@ func TestLoginCommand(t *testing.T) {
8383
expectedBrowserUrl := fmt.Sprintf("%s/cli/login?session_id=%s&token_name=%s&public_key=%s", utils.GetSupabaseDashboardURL(), sessionId, tokenName, publicKey)
8484
assert.Contains(t, out.String(), expectedBrowserUrl)
8585

86-
saved, err := credentials.StoreProvider.Get(utils.AccessTokenKey)
86+
saved, err := credentials.StoreProvider.Get(utils.CurrentProfile.Name)
8787
assert.NoError(t, err)
8888
assert.Equal(t, token, saved)
8989
assert.Empty(t, apitest.ListUnmatchedRequests())

internal/logout/logout_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func TestLogoutCommand(t *testing.T) {
3535

3636
t.Run("removes all Supabase CLI credentials", func(t *testing.T) {
3737
keyring.MockInit()
38-
require.NoError(t, credentials.StoreProvider.Set(utils.AccessTokenKey, token))
38+
require.NoError(t, credentials.StoreProvider.Set(utils.CurrentProfile.Name, token))
3939
require.NoError(t, credentials.StoreProvider.Set("project1", "password1"))
4040
require.NoError(t, credentials.StoreProvider.Set("project2", "password2"))
4141
t.Cleanup(fstest.MockStdin(t, "y"))
@@ -44,7 +44,7 @@ func TestLogoutCommand(t *testing.T) {
4444
// Check error
4545
assert.NoError(t, err)
4646
// Check that access token has been removed
47-
saved, _ := credentials.StoreProvider.Get(utils.AccessTokenKey)
47+
saved, _ := credentials.StoreProvider.Get(utils.CurrentProfile.Name)
4848
assert.Empty(t, saved)
4949
// check that project 1 has been removed
5050
saved, _ = credentials.StoreProvider.Get("project1")
@@ -56,14 +56,14 @@ func TestLogoutCommand(t *testing.T) {
5656

5757
t.Run("skips logout by default", func(t *testing.T) {
5858
keyring.MockInit()
59-
require.NoError(t, credentials.StoreProvider.Set(utils.AccessTokenKey, token))
59+
require.NoError(t, credentials.StoreProvider.Set(utils.CurrentProfile.Name, token))
6060
// Setup in-memory fs
6161
fsys := afero.NewMemMapFs()
6262
// Run test
6363
err := Run(context.Background(), os.Stdout, fsys)
6464
// Check error
6565
assert.ErrorIs(t, err, context.Canceled)
66-
saved, err := credentials.StoreProvider.Get(utils.AccessTokenKey)
66+
saved, err := credentials.StoreProvider.Get(utils.CurrentProfile.Name)
6767
assert.NoError(t, err)
6868
assert.Equal(t, token, saved)
6969
})

internal/utils/access_token.go

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package utils
22

33
import (
4+
"fmt"
45
"os"
56
"path/filepath"
67
"regexp"
@@ -32,12 +33,20 @@ func LoadAccessTokenFS(fsys afero.Fs) (string, error) {
3233
}
3334

3435
func loadAccessToken(fsys afero.Fs) (string, error) {
36+
logger := GetDebugLogger()
3537
// Env takes precedence
3638
if accessToken := os.Getenv("SUPABASE_ACCESS_TOKEN"); accessToken != "" {
39+
fmt.Fprintln(logger, "Using access token from env var...")
3740
return accessToken, nil
3841
}
39-
// Load from native credentials store
42+
// Load from current profile
43+
if accessToken, err := credentials.StoreProvider.Get(CurrentProfile.Name); err == nil {
44+
fmt.Fprintln(logger, "Using access token for profile:", CurrentProfile.Name)
45+
return accessToken, nil
46+
}
47+
// Load from legacy key for backwards compatibility
4048
if accessToken, err := credentials.StoreProvider.Get(AccessTokenKey); err == nil {
49+
fmt.Fprintln(logger, "Using access token from credentials store...")
4150
return accessToken, nil
4251
}
4352
// Fallback to token file
@@ -55,6 +64,7 @@ func fallbackLoadToken(fsys afero.Fs) (string, error) {
5564
} else if err != nil {
5665
return "", errors.Errorf("failed to read access token file: %w", err)
5766
}
67+
fmt.Fprintln(GetDebugLogger(), "Using access token from file:", path)
5868
return string(accessToken), nil
5969
}
6070

@@ -63,8 +73,10 @@ func SaveAccessToken(accessToken string, fsys afero.Fs) error {
6373
if !AccessTokenPattern.MatchString(accessToken) {
6474
return errors.New(ErrInvalidToken)
6575
}
66-
// Save to native credentials store
67-
if err := credentials.StoreProvider.Set(AccessTokenKey, accessToken); err == nil {
76+
// Save to current profile
77+
if err := credentials.StoreProvider.Set(CurrentProfile.Name, accessToken); err != nil {
78+
fmt.Fprintln(GetDebugLogger(), err)
79+
} else {
6880
return nil
6981
}
7082
// Fallback to token file
@@ -87,19 +99,20 @@ func fallbackSaveToken(accessToken string, fsys afero.Fs) error {
8799

88100
func DeleteAccessToken(fsys afero.Fs) error {
89101
// Always delete the fallback token file to handle legacy CLI
90-
if err := fallbackDeleteToken(fsys); err == nil {
91-
// Typically user system should only have either token file or keyring.
92-
// But we delete from both just in case.
93-
_ = credentials.StoreProvider.Delete(AccessTokenKey)
94-
return nil
95-
} else if !errors.Is(err, os.ErrNotExist) {
102+
if err := fallbackDeleteToken(fsys); err != nil && !errors.Is(err, os.ErrNotExist) {
96103
return err
97104
}
98-
// Fallback not found, delete from native credentials store
99-
err := credentials.StoreProvider.Delete(AccessTokenKey)
100-
if errors.Is(err, credentials.ErrNotSupported) || errors.Is(err, keyring.ErrNotFound) {
101-
return errors.New(ErrNotLoggedIn)
102-
} else if err != nil {
105+
// Always delete from legacy keyring
106+
if err := credentials.StoreProvider.Delete(AccessTokenKey); err != nil && !errors.Is(err, keyring.ErrNotFound) {
107+
fmt.Fprintln(GetDebugLogger(), err)
108+
}
109+
// Delete profile from native credentials store
110+
if err := credentials.StoreProvider.Delete(CurrentProfile.Name); err != nil {
111+
if errors.Is(err, credentials.ErrNotSupported) ||
112+
errors.Is(err, keyring.ErrUnsupportedPlatform) ||
113+
errors.Is(err, keyring.ErrNotFound) {
114+
return errors.New(ErrNotLoggedIn)
115+
}
103116
return errors.Errorf("failed to delete access token from keyring: %w", err)
104117
}
105118
return nil

internal/utils/access_token_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,16 @@ func TestDeleteToken(t *testing.T) {
166166
t.Run("deletes both keyring and fallback", func(t *testing.T) {
167167
token := string(apitest.RandomAccessToken(t))
168168
require.NoError(t, credentials.StoreProvider.Set(AccessTokenKey, token))
169+
require.NoError(t, credentials.StoreProvider.Set(CurrentProfile.Name, token))
169170
// Setup in-memory fs
170171
fsys := afero.NewMemMapFs()
171172
require.NoError(t, fallbackSaveToken(token, fsys))
172173
// Run test
173174
err := DeleteAccessToken(fsys)
174175
// Check error
175176
assert.NoError(t, err)
177+
_, err = credentials.StoreProvider.Get(CurrentProfile.Name)
178+
assert.ErrorIs(t, err, keyring.ErrNotFound)
176179
_, err = credentials.StoreProvider.Get(AccessTokenKey)
177180
assert.ErrorIs(t, err, keyring.ErrNotFound)
178181
path, err := getAccessTokenPath()

0 commit comments

Comments
 (0)