Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"net/http"
"net/url"
"os"

retry "github.com/appleboy/go-httpretry"
"github.com/go-authgate/cli/tui"
Expand Down Expand Up @@ -94,7 +95,7 @@ func refreshAccessToken(
}

if err := cfg.Store.Save(cfg.ClientID, *storage); err != nil {
fmt.Printf("Warning: Failed to save refreshed tokens: %v\n", err)
fmt.Fprintf(os.Stderr, "Warning: Failed to save refreshed tokens: %v\n", err)
}
return storage, nil
}
Expand Down
2 changes: 1 addition & 1 deletion browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func openBrowser(ctx context.Context, url string) error {
case "darwin":
cmd = exec.CommandContext(ctx, "open", url)
case "windows":
cmd = exec.CommandContext(ctx, "cmd", "/c", "start", url)
cmd = exec.CommandContext(ctx, "rundll32", "url.dll,FileProtocolHandler", url)
Comment thread
appleboy marked this conversation as resolved.
Outdated
default:
cmd = exec.CommandContext(ctx, "xdg-open", url)
}
Expand Down
3 changes: 2 additions & 1 deletion config.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ func loadConfig() *AppConfig {
var err error
cfg.RetryClient, err = retry.NewBackgroundClient(retry.WithHTTPClient(baseHTTPClient))
if err != nil {
panic(fmt.Sprintf("failed to create retry client: %v", err))
fmt.Fprintf(os.Stderr, "Error: failed to create retry HTTP client: %v\n", err)
os.Exit(1)
Comment thread
appleboy marked this conversation as resolved.
}

// Resolve timeout configuration.
Expand Down
24 changes: 20 additions & 4 deletions token_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,14 @@ func revokeTokenOnServer(

if tok.RefreshToken != "" {
wg.Go(func() {
if err := doRevoke(ctx, cfg, revokeURL, tok.RefreshToken, timeout); err != nil {
if err := doRevoke(
ctx,
cfg,
revokeURL,
tok.RefreshToken,
"refresh_token",
timeout,
); err != nil {
mu.Lock()
refreshErr = err
mu.Unlock()
Expand All @@ -182,7 +189,14 @@ func revokeTokenOnServer(

if tok.AccessToken != "" {
wg.Go(func() {
if err := doRevoke(ctx, cfg, revokeURL, tok.AccessToken, timeout); err != nil {
if err := doRevoke(
ctx,
cfg,
revokeURL,
tok.AccessToken,
"access_token",
timeout,
); err != nil {
mu.Lock()
accessErr = err
mu.Unlock()
Expand Down Expand Up @@ -213,14 +227,16 @@ func doRevoke(
cfg *AppConfig,
revokeURL string,
token string,
tokenTypeHint string,
timeout time.Duration,
) error {
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

data := url.Values{
"token": {token},
"client_id": {cfg.ClientID},
"token": {token},
"token_type_hint": {tokenTypeHint},
"client_id": {cfg.ClientID},
}
Comment thread
appleboy marked this conversation as resolved.
Comment thread
appleboy marked this conversation as resolved.
Outdated
if !cfg.IsPublicClient() {
data.Set("client_secret", cfg.ClientSecret)
Expand Down
56 changes: 40 additions & 16 deletions token_cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,11 @@ func TestRunTokenDelete(t *testing.T) {

func TestRunTokenDelete_ServerRevocation(t *testing.T) {
t.Run("successful revocation and local delete", func(t *testing.T) {
var revokedTokens []string
type revokeCall struct {
token string
tokenTypeHint string
}
var revokeCalls []revokeCall
var mu sync.Mutex
srv := httptest.NewServer(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -115,7 +119,10 @@ func TestRunTokenDelete_ServerRevocation(t *testing.T) {
return
}
mu.Lock()
revokedTokens = append(revokedTokens, r.FormValue("token"))
revokeCalls = append(revokeCalls, revokeCall{
token: r.FormValue("token"),
tokenTypeHint: r.FormValue("token_type_hint"),
})
mu.Unlock()
w.WriteHeader(http.StatusOK)
}),
Expand Down Expand Up @@ -163,16 +170,24 @@ func TestRunTokenDelete_ServerRevocation(t *testing.T) {

mu.Lock()
defer mu.Unlock()
if len(revokedTokens) != 2 {
t.Fatalf("expected 2 revoke calls, got %d", len(revokedTokens))
if len(revokeCalls) != 2 {
t.Fatalf("expected 2 revoke calls, got %d", len(revokeCalls))
}
// Revocations run concurrently, so order is non-deterministic.
got := map[string]bool{revokedTokens[0]: true, revokedTokens[1]: true}
if !got["refresh-456"] {
t.Errorf("expected refresh token to be revoked, got %v", revokedTokens)
// Build a map from token to its type hint for assertion.
hintByToken := make(map[string]string, len(revokeCalls))
for _, c := range revokeCalls {
hintByToken[c.token] = c.tokenTypeHint
}
if hint, ok := hintByToken["refresh-456"]; !ok {
t.Errorf("expected refresh token to be revoked, got %v", revokeCalls)
} else if hint != "refresh_token" {
t.Errorf("refresh token_type_hint: got %q, want %q", hint, "refresh_token")
}
if !got["access-123"] {
t.Errorf("expected access token to be revoked, got %v", revokedTokens)
if hint, ok := hintByToken["access-123"]; !ok {
t.Errorf("expected access token to be revoked, got %v", revokeCalls)
} else if hint != "access_token" {
t.Errorf("access token_type_hint: got %q, want %q", hint, "access_token")
}
})

Expand Down Expand Up @@ -269,16 +284,22 @@ func TestRunTokenDelete_ServerRevocation(t *testing.T) {
})

t.Run("only access token no refresh token", func(t *testing.T) {
var revokedTokens []string
var mu sync.Mutex
var (
callCount int
gotToken string
gotTokenTypeHint string
mu sync.Mutex
)
srv := httptest.NewServer(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, "bad form", http.StatusBadRequest)
return
}
mu.Lock()
revokedTokens = append(revokedTokens, r.FormValue("token"))
callCount++
gotToken = r.FormValue("token")
gotTokenTypeHint = r.FormValue("token_type_hint")
mu.Unlock()
Comment thread
appleboy marked this conversation as resolved.
w.WriteHeader(http.StatusOK)
}),
Expand Down Expand Up @@ -319,11 +340,14 @@ func TestRunTokenDelete_ServerRevocation(t *testing.T) {

mu.Lock()
defer mu.Unlock()
if len(revokedTokens) != 1 {
t.Fatalf("expected 1 revoke call (access only), got %d", len(revokedTokens))
if callCount != 1 {
t.Fatalf("expected 1 revoke call (access only), got %d", callCount)
}
if gotToken != "access-only" {
t.Errorf("token: got %q, want %q", gotToken, "access-only")
}
if revokedTokens[0] != "access-only" {
t.Errorf("expected access token, got %q", revokedTokens[0])
if gotTokenTypeHint != "access_token" {
t.Errorf("token_type_hint: got %q, want %q", gotTokenTypeHint, "access_token")
}
})
}
Expand Down
Loading