auth

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 8, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package auth contains the SafeDep CLI's authentication flows. It owns the OAuth2 device-code login, the static API-key login, and the helpers that read and write credentials via dry/cloud's keychain.

Commands under internal/cmd/auth invoke these flows. Nothing else in the CLI talks to the keychain directly.

Index

Constants

View Source
const (

	// DefaultAPIKeyExpiryDays is the lifetime of API keys created by the
	// device-code login flow. Override with --api-key-expiry-days.
	DefaultAPIKeyExpiryDays = 90

	// gRPCAppName identifies our connections to SafeDep Cloud in logs.
	GRPCAppName = "safedep-cli"
)

Variables

View Source
var CLIScopes = []string{"offline_access", "openid", "profile", "email"}

CLIScopes are the OAuth scopes we request. offline_access is required to receive a refresh token.

Functions

func APIKeyName

func APIKeyName(hostname string, now time.Time) string

APIKeyName returns the human-readable name used when creating API keys from the device login flow. Stable enough for users to identify keys in the cloud UI. Unique enough to avoid collisions on repeated logins.

func AccessTokenExpiry

func AccessTokenExpiry(token string) (time.Time, error)

AccessTokenExpiry decodes the unverified `exp` claim of a JWT and returns it as a UTC time. Verification is the identity provider's job. We only need the expiry to drive UI hints and the "session expired" error path.

func Audience

func Audience() string

Audience returns the OAuth audience, honouring the env override.

func ClientID

func ClientID() string

ClientID returns the OAuth client ID, honouring the env override.

func DeviceCodeURL

func DeviceCodeURL() string

DeviceCodeURL returns the device-code endpoint, honouring the env override.

func IsExpired

func IsExpired(token string, now time.Time) bool

IsExpired reports whether the token's exp claim is in the past. Tokens without a parseable exp claim are treated as expired so callers fall through to a re-login path.

func SaveAPIKey

func SaveAPIKey(_ context.Context, store cloud.CredentialStore, in APIKeyInput) error

SaveAPIKey persists the API key + tenant to the provided keychain store. The store is expected to be already scoped to the active profile by the caller.

func TokenURL

func TokenURL() string

TokenURL returns the token endpoint, honouring the env override.

func VerifyAPIKey

func VerifyAPIKey(ctx context.Context, in APIKeyInput) error

VerifyAPIKey checks that the supplied API key + tenant authenticate against the SafeDep data plane. We connect and issue a low-cost RPC. A successful round trip means the key is valid for that tenant.

Types

type APIKeyInput

type APIKeyInput struct {
	APIKey string
	Tenant string
}

APIKeyInput is the data needed to persist an API-key credential.

type BootstrapInput

type BootstrapInput struct {
	AccessToken     string
	PreferredTenant string

	CreateAPIKey     bool
	APIKeyExpiryDays int
	APIKeyName       string
	Picker           TenantPicker

	// ConnFor is the control-plane connection builder. Optional. When
	// nil, the package-local default is used. Tests inject a fake.
	ConnFor ControlPlaneConnFunc
}

BootstrapInput captures everything PostOAuthBootstrap needs to provision a tenant and (optionally) an API key on top of a fresh access token.

type BootstrapResult

type BootstrapResult struct {
	Tenant          string
	APIKey          string
	APIKeyExpiresAt time.Time
}

BootstrapResult reports what the bootstrap step accomplished.

func PostOAuthBootstrap

func PostOAuthBootstrap(ctx context.Context, in BootstrapInput) (*BootstrapResult, error)

PostOAuthBootstrap completes the work that follows a successful device flow: discover accessible tenants, pick one, optionally create an API key. It does not write to the keychain. The caller does that, since the keychain store is owned by App.

type ControlPlaneConnFunc

type ControlPlaneConnFunc func(token, tenant string) (*grpc.ClientConn, error)

ControlPlaneConnFunc opens a control-plane gRPC connection for the supplied (token, tenant). tenant may be empty for the bootstrap call to GetUserInfo. Tests inject a fake here. Production callers leave it nil and the package-local default is used.

type DeviceFlowResult

type DeviceFlowResult struct {
	AccessToken  string
	RefreshToken string
}

DeviceFlowResult is the outcome of a successful OAuth2 device-code authorisation: the access + refresh token pair returned by the IdP.

func RunDeviceFlow

func RunDeviceFlow(ctx context.Context, sink DeviceFlowSink) (*DeviceFlowResult, error)

RunDeviceFlow performs a complete OAuth2 device-code authorisation against the configured SafeDep identity provider. It blocks until the user completes the flow in their browser or the IdP returns an error.

type DeviceFlowSink

type DeviceFlowSink func(verificationURL, userCode string)

DeviceFlowSink reports the verification URL and user code to the user. Implementations decide how to present them (TUI banner, opening a browser, etc.). The sink runs once before polling begins.

type Status

type Status struct {
	Profile        string
	Tenant         string
	APIKey         bool
	OAuth          bool
	OAuthExpiresAt time.Time
}

Status describes what credentials a profile currently holds.

func BuildStatus

func BuildStatus(_ context.Context, profile string, opts []cloud.KeychainOption) (Status, error)

BuildStatus inspects the keychain via two resolvers (one per credential type) and returns what the active profile holds. Missing-credentials errors are treated as "not configured" rather than failures.

type TenantPicker

type TenantPicker func(tenants []string) (string, error)

TenantPicker resolves the tenant when the user has access to multiple. Invoked only when len(tenants) > 1 and no preferred tenant matches.

Jump to

Keyboard shortcuts

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