mirror of
https://gitea.com/gitea/tea.git
synced 2026-03-13 09:13:30 +01:00
feat: store OAuth tokens in OS keyring via credstore (#926)
## Summary - Introduce `github.com/go-authgate/sdk-go/credstore` to store OAuth tokens securely in the OS keyring (macOS Keychain / Linux Secret Service / Windows Credential Manager), with automatic fallback to an encrypted JSON file - Add `AuthMethod` field to `Login` struct; new OAuth logins are marked `auth_method: oauth` and no longer write `token`/`refresh_token`/`token_expiry` to `config.yml` - Add `GetAccessToken()` / `GetRefreshToken()` / `GetTokenExpiry()` accessors that transparently read from credstore for OAuth logins, with fallback to YAML fields for legacy logins - Update all token reference sites across the codebase to use the new accessors - Non-OAuth logins (token, SSH) are completely unaffected; no migration of existing tokens ## Key files | File | Role | |------|------| | `modules/config/credstore.go` | **New** — credstore wrapper (Load/Save/Delete) | | `modules/config/login.go` | Login struct, token accessors, refresh logic | | `modules/auth/oauth.go` | OAuth flow, token creation / re-authentication | | `modules/api/client.go`, `cmd/login/helper.go`, `cmd/login/oauth_refresh.go` | Token reference updates | | `modules/task/pull_*.go`, `modules/task/repo_clone.go` | Git operation token reference updates | ## Test plan - [x] `go build ./...` compiles successfully - [x] `go test ./...` all tests pass - [x] `tea login add --oauth` completes OAuth flow; verify config.yml has `auth_method: oauth` but no token/refresh_token/token_expiry - [x] `tea repos ls` API calls work (token read from credstore) - [x] `tea login delete <name>` credstore token is also removed - [x] Existing non-OAuth logins continue to work unchanged 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://gitea.com/gitea/tea/pulls/926 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com> Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
This commit is contained in:
@@ -377,22 +377,17 @@ func createLoginFromToken(name, serverURL string, token *oauth2.Token, insecure
|
||||
}
|
||||
}
|
||||
|
||||
// Create login object
|
||||
// Create login object with OAuth auth method
|
||||
login := config.Login{
|
||||
Name: name,
|
||||
URL: serverURL,
|
||||
Token: token.AccessToken,
|
||||
RefreshToken: token.RefreshToken,
|
||||
Token: token.AccessToken, // temporarily set for Client() validation
|
||||
AuthMethod: config.AuthMethodOAuth,
|
||||
Insecure: insecure,
|
||||
VersionCheck: true,
|
||||
Created: time.Now().Unix(),
|
||||
}
|
||||
|
||||
// Set token expiry if available
|
||||
if !token.Expiry.IsZero() {
|
||||
login.TokenExpiry = token.Expiry.Unix()
|
||||
}
|
||||
|
||||
// Validate token by getting user info
|
||||
client := login.Client()
|
||||
u, _, err := client.GetMyUserInfo()
|
||||
@@ -400,6 +395,9 @@ func createLoginFromToken(name, serverURL string, token *oauth2.Token, insecure
|
||||
return fmt.Errorf("failed to validate token: %s", err)
|
||||
}
|
||||
|
||||
// Clear token from YAML fields (will be stored in credstore)
|
||||
login.Token = ""
|
||||
|
||||
// Set user info
|
||||
login.User = u.UserName
|
||||
|
||||
@@ -415,6 +413,11 @@ func createLoginFromToken(name, serverURL string, token *oauth2.Token, insecure
|
||||
return err
|
||||
}
|
||||
|
||||
// Save tokens to credstore
|
||||
if err := config.SaveOAuthToken(login.Name, token.AccessToken, token.RefreshToken, token.Expiry); err != nil {
|
||||
return fmt.Errorf("failed to save token to secure store: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Login as %s on %s successful. Added this login as %s\n", login.User, login.URL, login.Name)
|
||||
return nil
|
||||
}
|
||||
@@ -443,7 +446,11 @@ func ReauthenticateLogin(login *config.Login) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the existing login with new token data
|
||||
if login.IsOAuth() {
|
||||
return config.SaveOAuthTokenFromOAuth2(login.Name, token, login)
|
||||
}
|
||||
|
||||
// Legacy path for non-OAuth logins
|
||||
login.Token = token.AccessToken
|
||||
if token.RefreshToken != "" {
|
||||
login.RefreshToken = token.RefreshToken
|
||||
@@ -451,7 +458,5 @@ func ReauthenticateLogin(login *config.Login) error {
|
||||
if !token.Expiry.IsZero() {
|
||||
login.TokenExpiry = token.Expiry.Unix()
|
||||
}
|
||||
|
||||
// Save updated login
|
||||
return config.SaveLoginTokens(login)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user