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
- Variables
- func ClientID() string
- func ClientSecret() string
- func DeleteSecureData(configDir string) error
- func DeleteTokenData(configDir string) error
- func LoadExportedCredentials(ctx context.Context, path, configDir string) (string, error)
- func RevokeTokenRemote(ctx context.Context) error
- func SaveSecureTokenData(configDir string, data *TokenData) error
- func SaveTokenData(configDir string, data *TokenData) error
- func SecureDataExists(configDir string) bool
- func SetClientID(id string)
- func SetClientSecret(secret string)
- type DeviceAuthResponse
- type DeviceFlowProvider
- type DeviceTokenResponse
- type ExportedCredentials
- type Identity
- type Manager
- func (m *Manager) DeleteToken() error
- func (m *Manager) GetMCPURL() (string, error)
- func (m *Manager) GetToken() (string, string, error)
- func (m *Manager) IsAuthenticated() bool
- func (m *Manager) SaveMCPURL(url string) error
- func (m *Manager) SaveToken(token string) error
- func (m *Manager) Status() (authenticated bool, source string, maskedToken string)
- type OAuthProvider
- func (p *OAuthProvider) ExchangeAuthCode(ctx context.Context, authCode, uid string) (*TokenData, error)
- func (p *OAuthProvider) GetAccessToken(ctx context.Context) (string, error)
- func (p *OAuthProvider) Login(ctx context.Context, force bool) (*TokenData, error)
- func (p *OAuthProvider) Logout() error
- func (p *OAuthProvider) Status() (*TokenData, error)
- type TokenData
Constants ¶
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" LogoutURL = "https://login.dingtalk.com/oauth2/logout" LogoutContinueURL = "https://login.dingtalk.com" )
Variables ¶
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.
Functions ¶
func ClientID ¶
func ClientID() string
ClientID returns the OAuth client ID with priority: 1. Runtime override (CLI flag --client-id) 2. Environment variable (DWS_CLIENT_ID) 3. Default hardcoded value
func ClientSecret ¶
func ClientSecret() string
ClientSecret returns the OAuth client secret with priority: 1. Runtime override (CLI flag --client-secret) 2. Environment variable (DWS_CLIENT_SECRET) 3. Default hardcoded value
func DeleteSecureData ¶
DeleteSecureData removes .data file from configDir.
func DeleteTokenData ¶
DeleteTokenData removes encrypted .data file from configDir.
func LoadExportedCredentials ¶ added in v1.0.0
func RevokeTokenRemote ¶
RevokeTokenRemote calls the DingTalk logout endpoint to invalidate the access token. 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 SaveSecureTokenData ¶
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 ¶
SaveTokenData encrypts and saves TokenData to .data file. Uses AES-256-GCM encryption with a key derived from device MAC address.
func SecureDataExists ¶
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 SetClientSecret ¶
func SetClientSecret(secret string)
SetClientSecret allows runtime override of the client secret (e.g., from CLI flags).
Types ¶
type DeviceAuthResponse ¶
type DeviceFlowProvider ¶
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)
type DeviceTokenResponse ¶
type ExportedCredentials ¶ added in v1.0.0
type ExportedCredentials struct {
RefreshToken string `json:"refresh_token,omitempty"`
PersistentCode string `json:"persistent_code,omitempty"`
CorpID string `json:"corp_id"`
UserID string `json:"user_id,omitempty"`
UserName string `json:"user_name,omitempty"`
CorpName string `json:"corp_name,omitempty"`
ExportedAt string `json:"exported_at"`
}
ExportedCredentials represents the JSON structure of an exported credentials file, used by auth import to restore credentials on another machine.
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 ¶
EnsureExists loads existing identity or creates a new one if not present.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
func (*Manager) DeleteToken ¶
func (*Manager) IsAuthenticated ¶
func (*Manager) SaveMCPURL ¶
type OAuthProvider ¶
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) 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 ¶
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 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"`
UpdatedAt string `json:"updated_at,omitempty"`
Source string `json:"source,omitempty"`
}
TokenData holds the OAuth token set persisted to disk.
func LoadSecureTokenData ¶
LoadSecureTokenData decrypts and loads TokenData from .data file. Reads are safe without locking because SaveSecureTokenData uses atomic rename.
func LoadTokenData ¶
LoadTokenData reads TokenData from encrypted .data file.
func (*TokenData) HasPersistentCode ¶
HasPersistentCode returns true if a persistent code is available.
func (*TokenData) IsAccessTokenValid ¶
IsAccessTokenValid returns true if the access token has not expired.
func (*TokenData) IsRefreshTokenValid ¶
IsRefreshTokenValid returns true if the refresh token has not expired.