credentials

package
v0.0.0-...-c7de752 Latest Latest
Warning

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

Go to latest
Published: Mar 4, 2026 License: Apache-2.0 Imports: 20 Imported by: 1

Documentation

Index

Constants

View Source
const (
	// DefaultCredentialsEnvVar is the environment variable checked for credentials.
	DefaultCredentialsEnvVar = "CARABINER_CREDENTIALS"

	// DefaultCredentialsFile is the filename for the default credentials file.
	DefaultCredentialsFile = "identity.json"

	// DefaultConfigDir is the subdirectory under os.UserConfigDir for carabiner config.
	DefaultConfigDir = "carabiner"

	// DefaultExchangeServer is the default deadrop exchange server URL.
	DefaultExchangeServer = "https://auth.carabiner.dev"
)
View Source
const DefaultLoginURL = "https://login.carabiner.dev"

DefaultLoginURL is the default login URL for the Carabiner login service.

View Source
const DefaultServer = "https://auth.carabiner.dev"

DefaultServer is the default deadrop exchange server URL.

View Source
const RenewalThreshold = 10 * time.Minute

RenewalThreshold is the time before expiry when a token should be renewed. If a token expires within this duration, it will be automatically renewed.

Variables

View Source
var ErrTokenExpired = fmt.Errorf("token is expired and cannot be renewed, please log in again")

ErrTokenExpired is returned when the token is expired and cannot be renewed.

Functions

func CleanAllExpiredTokens

func CleanAllExpiredTokens() (int, error)

CleanAllExpiredTokens removes expired tokens from all server sessions. Returns the total number of tokens removed.

func CleanExpiredTokens

func CleanExpiredTokens(serverURL string) (int, error)

CleanExpiredTokens removes all expired tokens from a server's token cache. Returns the number of tokens removed.

func DeleteExchangedToken

func DeleteExchangedToken(serverURL string, req *exchange.ExchangeRequest) error

DeleteExchangedToken removes a specific cached token.

func DeleteIdentity

func DeleteIdentity(serverURL string) error

DeleteIdentity removes the identity file for a specific server.

func DeleteSession

func DeleteSession(serverURL string) error

DeleteSession removes the entire session for a server, including its directory.

func GetConfigDir

func GetConfigDir() (string, error)

GetConfigDir returns the carabiner config directory path

func GetDefaultIdentityPath

func GetDefaultIdentityPath() (string, error)

GetDefaultIdentityPath returns the path to the default session's identity file

func GetSessionDir

func GetSessionDir(serverURL string) (string, error)

GetSessionDir returns the directory path for a server's session

func GetSessionIdentityPath

func GetSessionIdentityPath(serverURL string) (string, error)

GetSessionIdentityPath returns the path to the identity file for a server's session

func GetToken

func GetToken(ctx context.Context, audience ...string) (string, error)

GetToken is a convenience function for apps to get a token for a specific audience. It uses the default session's server and automatically handles caching and renewal.

Example usage:

token, err := credentials.GetToken(ctx, "https://api.example.com")
if err != nil {
    log.Fatal(err)
}
// Use token...

func GetTokenForServer

func GetTokenForServer(ctx context.Context, serverURL string, audience ...string) (string, error)

GetTokenForServer is like GetToken but allows specifying a specific server.

func GetTokenForServerWithOptions

func GetTokenForServerWithOptions(ctx context.Context, serverURL string, req *exchange.ExchangeRequest) (string, error)

GetTokenForServerWithOptions is like GetTokenWithOptions but allows specifying a specific server.

func GetTokenWithOptions

func GetTokenWithOptions(ctx context.Context, req *exchange.ExchangeRequest) (string, error)

GetTokenWithOptions is like GetToken but allows specifying full exchange options.

Example usage:

token, err := credentials.GetTokenWithOptions(ctx, &exchange.ExchangeRequest{
    Audience: []string{"https://api.example.com"},
    Scope:    []string{"read", "write"},
})

func GetTokensDir

func GetTokensDir(serverURL string) (string, error)

GetTokensDir returns the tokens directory path for a server's session.

func HashExchangeRequest

func HashExchangeRequest(req *exchange.ExchangeRequest) string

HashExchangeRequest generates a deterministic hash for an exchange request. This is used to create unique filenames for cached tokens. Only the Audience, Scope, and Resource fields are hashed.

func ListSessions

func ListSessions() (map[string]*SessionInfo, string, error)

ListSessions returns all configured sessions

func LoadDefaultIdentity

func LoadDefaultIdentity() (string, time.Time, error)

LoadDefaultIdentity loads the identity token from the default session.

func LoadExchangedToken

func LoadExchangedToken(serverURL string, req *exchange.ExchangeRequest) (string, time.Time, error)

LoadExchangedToken loads a cached exchanged token for a specific server and request. Returns the token and its expiry time if found and not expired.

func LoadExchangedTokenWithRenewal

func LoadExchangedTokenWithRenewal(ctx context.Context, serverURL string, req *exchange.ExchangeRequest) (string, time.Time, bool, error)

LoadExchangedTokenWithRenewal loads a cached exchanged token, automatically re-exchanging it if it's about to expire (within RenewalThreshold). Returns the token, expiry time, whether renewal was performed, and any error. This function opportunistically cleans up expired tokens with ~10% probability.

func LoadIdentity

func LoadIdentity(serverURL string) (string, time.Time, error)

LoadIdentity loads the identity token for a specific server. Returns the token and its expiry time if valid. This function does NOT perform auto-renewal. Use LoadIdentityWithRenewal for that.

func LoadIdentityWithRenewal

func LoadIdentityWithRenewal(ctx context.Context, serverURL string) (string, time.Time, bool, error)

LoadIdentityWithRenewal loads the identity token for a specific server, automatically renewing it if it's about to expire (within RenewalThreshold). Returns the token, expiry time, and whether renewal was performed.

func ResolveExchangeServer

func ResolveExchangeServer(override string) string

ResolveExchangeServer returns the exchange server URL to use. If override is non-empty it is returned directly. Otherwise the server URL from the default session is used. If no session exists, DefaultExchangeServer is returned.

func SaveExchangedToken

func SaveExchangedToken(serverURL string, req *exchange.ExchangeRequest, token string, expiresAt time.Time) error

SaveExchangedToken saves an exchanged token to the server's token cache.

func SaveIdentity

func SaveIdentity(serverURL, token string) error

SaveIdentity saves the identity token to the session-specific identity file for a server. This creates the session if it doesn't exist.

func SetDefaultSession

func SetDefaultSession(serverURL string) error

SetDefaultSession sets the default session to the specified server

Types

type CachedToken

type CachedToken struct {
	Token     string                    `json:"token"`
	ExpiresAt time.Time                 `json:"expires_at"`
	Spec      *exchange.ExchangeRequest `json:"spec"`
}

CachedToken represents an exchanged token stored on disk.

type ChainedTokenSource

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

ChainedTokenSource tries multiple TokenSources in order until one succeeds.

func NewChainedTokenSource

func NewChainedTokenSource(sources ...TokenSource) *ChainedTokenSource

NewChainedTokenSource creates a TokenSource that tries each source in order. The first source that returns a valid token is used.

func (*ChainedTokenSource) Token

func (c *ChainedTokenSource) Token(ctx context.Context) (string, error)

type EnvTokenSource

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

EnvTokenSource reads a token from an environment variable.

func DefaultEnvTokenSource

func DefaultEnvTokenSource() *EnvTokenSource

DefaultEnvTokenSource returns a TokenSource that reads from the CARABINER_CREDENTIALS environment variable.

func NewEnvTokenSource

func NewEnvTokenSource(envVar string) *EnvTokenSource

NewEnvTokenSource creates a TokenSource that reads from an environment variable.

func (*EnvTokenSource) Token

func (e *EnvTokenSource) Token(_ context.Context) (string, error)

type FileTokenSource

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

FileTokenSource reads a token from a file. The file is read on each call to Token(), allowing for external token rotation.

func DefaultFileTokenSource

func DefaultFileTokenSource() (*FileTokenSource, error)

DefaultFileTokenSource returns a TokenSource that reads from the default session's identity file. If no session exists, falls back to the legacy path at os.UserConfigDir()/carabiner/identity.json.

func NewFileTokenSource

func NewFileTokenSource(path string) *FileTokenSource

NewFileTokenSource creates a TokenSource that reads from a file. The file should contain a JWT token (whitespace is trimmed).

func ServerFileTokenSource

func ServerFileTokenSource(serverURL string) (*FileTokenSource, error)

ServerFileTokenSource returns a TokenSource that reads from a specific server's session identity file.

func (*FileTokenSource) Token

func (f *FileTokenSource) Token(_ context.Context) (string, error)

type Manager

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

Manager manages credential sessions by handling token lifecycle. It uses a central identity token source to exchange for short lived audience-specific tokens.

func NewManager

func NewManager(ctx context.Context, opts ...Option) (*Manager, error)

NewManager creates a new credential manager.

Use WithTokenSource to configure the central identity token source(s). If no sources are provided, the manager uses the default sources:

  1. CARABINER_CREDENTIALS environment variable
  2. os.UserConfigDir()/carabiner/identity.json

Use WithServer to configure the deadrop exchange server URL.

func (*Manager) Close

func (m *Manager) Close() error

Close stops all background refresh goroutines and releases resources.

func (*Manager) Register

func (m *Manager) Register(ctx context.Context, id string, req *exchange.ExchangeRequest) error

Register adds a new exchange request and immediately exchanges a token.

The id is used to retrieve the token later via Token() or TokenSource().

func (*Manager) Token

func (m *Manager) Token(ctx context.Context, id string) (string, error)

Token returns the token for the given id. If the token is expired or about to expire, it will be refreshed.

func (*Manager) TokenSource

func (m *Manager) TokenSource(id string) (TokenSource, error)

TokenSource returns a TokenSource for the given id.

type Option

type Option func(*Manager)

Option is a functional option for configuring the Manager.

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient sets a custom HTTP client for the exchange client.

func WithMaxRetries

func WithMaxRetries(retries int) Option

WithMaxRetries sets the maximum number of retry attempts for token exchange. Default is 5.

func WithRefreshBuffer

func WithRefreshBuffer(buffer float64) Option

WithRefreshBuffer sets the refresh buffer as a fraction of token lifetime. For example, 0.2 means refresh when 20% of the token lifetime remains (i.e., at 80% of the way through the token's validity period). Default is 0.2.

func WithRetryInterval

func WithRetryInterval(interval time.Duration) Option

WithRetryInterval sets the initial retry interval for exponential backoff. Default is 1 second.

func WithServer

func WithServer(server string) Option

WithServer sets the deadrop exchange server URL.

func WithTokenSource

func WithTokenSource(sources ...TokenSource) Option

WithTokenSource adds one or more TokenSources for the central identity token. Multiple sources are tried in order until one succeeds. If no sources are provided via this option, the Manager uses the default sources: 1. CARABINER_CREDENTIALS environment variable 2. os.UserConfigDir()/carabiner/identity.json

type ServerOptions

type ServerOptions struct {
	// Server is the deadrop exchange server URL.
	Server string

	// Prefix is an optional prefix for flag names (e.g., "deadrop" -> "--deadrop-server").
	Prefix string

	// Audience is the default audience for token exchange.
	Audience []string

	// DisablePersistence disables token caching to disk.
	DisablePersistence bool
}

ServerOptions is an ServerOptionsSet for configuring deadrop credentials in CLI tools. It provides the --server flag and methods to obtain TokenSource instances for specific audiences.

Example usage in a CLI tool:

type MyServerOptions struct {
    credentials.ServerOptions
    // other options...
}

func (o *MyServerOptions) AddFlags(cmd *cobra.Command) {
    o.ServerOptions.AddFlags(cmd)
    // add other flags...
}

// In command handler:
source, err := opts.TokenSource(ctx)
if err != nil {
    return err
}
token, err := source.Token(ctx)

Example with prefix and audience:

opts := credentials.NewServerOptions(
    credentials.WithPrefix("deadrop"),
    credentials.WithAudience("https://api.example.com"),
)

func NewServerOptions

func NewServerOptions(opts ...ServerOptionsOption) *ServerOptions

NewServerOptions creates a new ServerOptions with default values. Use functional options to customize the configuration.

Examples:

// Default options
opts := credentials.NewServerOptions()

// With prefix
opts := credentials.NewServerOptions(credentials.WithPrefix("deadrop"))

// With prefix and audience
opts := credentials.NewServerOptions(
    credentials.WithPrefix("deadrop"),
    credentials.WithAudience("https://api.example.com"),
)

func (*ServerOptions) AddFlags

func (o *ServerOptions) AddFlags(cmd *cobra.Command)

AddFlags adds the deadrop credential flags to the command.

func (*ServerOptions) Config

func (o *ServerOptions) Config() *command.OptionsSetConfig

Config returns the OptionsSetConfig for this options set.

func (*ServerOptions) Manager

func (o *ServerOptions) Manager(ctx context.Context) (*Manager, error)

Manager returns a new credentials Manager configured with these options. The Manager provides more control over token lifecycle than TokenSource.

Example:

mgr, err := opts.Manager(ctx)
if err != nil {
    return err
}
defer mgr.Close()

err = mgr.Register(ctx, "api", &exchange.ExchangeRequest{
    Audience: []string{"https://api.example.com"},
})
token, err := mgr.Token(ctx, "api")

func (*ServerOptions) TokenSource

func (o *ServerOptions) TokenSource(ctx context.Context, audience ...string) (TokenSource, error)

TokenSource returns a TokenSource for the given audience. If no audience is provided, uses the audience configured via WithAudience(). The returned TokenSource handles token exchange and automatic renewal.

Example:

// With audience specified at call time
source, err := opts.TokenSource(ctx, "https://api.example.com")

// Using preloaded audience from WithAudience()
opts := credentials.NewServerOptions(credentials.WithAudience("https://api.example.com"))
source, err := opts.TokenSource(ctx)

func (*ServerOptions) TokenSourceWithRequest

func (o *ServerOptions) TokenSourceWithRequest(ctx context.Context, req *exchange.ExchangeRequest) (TokenSource, error)

TokenSourceWithRequest returns a TokenSource for the given exchange request. This allows specifying additional exchange parameters like scope and resource.

Example:

source, err := opts.TokenSourceWithRequest(ctx, &exchange.ExchangeRequest{
    Audience: []string{"https://api.example.com"},
    Scope:    []string{"read", "write"},
})

func (*ServerOptions) Validate

func (o *ServerOptions) Validate() error

Validate validates the options.

type ServerOptionsOption

type ServerOptionsOption func(*ServerOptions)

ServerOptionsOption is a functional option for configuring ServerOptions.

func WithAudience

func WithAudience(audience ...string) ServerOptionsOption

WithAudience sets the default audience for token exchange. This can be overridden when calling TokenSource().

func WithDisablePersistence

func WithDisablePersistence() ServerOptionsOption

WithDisablePersistence disables token caching to disk.

func WithPrefix

func WithPrefix(prefix string) ServerOptionsOption

WithPrefix sets the flag prefix for the options. For example, WithPrefix("deadrop") results in flags like --deadrop-server.

type ServiceTokenSource

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

ServiceTokenSource is a TokenSource that exchanges the main Carabiner identity token for a service-specific token based on an ExchangeRequest. It manages the lifecycle of the exchanged token, automatically renewing it when less than 20% of its lifetime remains (configurable via WithServiceRefreshBuffer).

The ExchangeRequest serves as a template: its Audience, Scope, Resource, and token type fields are preserved, while SubjectToken is set automatically from the identity source on each exchange.

Example usage:

source, err := credentials.NewServiceTokenSource(
    &exchange.ExchangeRequest{
        Audience: []string{"https://api.example.com"},
    },
    "https://auth.carabiner.dev",
    credentials.WithServicePersistence(),
)
if err != nil {
    log.Fatal(err)
}
token, err := source.Token(ctx)

func NewServiceTokenSource

func NewServiceTokenSource(req *exchange.ExchangeRequest, serverURL string, opts ...ServiceTokenSourceOption) (*ServiceTokenSource, error)

NewServiceTokenSource creates a ServiceTokenSource that exchanges the main Carabiner identity for a service-specific token matching the given ExchangeRequest.

The request serves as a template: SubjectToken is ignored and set automatically from the identity source on each exchange. All other fields (Audience, Scope, Resource, SubjectTokenType, RequestedTokenType) are forwarded as-is.

The serverURL is the deadrop exchange server URL. Use options to configure identity source, persistence, and refresh behavior.

func (*ServiceTokenSource) Token

func (s *ServiceTokenSource) Token(ctx context.Context) (string, error)

Token returns a valid exchanged service token. If the current token has less than 20% of its lifetime remaining, it is automatically renewed in the background. If no valid token is available, a new exchange is performed synchronously.

type ServiceTokenSourceOption

type ServiceTokenSourceOption func(*ServiceTokenSource)

ServiceTokenSourceOption configures a ServiceTokenSource.

func WithServiceIdentitySource

func WithServiceIdentitySource(source TokenSource) ServiceTokenSourceOption

WithServiceIdentitySource overrides the default identity token source used to obtain the subject token for exchange.

func WithServicePersistence

func WithServicePersistence() ServiceTokenSourceOption

WithServicePersistence enables token persistence in the server's session directory. When enabled, exchanged tokens are cached to disk and loaded on subsequent calls, surviving process restarts.

func WithServiceRefreshBuffer

func WithServiceRefreshBuffer(buffer float64) ServiceTokenSourceOption

WithServiceRefreshBuffer sets the fraction of token lifetime remaining that triggers a renewal. Default is 0.2 (renew when 20% of lifetime remains).

type SessionInfo

type SessionInfo struct {
	Dir       string    `json:"dir"`
	CreatedAt time.Time `json:"created_at"`
	ServerURL string    `json:"server_url,omitempty"` // Stored for reference
}

SessionInfo holds information about a session for a specific server

func GetDefaultSession

func GetDefaultSession() (*SessionInfo, string, error)

GetDefaultSession returns the default session info, if any

func GetOrCreateSession

func GetOrCreateSession(serverURL string) (*SessionInfo, error)

GetOrCreateSession gets an existing session for a server or creates a new one

type SessionsConfig

type SessionsConfig struct {
	Sessions map[string]*SessionInfo `json:"sessions"`
	Default  string                  `json:"default,omitempty"`
}

SessionsConfig holds the mapping of servers to session directories

func LoadSessionsConfig

func LoadSessionsConfig() (*SessionsConfig, error)

LoadSessionsConfig loads the sessions configuration from disk

type StaticTokenSource

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

StaticTokenSource returns a fixed token. Useful for testing.

func NewStaticTokenSource

func NewStaticTokenSource(token string) *StaticTokenSource

NewStaticTokenSource creates a TokenSource that always returns the same token.

func (*StaticTokenSource) Token

func (s *StaticTokenSource) Token(_ context.Context) (string, error)

type TokenSource

type TokenSource interface {
	// Token returns a valid token or an error.
	Token(ctx context.Context) (string, error)
}

TokenSource is an interface for retrieving tokens, similar to oauth2.TokenSource.

func DefaultTokenSource

func DefaultTokenSource() (TokenSource, error)

DefaultTokenSource returns a ChainedTokenSource that tries: 1. CARABINER_CREDENTIALS environment variable 2. os.UserConfigDir()/carabiner/identity.json

Jump to

Keyboard shortcuts

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