auth

package
v1.0.17 Latest Latest
Warning

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

Go to latest
Published: Apr 27, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Overview

identity.go manages agent instance identification for tracking.

Each agent installation gets a unique agentId (UUID v4) that persists across version upgrades but regenerates on reinstall. This identity is transparently injected into MCP HTTP headers for gateway-side data collection.

Index

Constants

View Source
const (
	StatusPending   = "PENDING"
	StatusApproved  = "APPROVED"
	StatusRejected  = "REJECTED"
	StatusExpired   = "EXPIRED"
	StatusCancelled = "CANCELLED"
)

Device flow authorization status constants. Shared across device_flow.go and pat_auth_retry.go to avoid maintaining string literals in multiple places.

View Source
const (
	// AuthorizeURL is the DingTalk OAuth authorization page.
	AuthorizeURL = "https://login.dingtalk.com/oauth2/auth"

	// UserAccessTokenURL exchanges an authorization code for user tokens.
	UserAccessTokenURL = "https://api.dingtalk.com/v1.0/oauth2/userAccessToken"

	// UserInfoURL fetches the authenticated user's profile.
	UserInfoURL = "https://api.dingtalk.com/v1.0/contact/users/me"

	// DefaultClientID is the CLI's built-in OAuth client ID (DingTalk AppKey).
	// TODO: Replace <YOUR_CLIENT_ID> with your actual DingTalk AppKey before building.
	DefaultClientID = "<YOUR_CLIENT_ID>"

	// DefaultClientSecret is the CLI's built-in OAuth client secret (DingTalk AppSecret).
	// TODO: Replace <YOUR_CLIENT_SECRET> with your actual DingTalk AppSecret before building.
	DefaultClientSecret = "<YOUR_CLIENT_SECRET>"

	// CallbackPath is the localhost callback endpoint for OAuth redirect.
	CallbackPath = "/callback"

	// DefaultScopes are the OAuth scopes requested by the CLI.
	DefaultScopes = "openid corpid"

	// DefaultDeviceBaseURL is the login server base URL for device flow.
	DefaultDeviceBaseURL = "https://login.dingtalk.com"

	// DeviceCodePath requests a device_code and user_code.
	DeviceCodePath = "/oauth2/device/code.json"

	// DeviceTokenPath polls for authorization completion.
	DeviceTokenPath = "/oauth2/device/token.json"

	// DeviceGrantType is the grant_type value defined by RFC 8628.
	DeviceGrantType = "urn:ietf:params:oauth:grant-type:device_code"

	// Terminal API base URL for developer settings page.
	DefaultTerminalBaseURL = "https://open-dev.dingtalk.com"
	// DevicePollPath is the device flow polling path (used with MCP base URL).
	DevicePollPath = "/cli/oauth/device/poll"

	// DeveloperSettingsPath is the path to the organization developer settings page.
	DeveloperSettingsPath = "/fe/old#/developerSettings"

	LogoutURL         = "https://login.dingtalk.com/oauth2/logout"
	LogoutContinueURL = "https://login.dingtalk.com"

	// MCP API endpoints for CLI authorization management.
	DefaultMCPBaseURL    = "https://mcp.dingtalk.com"
	CLIAuthEnabledPath   = "/cli/cliAuthEnabled"
	SuperAdminPath       = "/cli/superAdmin"
	SendCliAuthApplyPath = "/cli/sendCliAuthApply"
	ClientIDPath         = "/cli/clientId"

	// MCP OAuth endpoints (used when clientId is fetched from MCP).
	MCPOAuthTokenPath   = "/oauth2/getToken"
	MCPRefreshTokenPath = "/oauth2/refreshToken"
	MCPRevokeTokenPath  = "/oauth2/revokeToken"
)

Variables

View Source
var ErrTokenDecryption = errors.New("token decryption failed")

ErrTokenDecryption indicates that token decryption failed, typically due to a device mismatch or corrupted data file. Callers can check this with errors.Is to distinguish decryption failures from other I/O or parsing errors.

View Source
var ValidSecretSources = map[string]bool{
	"file": true, "keychain": true,
}

ValidSecretSources is the set of recognized SecretRef sources.

Functions

func ClientID

func ClientID() string

ClientID returns the OAuth client ID with priority: 1. Runtime override (CLI flag --client-id) 2. Persisted app config (from previous login) 3. Environment variable (DWS_CLIENT_ID) 4. Default hardcoded value (if not a placeholder) Returns empty string if no valid client ID is available. Note: MCP server fetch (priority 4 in the full flow) is handled in OAuthProvider.Login()

func ClientSecret

func ClientSecret() string

ClientSecret returns the OAuth client secret with priority: 1. Runtime override (CLI flag --client-secret) 2. Persisted app config (from previous login, stored in keychain) 3. Environment variable (DWS_CLIENT_SECRET) 4. Default hardcoded value

func DeleteAppConfig added in v1.0.4

func DeleteAppConfig(configDir string) error

DeleteAppConfig removes the app configuration and associated keychain secrets.

func DeleteClientSecret added in v1.0.6

func DeleteClientSecret(clientID string) error

DeleteClientSecret removes the stored client secret for a specific client ID.

func DeleteSecureData

func DeleteSecureData(configDir string) error

DeleteSecureData removes .data file from configDir.

func DeleteTokenData

func DeleteTokenData(configDir string) error

DeleteTokenData removes token data. When an edition hook (DeleteToken) is registered, it delegates entirely to the hook; otherwise it falls back to keychain + legacy cleanup.

func DeleteTokenDataKeychain

func DeleteTokenDataKeychain() error

DeleteTokenDataKeychain removes TokenData from the platform keychain.

func DeleteTokenMarker added in v1.0.9

func DeleteTokenMarker(configDir string) error

DeleteTokenMarker removes the token.json marker file.

func EnsureMigration

func EnsureMigration(configDir string, logger *slog.Logger)

EnsureMigration performs one-time migration from legacy .data to keychain. This should be called early in the auth flow (e.g., during GetAccessToken). The migration is idempotent and thread-safe.

func FetchClientIDFromMCP added in v1.0.5

func FetchClientIDFromMCP(ctx context.Context) (string, error)

FetchClientIDFromMCP fetches the CLI client ID from MCP server. This is used when no client ID is provided via flags, config, or env vars. It retries up to mcpRequestMaxRetries times on transient errors.

func GetAppConfigPath added in v1.0.4

func GetAppConfigPath(configDir string) string

GetAppConfigPath returns the path to the app config file.

func GetDeveloperSettingsURL added in v1.0.11

func GetDeveloperSettingsURL() string

GetDeveloperSettingsURL returns the full URL to the organization developer settings page, derived from the terminal base URL.

func GetMCPBaseURL added in v1.0.5

func GetMCPBaseURL() string

GetMCPBaseURL returns the MCP base URL with priority: 1. ~/.dws/mcp_url file content (for pre-release environment) 2. Default value (https://mcp.dingtalk.com)

func GetRefreshTokenURL added in v1.0.5

func GetRefreshTokenURL() string

GetRefreshTokenURL returns the appropriate token refresh URL. Uses MCP endpoint when clientID is from MCP, otherwise uses direct DingTalk API.

func GetRevokeTokenURL added in v1.0.5

func GetRevokeTokenURL() string

GetRevokeTokenURL returns the token revocation URL (MCP only). Returns empty string if not using MCP mode.

func GetTerminalBaseURL added in v1.0.11

func GetTerminalBaseURL() string

GetTerminalBaseURL returns the terminal base URL with priority: 1. ~/.dws/terminal_url file content (for pre-release environment) 2. Default value (https://open-dev.dingtalk.com)

func GetUserAccessTokenURL added in v1.0.5

func GetUserAccessTokenURL() string

GetUserAccessTokenURL returns the appropriate token exchange URL. Uses MCP endpoint when clientID is from MCP, otherwise uses direct DingTalk API.

func HasAppConfig added in v1.0.4

func HasAppConfig(configDir string) bool

HasAppConfig returns true if an app configuration file exists.

func HasValidClientSecret added in v1.0.5

func HasValidClientSecret() bool

HasValidClientSecret returns true if a valid client secret is available. A valid secret is one that is not a placeholder (e.g., <YOUR_CLIENT_SECRET>).

func IsClientIDFromMCP added in v1.0.5

func IsClientIDFromMCP() bool

IsClientIDFromMCP returns true if the current clientID was fetched from MCP server.

func IsMigrationDone

func IsMigrationDone() bool

IsMigrationDone returns true if migration has been attempted.

func LoadClientSecret added in v1.0.6

func LoadClientSecret(clientID string) string

LoadClientSecret retrieves the stored client secret for a specific client ID. Returns empty string if not found.

func MarkAccessTokenStale added in v1.0.16

func MarkAccessTokenStale(configDir string) error

MarkAccessTokenStale loads the persisted TokenData, sets ExpiresAt to a past instant (preserving access_token and refresh_token), and writes it back. The next OAuthProvider.GetAccessToken call will see IsAccessTokenValid() == false and proceed to lockedRefresh, exchanging the refresh_token for a fresh access_token.

Use this only when the server has rejected the current access_token but the local expiry has not yet elapsed (zombie token scenario). It does not delete any token material and is safe to call concurrently — actual refresh is serialized by lockedRefresh's dual-layer locking.

Returns the original load error when there is no usable token on disk; a nil error when there is no access_token to invalidate (no-op).

func ParseDeviceFlowStatus added in v1.0.11

func ParseDeviceFlowStatus(rawStatus string, success bool) string

ParseDeviceFlowStatus normalizes a raw status string from the device flow poll response into a canonical status constant. When the server returns an empty status with success=false, it falls back to StatusExpired (server error / flow not found).

func RemoveSecretStore added in v1.0.4

func RemoveSecretStore(input SecretInput)

RemoveSecretStore cleans up keychain entries when an app is removed. Errors are intentionally ignored — cleanup is best-effort.

func ResolveAppCredentials added in v1.0.4

func ResolveAppCredentials(configDir string) (clientID, clientSecret string)

ResolveAppCredentials resolves the client ID and secret from the app config. Results are cached to avoid repeated keychain access. Returns empty strings if the config doesn't exist or resolution fails.

func ResolveSecret added in v1.0.4

func ResolveSecret(input SecretInput) (string, error)

ResolveSecret resolves a SecretInput to a plain string. SecretRef objects are resolved by source (file / keychain).

func RevokeTokenRemote

func RevokeTokenRemote(ctx context.Context) error

RevokeTokenRemote calls the appropriate logout/revoke endpoint to invalidate the access token. Uses MCP revoke endpoint when clientID is from MCP, otherwise uses DingTalk logout. This should be called before deleting local token data. The function is best-effort: errors are returned but callers may choose to ignore them.

func SaveAppConfig added in v1.0.4

func SaveAppConfig(configDir string, config *AppConfig) error

SaveAppConfig saves the app configuration to disk. If the client secret is a plain string, it will be stored in keychain and the config file will contain a reference to it.

func SaveClientSecret added in v1.0.6

func SaveClientSecret(clientID, clientSecret string) error

SaveClientSecret stores the client secret for a specific client ID. This is called during login to snapshot the credentials used.

func SaveSecureTokenData

func SaveSecureTokenData(configDir string, data *TokenData) error

SaveSecureTokenData encrypts and saves TokenData to .data file. The data is encrypted using AES-256-GCM with a key derived from the device MAC address. Uses atomic write (write .tmp then rename) to prevent corruption.

Concurrency: callers that involve token refresh MUST hold the business-level file lock (via acquireTokenLock) to prevent two processes from refreshing simultaneously. See OAuthProvider.lockedRefresh().

func SaveTokenData

func SaveTokenData(configDir string, data *TokenData) error

SaveTokenData persists TokenData. When an edition hook (SaveToken) is registered, it delegates entirely to the hook; otherwise it falls back to the default keychain-based storage.

func SaveTokenDataKeychain

func SaveTokenDataKeychain(data *TokenData) error

SaveTokenDataKeychain saves TokenData to the platform keychain. This is the new secure storage method using random master key.

func SecureDataExists

func SecureDataExists(configDir string) bool

SecureDataExists checks if the secure .data file exists in the given directory.

func SetClientID

func SetClientID(id string)

SetClientID allows runtime override of the client ID (e.g., from CLI flags).

func SetClientIDFromMCP added in v1.0.5

func SetClientIDFromMCP(id string)

SetClientIDFromMCP sets the clientID fetched from MCP server and marks it as MCP-sourced.

func SetClientSecret

func SetClientSecret(secret string)

SetClientSecret allows runtime override of the client secret (e.g., from CLI flags).

func TokenDataExistsKeychain

func TokenDataExistsKeychain() bool

TokenDataExistsKeychain checks if token data exists in keychain.

func WriteTokenMarker added in v1.0.9

func WriteTokenMarker(configDir string) error

WriteTokenMarker writes a token.json marker containing only an updated_at timestamp. The host application uses this file's presence and mtime to decide whether it needs to trigger a new auth exchange.

Types

type AppConfig added in v1.0.4

type AppConfig struct {
	ClientID     string      `json:"clientId"`
	ClientSecret SecretInput `json:"clientSecret"`
	CreatedAt    time.Time   `json:"createdAt"`
	UpdatedAt    time.Time   `json:"updatedAt,omitempty"`
}

AppConfig represents the application credentials configuration. This is stored in ~/.dws/app.json with the client secret securely stored in keychain.

func GetCachedAppConfig added in v1.0.4

func GetCachedAppConfig(configDir string) *AppConfig

GetCachedAppConfig returns the cached app configuration. It loads from disk on first call and caches the result. Returns nil if no configuration exists or loading fails.

func LoadAppConfig added in v1.0.4

func LoadAppConfig(configDir string) (*AppConfig, error)

LoadAppConfig loads the app configuration from disk. Returns nil, nil if the config file does not exist.

func ReloadAppConfig added in v1.0.4

func ReloadAppConfig(configDir string) (*AppConfig, error)

ReloadAppConfig forces a reload of the app configuration from disk. This should be called after SaveAppConfig to ensure the cache is updated.

type CLIAuthResult added in v1.0.11

type CLIAuthResult struct {
	CLIAuthEnabled       bool     `json:"cliAuthEnabled"`
	UserScope            string   `json:"userScope,omitempty"`            // "all" | "specified" | "forbidden"
	AllowedUsers         []string `json:"allowedUsers,omitempty"`         // staffId list when userScope="specified"
	ChannelScope         string   `json:"channelScope,omitempty"`         // "all" | "specified"
	AllowedChannels      []string `json:"allowedChannels,omitempty"`      // channelCode list when channelScope="specified"
	ChannelConfigEnabled bool     `json:"channelConfigEnabled,omitempty"` // whether org has any channel restriction configured
}

CLIAuthResult holds the business data returned by /cli/cliAuthEnabled. The server computes cliAuthEnabled by considering the org switch, userScope, and channelScope together; the CLI uses it as-is.

type CLIAuthStatus added in v1.0.5

type CLIAuthStatus struct {
	Success   bool           `json:"success"`
	ErrorCode string         `json:"errorCode,omitempty"`
	ErrorMsg  string         `json:"errorMsg,omitempty"`
	Result    *CLIAuthResult `json:"result"`
}

CLIAuthStatus represents the response from /cli/cliAuthEnabled API.

type ClientIDResponse added in v1.0.5

type ClientIDResponse struct {
	Success   bool   `json:"success"`
	ErrorCode string `json:"errorCode,omitempty"`
	ErrorMsg  string `json:"errorMsg,omitempty"`
	Result    string `json:"result"`
}

ClientIDResponse represents the response from /cli/clientId API.

type DeviceAuthResponse

type DeviceAuthResponse struct {
	DeviceCode              string `json:"deviceCode"`
	UserCode                string `json:"userCode"`
	VerificationURI         string `json:"verificationUri"`
	VerificationURIComplete string `json:"verificationUriComplete"`
	ExpiresIn               int    `json:"expiresIn"`
	Interval                int    `json:"interval"`
	FlowID                  string `json:"flowId"`
}

type DeviceFlowProvider

type DeviceFlowProvider struct {
	Output io.Writer
	// contains filtered or unexported fields
}

func NewDeviceFlowProvider

func NewDeviceFlowProvider(configDir string, logger *slog.Logger) *DeviceFlowProvider

func (*DeviceFlowProvider) Login

func (p *DeviceFlowProvider) Login(ctx context.Context) (*TokenData, error)

func (*DeviceFlowProvider) SetBaseURL

func (p *DeviceFlowProvider) SetBaseURL(baseURL string)

func (*DeviceFlowProvider) SetScope added in v1.0.11

func (p *DeviceFlowProvider) SetScope(scope string)

SetScope overrides the OAuth scope for the device flow.

func (*DeviceFlowProvider) SetTerminalBaseURL added in v1.0.11

func (p *DeviceFlowProvider) SetTerminalBaseURL(baseURL string)

SetTerminalBaseURL sets the terminal API base URL for device flow polling.

type DevicePollData added in v1.0.11

type DevicePollData struct {
	Status   string `json:"status"`
	AuthCode string `json:"authCode,omitempty"`
	FlowID   string `json:"flowId,omitempty"`
}

type DevicePollResponse added in v1.0.11

type DevicePollResponse struct {
	Success bool           `json:"success"`
	Code    string         `json:"code,omitempty"`
	Message string         `json:"message,omitempty"`
	Data    DevicePollData `json:"data"`
}

DevicePollResponse represents the response from the terminal API poll endpoint.

type DeviceTokenResponse

type DeviceTokenResponse struct {
	AuthCode    string `json:"authCode"`
	RedirectURL string `json:"redirectUrl"`
	Error       string `json:"error"`
}

type DualLock

type DualLock struct {
	Waited bool // true if we waited for another goroutine/process
	// contains filtered or unexported fields
}

DualLock holds both process-level and file-level locks.

func AcquireDualLock

func AcquireDualLock(ctx context.Context, configDir string) (*DualLock, error)

AcquireDualLock acquires both process-level and file-level locks. This provides comprehensive protection against: 1. Multiple goroutines in the same process (sync.Map) 2. Multiple CLI processes (file lock)

The caller MUST call Release() when done.

func (*DualLock) Release

func (d *DualLock) Release()

Release releases both locks in reverse order.

type Identity

type Identity struct {
	AgentID string `json:"agentId"` // UUID v4, generated at install time
	Source  string `json:"source"`  // data source, default "dws"
}

Identity holds the agent instance identification fields.

func EnsureExists

func EnsureExists(configDir string) *Identity

EnsureExists loads existing identity or creates a new one if not present.

func Load

func Load(configDir string) *Identity

Load reads the identity from <configDir>/identity.json. Returns nil if the file does not exist or cannot be parsed.

func (*Identity) Headers

func (id *Identity) Headers() map[string]string

Headers returns the identity as HTTP header key-value pairs.

type Manager

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

func NewManager

func NewManager(configDir string, logger *slog.Logger) *Manager

func (*Manager) DeleteToken

func (m *Manager) DeleteToken() error

func (*Manager) GetMCPURL

func (m *Manager) GetMCPURL() (string, error)

func (*Manager) GetToken

func (m *Manager) GetToken() (string, string, error)

func (*Manager) IsAuthenticated

func (m *Manager) IsAuthenticated() bool

func (*Manager) SaveMCPURL

func (m *Manager) SaveMCPURL(url string) error

func (*Manager) SaveToken

func (m *Manager) SaveToken(token string) error

func (*Manager) Status

func (m *Manager) Status() (authenticated bool, source string, maskedToken string)

type OAuthProvider

type OAuthProvider struct {
	Output io.Writer
	// contains filtered or unexported fields
}

OAuthProvider handles the DingTalk OAuth 2.0 authorization code flow.

func NewOAuthProvider

func NewOAuthProvider(configDir string, logger *slog.Logger) *OAuthProvider

NewOAuthProvider creates a new OAuth provider.

func (*OAuthProvider) CheckCLIAuthEnabled added in v1.0.5

func (p *OAuthProvider) CheckCLIAuthEnabled(ctx context.Context, accessToken string) (*CLIAuthStatus, error)

CheckCLIAuthEnabled checks if CLI authorization is enabled for the current corp. It retries up to mcpRequestMaxRetries times on transient errors to avoid false negatives caused by momentary network issues.

func (*OAuthProvider) ExchangeAuthCode

func (p *OAuthProvider) ExchangeAuthCode(ctx context.Context, authCode, uid string) (*TokenData, error)

ExchangeAuthCode takes an AuthCode and an optional UserID provided by an external host, exchanges it for tokens, and persists them.

func (*OAuthProvider) GetAccessToken

func (p *OAuthProvider) GetAccessToken(ctx context.Context) (string, error)

GetAccessToken returns a valid access token, auto-refreshing if needed. Uses a file lock with double-check pattern to prevent concurrent refresh from multiple CLI processes.

func (*OAuthProvider) Login

func (p *OAuthProvider) Login(ctx context.Context, force bool) (*TokenData, error)

Login performs authentication with smart degradation: 1. If force=false, try silent token refresh first (refresh_token) 2. If all silent methods fail (or force=true), fall back to browser OAuth flow

func (*OAuthProvider) Logout

func (p *OAuthProvider) Logout() error

Logout clears all stored credentials.

func (*OAuthProvider) Status

func (p *OAuthProvider) Status() (*TokenData, error)

Status returns the current auth status.

type SecretInput added in v1.0.4

type SecretInput struct {
	Plain string     // non-empty for plain string values
	Ref   *SecretRef // non-nil for SecretRef values
}

SecretInput represents a secret value: either a plain string or a SecretRef object.

func PlainSecret added in v1.0.4

func PlainSecret(s string) SecretInput

PlainSecret creates a SecretInput from a plain string.

func StoreSecret added in v1.0.4

func StoreSecret(clientID string, input SecretInput) (SecretInput, error)

StoreSecret stores a plain text secret in keychain and returns a SecretRef. If the input is already a SecretRef, it is returned as-is. Returns error if keychain is unavailable.

func (SecretInput) IsPlain added in v1.0.4

func (s SecretInput) IsPlain() bool

IsPlain returns true if this is a plain text string (not a SecretRef).

func (SecretInput) IsSecretRef added in v1.0.4

func (s SecretInput) IsSecretRef() bool

IsSecretRef returns true if this is a SecretRef object.

func (SecretInput) IsZero added in v1.0.4

func (s SecretInput) IsZero() bool

IsZero returns true if the SecretInput has no value.

func (SecretInput) MarshalJSON added in v1.0.4

func (s SecretInput) MarshalJSON() ([]byte, error)

MarshalJSON serializes SecretInput: plain string → JSON string, SecretRef → JSON object.

func (*SecretInput) UnmarshalJSON added in v1.0.4

func (s *SecretInput) UnmarshalJSON(data []byte) error

UnmarshalJSON deserializes SecretInput from either a JSON string or a SecretRef object.

type SecretRef added in v1.0.4

type SecretRef struct {
	Source string `json:"source"` // "keychain" | "file"
	ID     string `json:"id"`     // keychain key or file path
}

SecretRef references a secret stored externally.

type SendApplyResponse added in v1.0.5

type SendApplyResponse struct {
	Success   bool   `json:"success"`
	ErrorCode string `json:"errorCode,omitempty"`
	ErrorMsg  string `json:"errorMsg,omitempty"`
	Result    bool   `json:"result"`
}

SendApplyResponse represents the response from /cli/sendCliAuthApply API.

func SendCliAuthApply added in v1.0.5

func SendCliAuthApply(ctx context.Context, accessToken, adminStaffID string) (*SendApplyResponse, error)

SendCliAuthApply sends a CLI auth apply request to the specified admin. It retries up to mcpRequestMaxRetries times on transient errors.

type SuperAdmin added in v1.0.5

type SuperAdmin struct {
	StaffID string `json:"staffId"`
	Name    string `json:"name"`
}

SuperAdmin represents a corp super admin.

type SuperAdminResponse added in v1.0.5

type SuperAdminResponse struct {
	Success   bool         `json:"success"`
	ErrorCode string       `json:"errorCode,omitempty"`
	ErrorMsg  string       `json:"errorMsg,omitempty"`
	Result    []SuperAdmin `json:"result"`
}

SuperAdminResponse represents the response from /cli/superAdmin API.

func GetSuperAdmins added in v1.0.5

func GetSuperAdmins(ctx context.Context, accessToken string) (*SuperAdminResponse, error)

GetSuperAdmins fetches the list of corp super admins. It retries up to mcpRequestMaxRetries times on transient errors.

type TokenData

type TokenData struct {
	AccessToken    string    `json:"access_token"`
	RefreshToken   string    `json:"refresh_token"`
	PersistentCode string    `json:"persistent_code"`
	ExpiresAt      time.Time `json:"expires_at"`
	RefreshExpAt   time.Time `json:"refresh_expires_at"`
	CorpID         string    `json:"corp_id"`
	UserID         string    `json:"user_id,omitempty"`
	UserName       string    `json:"user_name,omitempty"`
	CorpName       string    `json:"corp_name,omitempty"`
	ClientID       string    `json:"client_id,omitempty"` // Associated app client ID for refresh
	UpdatedAt      string    `json:"updated_at,omitempty"`
	Source         string    `json:"source,omitempty"`
}

TokenData holds the OAuth token set persisted to disk.

func ExchangeCodeForToken added in v1.0.11

func ExchangeCodeForToken(ctx context.Context, configDir, code string) (*TokenData, error)

ExchangeCodeForToken exchanges an authorization code for token data using the currently configured client credentials. This is a convenience wrapper around OAuthProvider.exchangeCode for callers outside the auth package.

func LoadSecureTokenData

func LoadSecureTokenData(configDir string) (*TokenData, error)

LoadSecureTokenData decrypts and loads TokenData from .data file. Reads are safe without locking because SaveSecureTokenData uses atomic rename.

func LoadTokenData

func LoadTokenData(configDir string) (*TokenData, error)

LoadTokenData reads TokenData. When an edition hook (LoadToken) is registered, it delegates entirely to the hook; otherwise it falls back to keychain with legacy .data migration.

func LoadTokenDataKeychain

func LoadTokenDataKeychain() (*TokenData, error)

LoadTokenDataKeychain loads TokenData from the platform keychain.

func (*TokenData) HasPersistentCode

func (t *TokenData) HasPersistentCode() bool

HasPersistentCode returns true if a persistent code is available.

func (*TokenData) IsAccessTokenValid

func (t *TokenData) IsAccessTokenValid() bool

IsAccessTokenValid returns true if the access token has not expired.

func (*TokenData) IsRefreshTokenValid

func (t *TokenData) IsRefreshTokenValid() bool

IsRefreshTokenValid returns true if the refresh token has not expired.

type TokenMarker added in v1.0.9

type TokenMarker struct {
	UpdatedAt string `json:"updated_at"`
}

TokenMarker is a lightweight file the host application reads to detect whether the CLI has a valid token without accessing the keychain.

Jump to

Keyboard shortcuts

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