auth

package
v1.13.1 Latest Latest
Warning

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

Go to latest
Published: Dec 24, 2025 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package auth provides authentication and authorization for Hector v2.

This package is ported from legacy Hector (pkg/auth) and adapted to work with a2a-go's CallInterceptor system for seamless integration.

Architecture

The auth package follows a layered approach:

  1. JWTValidator: Validates JWT tokens using JWKS (JSON Web Key Set)
  2. HTTP Middleware: Extracts and validates tokens from HTTP requests
  3. CallInterceptor: Bridges to a2a-go's authentication system

Usage

Configure authentication in your hector.yaml:

server:
  auth:
    enabled: true
    jwks_url: "https://auth.example.com/.well-known/jwks.json"
    issuer: "https://auth.example.com"
    audience: "hector-api"

The auth middleware will automatically validate JWT tokens and make claims available to agents via the invocation context.

Index

Constants

View Source
const (
	// ClaimsContextKey is the context key for storing validated claims.
	ClaimsContextKey contextKey = "hector_auth_claims"
)

Variables

View Source
var (
	// ErrUnauthorized is returned when authentication is required but not provided.
	ErrUnauthorized = errors.New("unauthorized: authentication required")

	// ErrForbidden is returned when the user lacks permission.
	ErrForbidden = errors.New("forbidden: insufficient permissions")

	// ErrInvalidToken is returned when a token cannot be validated.
	ErrInvalidToken = errors.New("invalid token")

	// ErrTokenExpired is returned when a token has expired.
	ErrTokenExpired = errors.New("token expired")

	// ErrMissingClaims is returned when required claims are missing.
	ErrMissingClaims = errors.New("missing required claims")
)

Common authentication errors.

Functions

func ContextWithClaims

func ContextWithClaims(ctx context.Context, claims *Claims) context.Context

ContextWithClaims returns a new context with the given claims.

func Middleware

func Middleware(validator TokenValidator) func(http.Handler) http.Handler

Middleware creates an HTTP middleware that validates JWT tokens. Requests without valid tokens receive 401 Unauthorized.

The middleware extracts the token from the Authorization header:

  • "Bearer <token>" format (preferred)
  • Raw token (fallback)

Valid claims are stored in the request context and can be retrieved using ClaimsFromContext().

func MiddlewareWithExclusions

func MiddlewareWithExclusions(validator TokenValidator, excludedPaths []string) func(http.Handler) http.Handler

MiddlewareWithExclusions creates a middleware that skips auth for certain paths. This is useful for health checks, public endpoints, etc.

func OptionalMiddleware

func OptionalMiddleware(validator TokenValidator) func(http.Handler) http.Handler

OptionalMiddleware validates tokens if present but doesn't require them. If a valid token is present, claims are added to the context. If no token is present, the request proceeds without claims. If an invalid token is present, the request is rejected.

func RequireRole

func RequireRole(roles ...string) func(http.Handler) http.Handler

RequireRole creates a middleware that requires the user to have a specific role. Must be used after Middleware() in the chain.

func RequireTenant

func RequireTenant(tenants ...string) func(http.Handler) http.Handler

RequireTenant creates a middleware that requires the user to belong to a specific tenant. Must be used after Middleware() in the chain.

Types

type AuthenticatedUser

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

AuthenticatedUser implements a2asrv.User interface. It wraps Hector's Claims to provide user information to a2a-go.

func UserFromCallContext

func UserFromCallContext(callCtx *a2asrv.CallContext) *AuthenticatedUser

UserFromCallContext extracts the AuthenticatedUser from a2a-go CallContext. Returns nil if the user is not authenticated or not an AuthenticatedUser.

func (*AuthenticatedUser) Authenticated

func (u *AuthenticatedUser) Authenticated() bool

Authenticated returns true since this represents an authenticated user.

func (*AuthenticatedUser) Claims

func (u *AuthenticatedUser) Claims() *Claims

Claims returns the underlying Hector claims. This allows access to full claim data when needed.

func (*AuthenticatedUser) Email

func (u *AuthenticatedUser) Email() string

Email returns the user's email address.

func (*AuthenticatedUser) Name

func (u *AuthenticatedUser) Name() string

Name returns the user's subject (unique identifier).

func (*AuthenticatedUser) Role

func (u *AuthenticatedUser) Role() string

Role returns the user's role.

func (*AuthenticatedUser) TenantID

func (u *AuthenticatedUser) TenantID() string

TenantID returns the user's tenant ID.

type Claims

type Claims struct {
	// Subject is the unique identifier for the user (sub claim).
	Subject string `json:"sub"`

	// Email is the user's email address (if provided).
	Email string `json:"email,omitempty"`

	// Role is the user's role for authorization decisions.
	Role string `json:"role,omitempty"`

	// TenantID supports multi-tenant applications.
	TenantID string `json:"tenant_id,omitempty"`

	// Custom contains any additional claims not mapped to struct fields.
	Custom map[string]any `json:"-"`
}

Claims represents the validated claims from a JWT token. This structure is designed to support common identity providers (Auth0, Okta, Keycloak, etc.) while being extensible for custom claims.

func ClaimsFromCallContext

func ClaimsFromCallContext(callCtx *a2asrv.CallContext) *Claims

ClaimsFromCallContext extracts Claims from a2a-go CallContext. Returns nil if the user is not authenticated.

func ClaimsFromContext

func ClaimsFromContext(ctx context.Context) *Claims

ClaimsFromContext extracts claims from a context. Returns nil if no claims are present.

func (*Claims) GetClaim

func (c *Claims) GetClaim(key string) (any, bool)

GetClaim retrieves a custom claim by key.

func (*Claims) GetStringClaim

func (c *Claims) GetStringClaim(key string) string

GetStringClaim retrieves a custom claim as a string.

func (*Claims) HasAnyRole

func (c *Claims) HasAnyRole(roles ...string) bool

HasAnyRole checks if the user has any of the specified roles.

func (*Claims) HasRole

func (c *Claims) HasRole(role string) bool

HasRole checks if the user has a specific role.

type CredentialType

type CredentialType string

CredentialType identifies the type of credential for outbound requests.

const (
	CredentialTypeBearer CredentialType = "bearer"
	CredentialTypeAPIKey CredentialType = "api_key"
	CredentialTypeBasic  CredentialType = "basic"
)

type Interceptor

type Interceptor struct {
	// RequireAuth when true rejects unauthenticated requests.
	// When false, unauthenticated requests proceed with a nil User.
	RequireAuth bool
}

Interceptor bridges Hector's auth system to a2a-go's CallInterceptor. It reads Claims from the HTTP context (set by Middleware) and sets the a2a-go CallContext.User field.

Architecture

The auth flow is:

  1. HTTP request arrives
  2. auth.Middleware validates JWT and stores Claims in context
  3. a2a-go JSON-RPC handler processes the request
  4. auth.Interceptor.Before() reads Claims and sets CallContext.User
  5. Executor/Agent can access User via CallContext

This design keeps JWT validation in standard HTTP middleware while bridging to a2a-go's authentication system.

func NewInterceptor

func NewInterceptor(requireAuth bool) *Interceptor

NewInterceptor creates a new auth interceptor.

func (*Interceptor) After

func (i *Interceptor) After(ctx context.Context, callCtx *a2asrv.CallContext, resp *a2asrv.Response) error

After is called after each a2a-go request handler method. Currently a no-op but can be extended for audit logging.

func (*Interceptor) Before

func (i *Interceptor) Before(ctx context.Context, callCtx *a2asrv.CallContext, req *a2asrv.Request) (context.Context, error)

Before is called before each a2a-go request handler method. It bridges Claims from HTTP context to a2a-go's User interface.

type JWTValidator

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

JWTValidator validates JWT tokens using JWKS (JSON Web Key Set). It supports automatic key rotation via the jwk.Cache.

This is ported from legacy Hector (pkg/auth/jwt.go) with the same production-tested implementation.

func NewJWTValidator

func NewJWTValidator(cfg JWTValidatorConfig) (*JWTValidator, error)

NewJWTValidator creates a new JWT validator. It fetches the JWKS from the provided URL and caches the keys.

func (*JWTValidator) Close

func (v *JWTValidator) Close() error

Close releases resources held by the validator. Currently a no-op but provided for future resource cleanup.

func (*JWTValidator) ValidateToken

func (v *JWTValidator) ValidateToken(ctx context.Context, tokenString string) (*Claims, error)

ValidateToken validates a JWT token string and returns the extracted claims. It verifies:

  • Token signature against JWKS
  • Token expiration (exp claim)
  • Token not-before time (nbf claim)
  • Issuer (iss claim)
  • Audience (aud claim)

type JWTValidatorConfig

type JWTValidatorConfig struct {
	// JWKSURL is the URL to fetch JSON Web Key Set from.
	// Example: "https://auth.example.com/.well-known/jwks.json"
	JWKSURL string

	// Issuer is the expected token issuer (iss claim).
	// Example: "https://auth.example.com"
	Issuer string

	// Audience is the expected token audience (aud claim).
	// Example: "hector-api"
	Audience string

	// RefreshInterval is how often to refresh the JWKS.
	// Default: 15 minutes
	RefreshInterval time.Duration
}

JWTValidatorConfig configures the JWT validator.

type TokenProvider

type TokenProvider func() (string, error)

TokenProvider is a function that returns a token for outbound requests.

func NewTokenProvider

func NewTokenProvider(credType CredentialType, token, apiKey, username, password string) (TokenProvider, error)

NewTokenProvider creates a TokenProvider based on credential configuration. This is useful for making authenticated outbound requests (e.g., to remote agents).

type TokenValidator

type TokenValidator interface {
	ValidateToken(ctx context.Context, tokenString string) (*Claims, error)
	Close() error
}

TokenValidator is the interface for token validation. This allows for alternative implementations (e.g., for testing).

func NewValidatorFromConfig

func NewValidatorFromConfig(cfg *config.AuthConfig) (TokenValidator, error)

NewValidatorFromConfig creates a TokenValidator from configuration. Returns nil if authentication is not enabled.

Jump to

Keyboard shortcuts

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