Documentation
¶
Overview ¶
Package lfxv2 provides client configuration for LFX v2 API services.
Token Exchange ¶
The package supports automatic OAuth2 token exchange (RFC 8693) for converting MCP access tokens into LFX API tokens. Token exchange is performed per-request using tokens stored in the request context.
Usage in MCP Tools ¶
A single *Clients instance should be created once at startup (via NewClients) and shared across all tool invocations. Per-request, call WithMCPToken to attach the caller's MCP bearer token to the context before making LFX API calls:
func handleMyTool(ctx context.Context, req *mcp.CallToolRequest, args MyToolArgs) (*mcp.CallToolResult, any, error) {
// Extract raw MCP token from request.
mcpToken, err := lfxv2.ExtractMCPToken(req.Extra.TokenInfo)
if err != nil {
return nil, nil, err
}
// Attach token to context; the shared clients instance handles exchange.
ctx = sharedClients.WithMCPToken(ctx, mcpToken)
// Make API calls - token exchange and caching happen automatically.
result, err := sharedClients.Project.GetOneProjectBase(ctx, &projectservice.GetOneProjectBasePayload{})
// ...
}
Token Caching ¶
Exchanged tokens are cached per MCP token inside the long-lived *Clients instance to avoid redundant token-exchange round-trips on every request. The cache is goroutine-safe and automatically expires tokens with a fixed buffer of 5 minutes before their exp claim.
Package lfxv2 provides client utilities for interacting with LFX v2 APIs, including OAuth2 token exchange.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExtractMCPToken ¶
ExtractMCPToken extracts the raw MCP token from auth.TokenInfo.Extra. This token can be passed to WithMCPToken for use in LFX API calls. Returns an error if the token cannot be extracted.
For requests authenticated via a static API key (Extra["api_key_auth"]==true), the apiKeyMCPToken sentinel is returned so that the token-exchange layer uses the client_credentials grant rather than attempting to exchange a bearer token.
Types ¶
type ClientConfig ¶
type ClientConfig struct {
// APIDomain is the LFX API base domain.
APIDomain string
// HTTPClient is the HTTP client to use for API calls.
// If nil, a default client with 30s timeout will be created.
HTTPClient *http.Client
// TokenExchangeClient is the RFC 8693 OAuth2 token exchange client.
// If provided, the client will automatically exchange MCP tokens (from request context)
// for target API tokens.
TokenExchangeClient *TokenExchangeClient
// DebugLogger is used for debug-level HTTP request/response logging.
// If nil, debug logging is disabled.
DebugLogger *slog.Logger
}
ClientConfig holds configuration for LFX v2 API clients.
type Clients ¶
type Clients struct {
Committee *committeeservice.Client
MailingList *mailinglist.Client
Member *memberservice.Client
Project *projectservice.Client
QuerySvc *querysvc.Client
// contains filtered or unexported fields
}
Clients holds initialized LFX v2 API service clients.
func NewClients ¶
func NewClients(_ context.Context, cfg ClientConfig) (*Clients, error)
NewClients initializes and returns LFX v2 API service clients.
func (*Clients) WithMCPToken ¶ added in v0.4.6
WithMCPToken attaches mcpToken to ctx so the auth interceptor can retrieve it when forwarding requests to LFX APIs. Call this once per inbound request before invoking any LFX API method on the shared *Clients instance.
type TokenExchangeClient ¶
type TokenExchangeClient struct {
// contains filtered or unexported fields
}
TokenExchangeClient handles OAuth2 token exchange per RFC 8693.
func NewTokenExchangeClient ¶
func NewTokenExchangeClient(cfg TokenExchangeConfig) (*TokenExchangeClient, error)
NewTokenExchangeClient creates a new RFC 8693 token exchange client.
func (*TokenExchangeClient) ClientCredentials ¶ added in v0.4.1
func (c *TokenExchangeClient) ClientCredentials(ctx context.Context) (*TokenExchangeResponse, error)
ClientCredentials obtains an LFX API token using the client_credentials grant. This is used when the caller presents an M2M token, which Auth0 cannot exchange via RFC 8693 token exchange (it requires a user subject). Instead, the MCP server mints a fresh LFX token using its own client identity.
func (*TokenExchangeClient) ExchangeToken ¶
func (c *TokenExchangeClient) ExchangeToken(ctx context.Context, subjectToken string) (*TokenExchangeResponse, error)
ExchangeToken exchanges a subject token for a new access token per RFC 8693.
type TokenExchangeConfig ¶
type TokenExchangeConfig struct {
// TokenEndpoint is the OAuth2 token endpoint URL (e.g., "https://example.auth0.com/oauth/token").
TokenEndpoint string
// ClientID is the M2M client ID for token exchange.
ClientID string
// ClientSecret is the M2M client secret for token exchange.
// Ignored if ClientAssertionSigningKey is provided.
ClientSecret string
// ClientAssertionSigningKey is the PEM-encoded RSA private key for generating client assertions.
// If provided, this takes precedence over ClientSecret for client authentication.
// The key is used to sign a JWT assertion per RFC 7523.
ClientAssertionSigningKey string
// SubjectTokenType is the token type of the incoming subject token (e.g., LFX MCP API identifier).
SubjectTokenType string
// Audience is the target audience for the exchanged token (e.g., LFX V2 API identifier).
Audience string
// HTTPClient is the HTTP client to use for token exchange.
// If nil, a default client with 30s timeout will be created.
HTTPClient *http.Client
}
TokenExchangeConfig holds configuration for OAuth2 token exchange (RFC 8693).
type TokenExchangeResponse ¶
type TokenExchangeResponse struct {
AccessToken string `json:"access_token"`
IssuedTokenType string `json:"issued_token_type,omitempty"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
Scope string `json:"scope,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
}
TokenExchangeResponse represents the response from OAuth2 token exchange per RFC 8693.