auth

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Mar 27, 2026 License: Apache-2.0 Imports: 23 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 (
	// 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

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.

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

func DeleteSecureData(configDir string) error

DeleteSecureData removes .data file from configDir.

func DeleteTokenData

func DeleteTokenData(configDir string) error

DeleteTokenData removes encrypted .data file from configDir.

func LoadExportedCredentials added in v1.0.0

func LoadExportedCredentials(ctx context.Context, path, configDir string) (string, error)

func RevokeTokenRemote

func RevokeTokenRemote(ctx context.Context) error

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

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 encrypts and saves TokenData to .data file. Uses AES-256-GCM encryption with a key derived from device MAC address.

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 SetClientSecret

func SetClientSecret(secret string)

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

Types

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"`
}

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)

type DeviceTokenResponse

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

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

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) 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 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

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 from encrypted .data file.

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.

Jump to

Keyboard shortcuts

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