// Package authclient provides an adapter for validating tokens via the auth-svc. package authclient import ( "context" "fmt" "net/http" "git.threesix.ai/jordan/sp4-v2-1770499323/pkg/httpclient" "git.threesix.ai/jordan/sp4-v2-1770499323/pkg/svc" "git.threesix.ai/jordan/sp4-v2-1770499323/services/chat-svc/internal/port" ) // compile-time check var _ port.AuthValidator = (*Client)(nil) // validateEnvelope matches the auth-svc response envelope: {data: ValidateResponse, meta: ...} type validateEnvelope struct { Data port.AuthUser `json:"data"` } // Client validates tokens by calling auth-svc's /validate endpoint. type Client struct { baseURL string httpClient *httpclient.Client } // New creates a new auth-svc client adapter. // Returns an error if AUTH_SVC_URL is not configured. func New() (*Client, error) { baseURL := svc.ServiceURL("auth-svc") if baseURL == "" { return nil, fmt.Errorf("auth-svc not configured (missing AUTH_SVC_URL env var)") } httpClient := httpclient.New(httpclient.Config{ MaxRetries: 3, CircuitBreaker: httpclient.NewCircuitBreaker(httpclient.DefaultCircuitBreakerConfig()), }) return &Client{ baseURL: baseURL, httpClient: httpClient, }, nil } // ValidateToken calls auth-svc's /validate endpoint with the given Bearer token. func (c *Client) ValidateToken(ctx context.Context, token string) (*port.AuthUser, error) { url := c.baseURL + "/api/auth-svc/validate" req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, nil) if err != nil { return nil, fmt.Errorf("create validate request: %w", err) } req.Header.Set("Authorization", "Bearer "+token) resp, err := c.httpClient.Do(req) if err != nil { return nil, fmt.Errorf("auth-svc request failed: %w", err) } envelope, err := svc.DecodeResponse[validateEnvelope](resp) if err != nil { return nil, fmt.Errorf("auth-svc validation failed: %w", err) } return &envelope.Data, nil }