auth

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 4, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package auth provides keyring-based credential storage and OAuth token management.

Index

Constants

View Source
const (
	// PATClient is the client name used for PAT tokens in the keyring.
	PATClient = "pat"

	// PATEnvToken is the environment variable for the PAT.
	PATEnvToken = "HARVESTCLI_TOKEN"

	// PATEnvAccountID is the environment variable for the account ID.
	PATEnvAccountID = "HARVESTCLI_ACCOUNT_ID"
)

Variables

View Source
var ErrNotAuthenticated = errors.New("not authenticated")

ErrNotAuthenticated indicates no valid token is available.

View Source
var HarvestOAuthEndpoint = oauth2.Endpoint{
	AuthURL:  "https://id.getharvest.com/oauth2/authorize",
	TokenURL: "https://id.getharvest.com/api/v2/oauth2/token",
}

HarvestOAuthEndpoint is the Harvest OAuth2 endpoint.

Functions

func Authorize

func Authorize(ctx context.Context, creds *config.ClientCredentials, opts AuthorizeOptions) (email string, accountID int64, tok *oauth2.Token, err error)

Authorize performs OAuth authorization and returns the email, account ID, and token.

func DeletePAT

func DeletePAT(store Store, email string) error

DeletePAT removes a PAT from the keyring for the given email.

func GetAuthenticatedEmail

func GetAuthenticatedEmail(client string) (string, error)

GetAuthenticatedEmail returns the email for any authenticated account, optionally filtered by client name.

func GetPAT

func GetPAT(store Store, email string) (token string, accountID int64, err error)

GetPAT retrieves a PAT from the keyring for the given email.

func GetPATFromEnv

func GetPATFromEnv() (token string, accountID int64, ok bool)

GetPATFromEnv checks for HARVESTCLI_TOKEN and HARVESTCLI_ACCOUNT_ID environment variables. Returns token, accountID, ok.

func IsKeychainLockedError

func IsKeychainLockedError(msg string) bool

IsKeychainLockedError returns true if the error indicates the keychain is locked.

func ParseTokenKey

func ParseTokenKey(k string) (client, email string, ok bool)

ParseTokenKey parses a keyring key into client and email.

func SelectAccount

func SelectAccount(accounts []HarvestAccount) (int64, error)

SelectAccount prompts user to select an account if multiple exist. Returns the selected account ID.

func StorePAT

func StorePAT(store Store, email string, accountID int64, token string) error

StorePAT stores a PAT in the keyring for the given email/account.

func ValidatePAT

func ValidatePAT(ctx context.Context, token string, accountID int64) (email string, err error)

ValidatePAT validates a PAT by calling /users/me endpoint. Returns the user's email if valid.

Types

type AccountsResponse

type AccountsResponse struct {
	User struct {
		ID        int64  `json:"id"`
		FirstName string `json:"first_name"`
		LastName  string `json:"last_name"`
		Email     string `json:"email"`
	} `json:"user"`
	Accounts []HarvestAccount `json:"accounts"`
}

AccountsResponse is the response from /accounts endpoint.

func FetchAccounts

func FetchAccounts(ctx context.Context, tok *oauth2.Token) (*AccountsResponse, error)

FetchAccounts retrieves the user's Harvest accounts using the token.

type AuthorizeOptions

type AuthorizeOptions struct {
	Manual       bool          // Manual copy/paste flow instead of browser
	ForceConsent bool          // Force consent screen
	Timeout      time.Duration // Timeout for callback server
	Client       string        // OAuth client name
}

AuthorizeOptions configures the OAuth authorization flow.

type HarvestAccount

type HarvestAccount struct {
	ID      int64  `json:"id"`
	Name    string `json:"name"`
	Product string `json:"product"`
}

HarvestAccount represents a Harvest account from the accounts endpoint.

type KeyringStore

type KeyringStore struct {
	// contains filtered or unexported fields
}

KeyringStore implements Store using the system keyring.

func (*KeyringStore) DeleteToken

func (s *KeyringStore) DeleteToken(client, email string) error

DeleteToken removes a token from the keyring.

func (*KeyringStore) GetToken

func (s *KeyringStore) GetToken(client, email string) (Token, error)

GetToken retrieves a token from the keyring.

func (*KeyringStore) Keys

func (s *KeyringStore) Keys() ([]string, error)

Keys returns all keys in the keyring.

func (*KeyringStore) ListTokens

func (s *KeyringStore) ListTokens() ([]Token, error)

ListTokens returns all tokens in the keyring.

func (*KeyringStore) SetToken

func (s *KeyringStore) SetToken(client, email string, accountID int64, tok Token) error

SetToken stores a token in the keyring.

type PATTokenSource

type PATTokenSource struct {
	// contains filtered or unexported fields
}

PATTokenSource is a token source that uses a Personal Access Token. PATs don't expire and don't need refresh.

func NewPATTokenSource

func NewPATTokenSource(token string) *PATTokenSource

NewPATTokenSource creates a TokenSource from a Personal Access Token.

func (*PATTokenSource) Token

func (p *PATTokenSource) Token() (*oauth2.Token, error)

Token returns an oauth2.Token containing the PAT. PATs don't expire, so we set a far-future expiry.

type Store

type Store interface {
	Keys() ([]string, error)
	SetToken(client, email string, accountID int64, tok Token) error
	GetToken(client, email string) (Token, error)
	DeleteToken(client, email string) error
	ListTokens() ([]Token, error)
}

Store defines the interface for token storage.

func OpenDefault

func OpenDefault() (Store, error)

OpenDefault opens the keyring store with auto-detected backend.

func OpenWithBackend

func OpenWithBackend(backend string) (Store, error)

OpenWithBackend opens the keyring store with a specific backend.

type Token

type Token struct {
	Client       string    `json:"client,omitempty"`
	Email        string    `json:"email"`
	AccountID    int64     `json:"account_id"`
	Scopes       []string  `json:"scopes,omitempty"`
	CreatedAt    time.Time `json:"created_at,omitempty"`
	RefreshToken string    `json:"-"` // NEVER serialize to JSON/logs
}

Token represents stored authentication information. RefreshToken is stored separately in the keyring and never serialized to JSON.

type TokenSource

type TokenSource struct {
	// contains filtered or unexported fields
}

TokenSource provides OAuth2 tokens with lazy refresh on 401. Access tokens are kept in memory only; refresh tokens are stored in keyring.

func NewTokenSource

func NewTokenSource(store Store, client, email string, cfg *oauth2.Config) *TokenSource

NewTokenSource creates a new TokenSource for the given client and email.

func (*TokenSource) Invalidate

func (ts *TokenSource) Invalidate()

Invalidate marks the current access token as invalid. Forces a refresh on the next Token() call. Call this on 401 responses.

func (*TokenSource) Token

func (ts *TokenSource) Token() (*oauth2.Token, error)

Token returns a valid OAuth2 token, refreshing if necessary. Implements oauth2.TokenSource interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL