nix-cache-login/cmd/logout.go

64 lines
1.6 KiB
Go
Raw Normal View History

2026-02-26 11:05:16 +01:00
package cmd
import (
"fmt"
"net/http"
"net/url"
"os"
"strings"
"github.com/spf13/cobra"
"guardianproject.dev/ops/nix-cache-login/internal/config"
"guardianproject.dev/ops/nix-cache-login/internal/netrc"
)
var logoutCmd = &cobra.Command{
Use: "logout",
Short: "Remove tokens and revoke session",
Long: `Removes the access token from the netrc file, deletes the stored
refresh token, and revokes the refresh token at Keycloak.`,
RunE: runLogout,
}
func init() {
rootCmd.AddCommand(logoutCmd)
}
func runLogout(cmd *cobra.Command, args []string) error {
// Read and revoke refresh token if it exists
rtPath := config.RefreshTokenPath()
if rtData, err := os.ReadFile(rtPath); err == nil && len(rtData) > 0 {
refreshToken := string(rtData)
// Revoke at Keycloak
revokeURL := strings.TrimSuffix(cfg.Issuer, "/") + "/protocol/openid-connect/revoke"
data := url.Values{
"token": {refreshToken},
"token_type_hint": {"refresh_token"},
"client_id": {cfg.ClientID},
}
resp, err := http.PostForm(revokeURL, data)
if err != nil {
fmt.Fprintf(os.Stderr, "Warning: could not revoke token at Keycloak: %v\n", err)
} else {
resp.Body.Close()
if resp.StatusCode >= 400 {
fmt.Fprintf(os.Stderr, "Warning: token revocation returned status %d\n", resp.StatusCode)
}
}
// Delete refresh token file
os.Remove(rtPath)
}
// Remove token from netrc
if err := netrc.Remove(cfg.NetrcPath, cfg.CacheHost); err != nil {
return fmt.Errorf("removing netrc entry: %w", err)
}
fmt.Fprintln(os.Stderr, "Logged out.")
return nil
}