agentauth

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Jun 27, 2026 License: MIT Imports: 16 Imported by: 0

README

AgentAuth

AgentAuth provides a unified authorization layer for AI agents, combining two complementary protocols:

  • ID-JAG (Identity Assertion Authorization Grant) - Automated, policy-based authorization
  • AAuth (Agent Authorization) - Human-in-the-loop consent for sensitive operations

Package Structure

This repository provides interface-based packages for implementing authorization servers:

Interface-Based Packages

For composable architectures with custom storage backends:

These packages define Store interfaces, allowing you to implement your own storage (DynamoDB, PostgreSQL, etc.).

Storage Implementations

For production use, storage implementations are available in a separate package:

  • plexusone/agentauth/store - SQLite and DynamoDB implementations
    • store.SQLiteStore - SQLite-backed storage
    • store.DynamoDBStore - AWS DynamoDB storage (requires build tag)
    • store.PersonServerAdapter - Adapts Storer to personserver.Store
    • store.AuthzServerAdapter - Adapts Storer to authzserver.Store
Core Package

The agentauth package provides shared types and helper functionality:

  • Policy-based protocol routing (HybridProvider)
  • Provider interfaces for unified authorization
  • Token caching and refresh handling

Architecture

┌──────────────────────────────────────────────────────────────┐
│                    Your Application                           │
│                                                              │
│  ┌─────────────────────┐    ┌─────────────────────┐         │
│  │ aauth/personserver  │    │ idjag/authzserver   │         │
│  │ (Store interface)   │    │ (Store interface)   │         │
│  └──────────┬──────────┘    └──────────┬──────────┘         │
│             │                          │                     │
│             └──────────┬───────────────┘                     │
│                        │                                     │
│         ┌──────────────┴──────────────┐                      │
│         │ plexusone/agentauth/store   │                      │
│         │ (SQLite, DynamoDB, etc.)    │                      │
│         └─────────────────────────────┘                      │
└──────────────────────────────────────────────────────────────┘

Quick Start

Basic Server Setup
package main

import (
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "log"
    "net/http"

    "github.com/aistandardsio/agent-protocols/aauth/personserver"
    "github.com/aistandardsio/agent-protocols/idjag/authzserver"
    "github.com/plexusone/agentauth/store"
)

func main() {
    // Create SQLite store
    sqliteStore, _ := store.NewSQLite("agentauth.db")
    defer sqliteStore.Close()

    // Create adapters for both server types
    psStore := store.NewPersonServerAdapter(sqliteStore)
    asStore := store.NewAuthzServerAdapter(sqliteStore)

    // Generate signing key
    privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    keyID := "key-1"
    issuer := "http://localhost:8080"

    // Create servers
    ps, _ := personserver.New(psStore, issuer, privateKey, keyID)
    as, _ := authzserver.New(asStore, issuer, privateKey, keyID)

    // Register handlers
    mux := http.NewServeMux()

    // AAuth endpoints under /aauth
    psMux := http.NewServeMux()
    ps.RegisterHandlers(psMux)
    mux.Handle("/aauth/", http.StripPrefix("/aauth", psMux))

    // ID-JAG endpoints under /oauth
    asMux := http.NewServeMux()
    as.RegisterHandlers(asMux)
    mux.Handle("/oauth/", http.StripPrefix("/oauth", asMux))

    log.Fatal(http.ListenAndServe(":8080", mux))
}
Using the CLI Server
# Run with default settings (in-memory database)
go run ./cmd/agentauth-server

# Run with persistent storage
go run ./cmd/agentauth-server --db ./agentauth.db

# Run with custom port
go run ./cmd/agentauth-server --port 9000

Packages

aauth/personserver

AAuth Person Server with interface-based storage:

import "github.com/aistandardsio/agent-protocols/aauth/personserver"

// Implement personserver.Store interface for your storage backend
type MyStore struct { /* ... */ }

// Create server with your custom store
ps, err := personserver.New(myStore, issuer, privateKey, keyID,
    personserver.WithTokenTTL(2*time.Hour),
)

Endpoints:

Method Path Description
GET /.well-known/aauth-configuration Discovery metadata
GET /.well-known/jwks.json Public key set
POST /authorize Request authorization
GET /consent/{id} Consent page
POST /consent/{id} Submit consent
GET /consent/status/{id} Poll consent status
POST /token Token endpoint
POST /revoke Token revocation
idjag/authzserver

ID-JAG Authorization Server with interface-based storage:

import "github.com/aistandardsio/agent-protocols/idjag/authzserver"

// Implement authzserver.Store interface for your storage backend
type MyStore struct { /* ... */ }

// Create server with your custom store
as, err := authzserver.New(myStore, issuer, privateKey, keyID,
    authzserver.WithTokenTTL(time.Hour),
    authzserver.WithPersonServerURL("http://localhost:8080/aauth"),
)

Endpoints:

Method Path Description
GET /.well-known/oauth-authorization-server Discovery metadata
GET /.well-known/jwks.json Public key set
POST /token Token exchange (RFC 8693)
POST /introspect Token introspection (RFC 7662)
POST /revoke Token revocation (RFC 7009)
POST /policy/evaluate Evaluate scope policy

Policy-Based Routing

The authorization server uses scope policies to route requests:

// Create policies using the store
policies := []*store.ScopePolicy{
    {
        Pattern:  "read:*",
        Protocol: "idjag",  // Auto-approve via ID-JAG
    },
    {
        Pattern:  "write:*",
        Protocol: "aauth",  // Require human consent
        InteractionType: "supervised",
    },
    {
        Pattern:  "admin:*",
        Protocol: "aauth",
        Priority: 200,  // Higher priority
    },
}

for _, p := range policies {
    sqliteStore.CreateScopePolicy(ctx, p)
}

Pattern Syntax:

  • read:email - Exact match
  • read:* - Wildcard (matches read:email, read:profile, etc.)
  • api:*:read - Glob pattern (matches api:v1:read, api:v2:read, etc.)

Authorization Flows

ID-JAG Flow (Automated)
Agent                    AuthZ Server              IdP
  │                           │                     │
  │──── Request ID-JAG ──────>│                     │
  │                           │                     │
  │<─── ID-JAG Assertion ─────│                     │
  │                           │                     │
  │──── Token Exchange ──────>│                     │
  │     (grant_type=token-exchange)                 │
  │                           │                     │
  │<─── Access Token ────────│                      │
Agent                    Person Server            User
  │                           │                     │
  │──── POST /authorize ─────>│                     │
  │                           │                     │
  │<─── 202 Accepted ────────│                      │
  │     (consent_uri, status_uri)                   │
  │                           │                     │
  │                           │<─── Visit consent ──│
  │                           │                     │
  │                           │──── Consent page ──>│
  │                           │                     │
  │                           │<─── Approve/Deny ───│
  │                           │                     │
  │──── Poll status_uri ─────>│                     │
  │                           │                     │
  │<─── Access Token ────────│                      │

Client SDK

The agentauth/client package provides a Go SDK for agents to interact with AgentAuth servers.

ID-JAG Token Exchange
import "github.com/aistandardsio/agent-protocols/agentauth/client"

c := client.New("https://authz.example.com")

// Exchange an ID-JAG assertion for an access token
token, err := c.ExchangeIDJAG(ctx, idJagAssertion, "read:email read:profile")
if err != nil {
    log.Fatal(err)
}
fmt.Println("Access token:", token.AccessToken)
// Request authorization that may require consent
result, err := c.RequestAuthorization(ctx, &client.AuthorizationRequest{
    AgentToken:  agentToken,
    UserID:      "user-123",
    Scopes:      "write:profile",
    MissionName: "Update Profile",
})
if err != nil {
    log.Fatal(err)
}

switch result.Status {
case "approved":
    // Immediate approval (pre-authorized)
    fmt.Println("Token:", result.Token.AccessToken)
case "pending":
    // User needs to approve
    fmt.Println("Please approve at:", result.ConsentURI)

    // Wait for approval
    token, err := c.WaitForConsent(ctx, result.StatusURI)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Token:", token.AccessToken)
}

Examples

See the agentauth-demo for a complete working example.

Documentation

Overview

Package agentauth provides a unified authorization layer for AI agents. It abstracts the underlying protocols (ID-JAG, AAuth) and provides policy-based routing to determine which protocol to use for each request.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrConsentRequired indicates human consent is needed.
	ErrConsentRequired = errors.New("human consent required")

	// ErrConsentDenied indicates consent was denied.
	ErrConsentDenied = errors.New("consent denied")

	// ErrConsentTimeout indicates consent polling timed out.
	ErrConsentTimeout = errors.New("consent timeout")

	// ErrUnauthorized indicates authorization failed.
	ErrUnauthorized = errors.New("unauthorized")

	// ErrProviderNotConfigured indicates the required provider is not configured.
	ErrProviderNotConfigured = errors.New("provider not configured")
)

Provider errors.

View Source
var (
	ErrNotFound      = errors.New("not found")
	ErrAlreadyExists = errors.New("already exists")
	ErrInvalidInput  = errors.New("invalid input")
)

Store errors.

Functions

func IsJWT

func IsJWT(s string) bool

IsJWT checks if a string looks like a JWT (3 dot-separated parts).

Types

type AAuthConfig

type AAuthConfig struct {
	// Enabled enables AAuth authorization.
	Enabled bool `json:"enabled" yaml:"enabled"`

	// AgentID is the AAuth agent identifier (e.g., "aauth:agent@example.com").
	AgentID string `json:"agent_id" yaml:"agent_id"`

	// PersonServer is the Person Server URL.
	PersonServer string `json:"person_server" yaml:"person_server"`

	// PrivateKey is the path/URI to the private key.
	PrivateKey string `json:"private_key" yaml:"private_key"`

	// KeyID is the key identifier.
	KeyID string `json:"key_id,omitempty" yaml:"key_id,omitempty"`

	// Algorithm is the signing algorithm (default: ES256).
	Algorithm string `json:"algorithm,omitempty" yaml:"algorithm,omitempty"`

	// DefaultAudience is the default audience for tokens.
	DefaultAudience []string `json:"default_audience,omitempty" yaml:"default_audience,omitempty"`

	// DefaultInteractionType is the default interaction type.
	DefaultInteractionType string `json:"default_interaction_type,omitempty" yaml:"default_interaction_type,omitempty"`

	// DefaultMissionDuration is the default mission duration.
	DefaultMissionDuration time.Duration `json:"default_mission_duration,omitempty" yaml:"default_mission_duration,omitempty"`
}

AAuthConfig configures the AAuth provider.

func (*AAuthConfig) Validate

func (c *AAuthConfig) Validate() error

Validate validates the AAuth configuration.

type AAuthProvider

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

AAuthProvider implements Provider using AAuth protocol.

func NewAAuthProvider

func NewAAuthProvider(config *AAuthConfig, opts ...AAuthProviderOption) (*AAuthProvider, error)

NewAAuthProvider creates a new AAuth provider.

func (*AAuthProvider) Authorize

func (p *AAuthProvider) Authorize(ctx context.Context, req *AuthRequest) (*AuthResult, error)

Authorize submits a mission proposal and handles consent flow.

func (*AAuthProvider) CheckConsent

func (p *AAuthProvider) CheckConsent(ctx context.Context, statusURI string) (*AuthResult, error)

CheckConsent checks the status of a pending consent request.

func (*AAuthProvider) HTTPClient

func (p *AAuthProvider) HTTPClient(ctx context.Context, req *AuthRequest) (*http.Client, error)

HTTPClient returns an HTTP client with automatic AAuth authorization.

func (*AAuthProvider) InitializeAgent

func (p *AAuthProvider) InitializeAgent(privateKey crypto.PrivateKey) error

InitializeAgent initializes the AAuth agent from config.

func (*AAuthProvider) Protocol

func (p *AAuthProvider) Protocol() Protocol

Protocol returns ProtocolAAuth.

func (*AAuthProvider) Revoke

func (p *AAuthProvider) Revoke(ctx context.Context, token string) error

Revoke revokes an AAuth authorization.

func (*AAuthProvider) SetAgent

func (p *AAuthProvider) SetAgent(agent *aauth.Agent)

SetAgent sets the AAuth agent (for deferred initialization).

func (*AAuthProvider) WaitForConsent

func (p *AAuthProvider) WaitForConsent(ctx context.Context, statusURI string, timeout time.Duration) (*AuthResult, error)

WaitForConsent polls for consent approval with timeout.

type AAuthProviderOption

type AAuthProviderOption func(*AAuthProvider)

AAuthProviderOption configures the AAuthProvider.

func WithAAuthAgent

func WithAAuthAgent(agent *aauth.Agent) AAuthProviderOption

WithAAuthAgent sets the AAuth agent directly.

func WithAAuthConsentMode

func WithAAuthConsentMode(mode ConsentMode) AAuthProviderOption

WithAAuthConsentMode sets the consent flow mode.

func WithAAuthPollConfig

func WithAAuthPollConfig(interval, timeout time.Duration) AAuthProviderOption

WithAAuthPollConfig sets polling configuration.

type ActorClaims

type ActorClaims struct {
	// Subject is the actor's identifier (e.g., user ID).
	Subject string `json:"sub"`

	// Issuer is the actor's identity provider.
	Issuer string `json:"iss,omitempty"`
}

ActorClaims represents the actor in a delegation token.

type Agent

type Agent struct {
	ID          string    `json:"id" db:"id"`
	Name        string    `json:"name" db:"name"`
	Description string    `json:"description,omitempty" db:"description"`
	PublicKey   string    `json:"public_key" db:"public_key"`
	RedirectURI string    `json:"redirect_uri,omitempty" db:"redirect_uri"`
	Trusted     bool      `json:"trusted" db:"trusted"`
	CreatedAt   time.Time `json:"created_at" db:"created_at"`
	UpdatedAt   time.Time `json:"updated_at" db:"updated_at"`
}

Agent represents a registered agent that can request authorization.

type AuthRequest

type AuthRequest struct {
	// Scopes are the requested scopes.
	Scopes []string `json:"scopes"`

	// Resource is the target resource (optional).
	Resource string `json:"resource,omitempty"`

	// Audience is the intended audience (optional).
	Audience []string `json:"audience,omitempty"`

	// Subject is the subject being represented (for delegation).
	Subject string `json:"subject,omitempty"`

	// MissionName is a human-readable name for the mission (AAuth).
	MissionName string `json:"mission_name,omitempty"`

	// MissionDescription describes what the agent will do (AAuth).
	MissionDescription string `json:"mission_description,omitempty"`

	// Duration is the requested authorization duration.
	Duration time.Duration `json:"duration,omitempty"`

	// InteractionType is the AAuth interaction type.
	InteractionType string `json:"interaction_type,omitempty"`

	// RedirectURI is the callback URI for consent flow.
	RedirectURI string `json:"redirect_uri,omitempty"`

	// State is an opaque value for CSRF protection.
	State string `json:"state,omitempty"`

	// ForceProtocol overrides policy-based protocol selection.
	ForceProtocol Protocol `json:"force_protocol,omitempty"`

	// Metadata contains additional request metadata.
	Metadata map[string]any `json:"metadata,omitempty"`
}

AuthRequest contains the parameters for an authorization request.

type AuthResult

type AuthResult struct {
	// Status is the authorization status.
	Status AuthStatus `json:"status"`

	// Protocol indicates which protocol was used.
	Protocol Protocol `json:"protocol"`

	// Token is the access token (if approved).
	Token string `json:"token,omitempty"`

	// TokenType is the token type (e.g., "Bearer", "DPoP").
	TokenType string `json:"token_type,omitempty"`

	// ExpiresAt is when the token expires.
	ExpiresAt time.Time `json:"expires_at,omitempty"`

	// Scopes are the granted scopes.
	Scopes []string `json:"scopes,omitempty"`

	// ConsentURI is the URI for human consent (if pending).
	ConsentURI string `json:"consent_uri,omitempty"`

	// StatusURI is the URI to poll for consent status.
	StatusURI string `json:"status_uri,omitempty"`

	// PollInterval is the recommended polling interval.
	PollInterval time.Duration `json:"poll_interval,omitempty"`

	// Message is a human-readable message.
	Message string `json:"message,omitempty"`

	// Metadata contains protocol-specific metadata.
	Metadata map[string]any `json:"metadata,omitempty"`
}

AuthResult contains the result of an authorization request.

func (*AuthResult) IsApproved

func (r *AuthResult) IsApproved() bool

IsApproved returns true if authorization was granted.

func (*AuthResult) IsPending

func (r *AuthResult) IsPending() bool

IsPending returns true if human consent is pending.

type AuthStatus

type AuthStatus string

AuthStatus represents the status of an authorization request.

const (
	StatusApproved AuthStatus = "approved"
	StatusPending  AuthStatus = "pending"
	StatusDenied   AuthStatus = "denied"
	StatusExpired  AuthStatus = "expired"
)

Authorization statuses.

type CacheConfig

type CacheConfig struct {
	// Enabled enables token caching.
	Enabled bool `json:"enabled" yaml:"enabled"`

	// TTL is the cache TTL (default: token expiry - 1 minute).
	TTL time.Duration `json:"ttl,omitempty" yaml:"ttl,omitempty"`

	// MaxSize is the maximum cache size.
	MaxSize int `json:"max_size,omitempty" yaml:"max_size,omitempty"`
}

CacheConfig configures token caching.

type Config

type Config struct {
	// AgentID is the agent's identifier.
	AgentID string `json:"agent_id" yaml:"agent_id"`

	// Policy defines authorization routing rules.
	Policy *Policy `json:"policy" yaml:"policy"`

	// IDJAG is the ID-JAG provider configuration.
	IDJAG *IDJAGConfig `json:"idjag,omitempty" yaml:"idjag,omitempty"`

	// AAuth is the AAuth provider configuration.
	AAuth *AAuthConfig `json:"aauth,omitempty" yaml:"aauth,omitempty"`

	// Consent configures the consent flow.
	Consent *ConsentConfig `json:"consent,omitempty" yaml:"consent,omitempty"`

	// Cache configures token caching.
	Cache *CacheConfig `json:"cache,omitempty" yaml:"cache,omitempty"`
}

Config is the main configuration for the agentauth package.

func DefaultConfig

func DefaultConfig(agentID string) *Config

DefaultConfig returns a default configuration.

func (*Config) Validate

func (c *Config) Validate() error

Validate validates the configuration.

type ConsentConfig

type ConsentConfig struct {
	// Mode is the consent flow mode.
	Mode ConsentMode `json:"mode" yaml:"mode"`

	// RedirectURI is the callback URI for redirect flow.
	RedirectURI string `json:"redirect_uri,omitempty" yaml:"redirect_uri,omitempty"`

	// ListenAddr is the address for the callback server (redirect flow).
	ListenAddr string `json:"listen_addr,omitempty" yaml:"listen_addr,omitempty"`

	// PollInterval is the polling interval for deferred flow.
	PollInterval time.Duration `json:"poll_interval,omitempty" yaml:"poll_interval,omitempty"`

	// PollTimeout is the maximum time to wait for consent.
	PollTimeout time.Duration `json:"poll_timeout,omitempty" yaml:"poll_timeout,omitempty"`

	// ShowQRCode shows a QR code for the consent URI (CLI).
	ShowQRCode bool `json:"show_qr_code,omitempty" yaml:"show_qr_code,omitempty"`

	// OpenBrowser automatically opens the consent URI in a browser.
	OpenBrowser bool `json:"open_browser,omitempty" yaml:"open_browser,omitempty"`

	// OnConsentRequired is called when consent is required.
	// Allows custom UI handling.
	OnConsentRequired func(consentURI string) `json:"-" yaml:"-"`
}

ConsentConfig configures the consent flow.

type ConsentHandler

type ConsentHandler interface {
	// StartConsent initiates a consent flow.
	// Returns the consent URI for the user to visit.
	StartConsent(ctx context.Context, req *AuthRequest) (consentURI string, state string, err error)

	// HandleCallback handles the consent callback.
	HandleCallback(ctx context.Context, code, state string) (*AuthResult, error)

	// ServeHTTP handles HTTP callbacks (implements http.Handler).
	ServeHTTP(w http.ResponseWriter, r *http.Request)
}

ConsentHandler handles interactive consent flows.

type ConsentMode

type ConsentMode string

ConsentMode defines how consent is handled.

const (
	// ConsentModeRedirect uses OAuth-style redirect flow.
	ConsentModeRedirect ConsentMode = "redirect"

	// ConsentModeDeferred uses polling-based deferred consent.
	ConsentModeDeferred ConsentMode = "deferred"

	// ConsentModeDevice uses device authorization flow.
	ConsentModeDevice ConsentMode = "device"
)

Consent modes.

type HybridProvider

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

HybridProvider routes authorization requests to the appropriate provider based on policy configuration.

func NewHybridProvider

func NewHybridProvider(config *Config, opts ...HybridProviderOption) (*HybridProvider, error)

NewHybridProvider creates a new hybrid provider.

func (*HybridProvider) Authorize

func (h *HybridProvider) Authorize(ctx context.Context, req *AuthRequest) (*AuthResult, error)

Authorize routes the request to the appropriate provider based on policy.

func (*HybridProvider) CheckConsent

func (h *HybridProvider) CheckConsent(ctx context.Context, statusURI string) (*AuthResult, error)

CheckConsent delegates to the appropriate provider.

func (*HybridProvider) ClearCache

func (h *HybridProvider) ClearCache()

ClearCache clears the token cache.

func (*HybridProvider) GetProviderForScopes

func (h *HybridProvider) GetProviderForScopes(scopes []string) (Protocol, Provider)

GetProviderForScopes returns which provider would be used for the given scopes.

func (*HybridProvider) HTTPClient

func (h *HybridProvider) HTTPClient(ctx context.Context, req *AuthRequest) (*http.Client, error)

HTTPClient returns an HTTP client with automatic authorization.

func (*HybridProvider) PolicyMatcher

func (h *HybridProvider) PolicyMatcher() *PolicyMatcher

PolicyMatcher returns the policy matcher for inspection.

func (*HybridProvider) Protocol

func (h *HybridProvider) Protocol() Protocol

Protocol returns the hybrid protocol identifier.

func (*HybridProvider) Revoke

func (h *HybridProvider) Revoke(ctx context.Context, token string) error

Revoke revokes an authorization.

func (*HybridProvider) WaitForConsent

func (h *HybridProvider) WaitForConsent(ctx context.Context, statusURI string, timeout time.Duration) (*AuthResult, error)

WaitForConsent polls for consent approval.

type HybridProviderOption

type HybridProviderOption func(*HybridProvider)

HybridProviderOption configures the HybridProvider.

func WithAAuthProvider

func WithAAuthProvider(p Provider) HybridProviderOption

WithAAuthProvider sets the AAuth provider.

func WithIDJAGProvider

func WithIDJAGProvider(p Provider) HybridProviderOption

WithIDJAGProvider sets the ID-JAG provider.

type IDJAGConfig

type IDJAGConfig struct {
	// Enabled enables ID-JAG authorization.
	Enabled bool `json:"enabled" yaml:"enabled"`

	// Issuer is the assertion issuer (agent's identity).
	Issuer string `json:"issuer" yaml:"issuer"`

	// TokenEndpoint is the authorization server's token endpoint.
	TokenEndpoint string `json:"token_endpoint" yaml:"token_endpoint"`

	// PrivateKey is the path/URI to the private key for signing.
	// Supports: file path, vault URI (op://, bw://), env:// prefix.
	PrivateKey string `json:"private_key" yaml:"private_key"`

	// KeyID is the key identifier.
	KeyID string `json:"key_id,omitempty" yaml:"key_id,omitempty"`

	// Algorithm is the signing algorithm (default: ES256).
	Algorithm string `json:"algorithm,omitempty" yaml:"algorithm,omitempty"`

	// DefaultAudience is the default audience for assertions.
	DefaultAudience []string `json:"default_audience,omitempty" yaml:"default_audience,omitempty"`

	// AssertionTTL is the assertion lifetime (default: 5m).
	AssertionTTL time.Duration `json:"assertion_ttl,omitempty" yaml:"assertion_ttl,omitempty"`
}

IDJAGConfig configures the ID-JAG provider.

func (*IDJAGConfig) Validate

func (c *IDJAGConfig) Validate() error

Validate validates the ID-JAG configuration.

type IDJAGProvider

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

IDJAGProvider implements Provider using ID-JAG protocol.

func NewIDJAGProvider

func NewIDJAGProvider(config *IDJAGConfig, opts ...IDJAGProviderOption) (*IDJAGProvider, error)

NewIDJAGProvider creates a new ID-JAG provider.

func (*IDJAGProvider) Authorize

func (p *IDJAGProvider) Authorize(ctx context.Context, req *AuthRequest) (*AuthResult, error)

Authorize creates an assertion and exchanges it for an access token.

func (*IDJAGProvider) CheckConsent

func (p *IDJAGProvider) CheckConsent(ctx context.Context, statusURI string) (*AuthResult, error)

CheckConsent is not used by ID-JAG (no human consent flow).

func (*IDJAGProvider) HTTPClient

func (p *IDJAGProvider) HTTPClient(ctx context.Context, req *AuthRequest) (*http.Client, error)

HTTPClient returns an HTTP client with automatic ID-JAG authorization.

func (*IDJAGProvider) Protocol

func (p *IDJAGProvider) Protocol() Protocol

Protocol returns ProtocolIDJAG.

func (*IDJAGProvider) Revoke

func (p *IDJAGProvider) Revoke(ctx context.Context, token string) error

Revoke revokes a token (if supported by the authorization server).

func (*IDJAGProvider) SetPrivateKey

func (p *IDJAGProvider) SetPrivateKey(key crypto.PrivateKey)

SetPrivateKey sets the private key (for deferred initialization).

func (*IDJAGProvider) WaitForConsent

func (p *IDJAGProvider) WaitForConsent(ctx context.Context, statusURI string, timeout time.Duration) (*AuthResult, error)

WaitForConsent is not used by ID-JAG.

type IDJAGProviderOption

type IDJAGProviderOption func(*IDJAGProvider)

IDJAGProviderOption configures the IDJAGProvider.

func WithIDJAGHTTPClient

func WithIDJAGHTTPClient(client *http.Client) IDJAGProviderOption

WithIDJAGHTTPClient sets a custom HTTP client.

func WithIDJAGPrivateKey

func WithIDJAGPrivateKey(key crypto.PrivateKey) IDJAGProviderOption

WithIDJAGPrivateKey sets the private key directly.

type Mission

type Mission struct {
	ID              string        `json:"id" db:"id"`
	AgentID         string        `json:"agent_id" db:"agent_id"`
	UserID          string        `json:"user_id" db:"user_id"`
	Name            string        `json:"name" db:"name"`
	Description     string        `json:"description,omitempty" db:"description"`
	Scopes          string        `json:"scopes" db:"scopes"`
	InteractionType string        `json:"interaction_type" db:"interaction_type"`
	Status          MissionStatus `json:"status" db:"status"`
	Duration        int64         `json:"duration" db:"duration"`
	ExpiresAt       *time.Time    `json:"expires_at,omitempty" db:"expires_at"`
	ApprovedAt      *time.Time    `json:"approved_at,omitempty" db:"approved_at"`
	DeniedAt        *time.Time    `json:"denied_at,omitempty" db:"denied_at"`
	DenialReason    string        `json:"denial_reason,omitempty" db:"denial_reason"`
	CreatedAt       time.Time     `json:"created_at" db:"created_at"`
	UpdatedAt       time.Time     `json:"updated_at" db:"updated_at"`
}

Mission represents an agent's request to act on behalf of a user.

func (*Mission) IsActive

func (m *Mission) IsActive() bool

IsActive returns true if the mission is currently active.

type MissionStatus

type MissionStatus string

MissionStatus represents the status of a mission request.

const (
	MissionStatusPending  MissionStatus = "pending"
	MissionStatusApproved MissionStatus = "approved"
	MissionStatusDenied   MissionStatus = "denied"
	MissionStatusExpired  MissionStatus = "expired"
	MissionStatusRevoked  MissionStatus = "revoked"
)

Mission statuses.

type Policy

type Policy struct {
	// Mode is the overall policy mode.
	Mode PolicyMode `json:"mode" yaml:"mode"`

	// DefaultProtocol is used when no scope policy matches (hybrid mode).
	DefaultProtocol Protocol `json:"default_protocol" yaml:"default_protocol"`

	// ScopePolicies define per-scope authorization rules.
	ScopePolicies []ScopePolicy `json:"scope_policies,omitempty" yaml:"scope_policies,omitempty"`

	// SensitiveScopes always require AAuth/human consent.
	// Shorthand for adding AAuth policies for each scope.
	SensitiveScopes []string `json:"sensitive_scopes,omitempty" yaml:"sensitive_scopes,omitempty"`

	// AutoScopes always use ID-JAG/automatic authorization.
	// Shorthand for adding ID-JAG policies for each scope.
	AutoScopes []string `json:"auto_scopes,omitempty" yaml:"auto_scopes,omitempty"`
}

Policy defines authorization policies for scope routing.

func DefaultPolicy

func DefaultPolicy() *Policy

DefaultPolicy returns a sensible default policy.

type PolicyMatcher

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

PolicyMatcher matches scopes to policies.

func NewPolicyMatcher

func NewPolicyMatcher(policy *Policy) *PolicyMatcher

NewPolicyMatcher creates a new policy matcher.

func (*PolicyMatcher) GetScopePolicy

func (m *PolicyMatcher) GetScopePolicy(scope string) *ScopePolicy

GetScopePolicy returns the policy for a specific scope.

func (*PolicyMatcher) Match

func (m *PolicyMatcher) Match(scopes []string) Protocol

Match returns the protocol for a set of scopes. If any scope requires AAuth, AAuth is returned. If all scopes match auto policies, IDJAG is returned.

func (*PolicyMatcher) RequiresConsent

func (m *PolicyMatcher) RequiresConsent(scopes []string) bool

RequiresConsent returns true if any scope requires human consent.

func (*PolicyMatcher) SplitByProtocol

func (m *PolicyMatcher) SplitByProtocol(scopes []string) (auto, human []string)

SplitByProtocol splits scopes into auto and human-required groups.

type PolicyMode

type PolicyMode string

PolicyMode determines how authorization requests are routed.

const (
	// PolicyModeAuto uses ID-JAG for all requests (no human interaction).
	PolicyModeAuto PolicyMode = "auto"

	// PolicyModeHuman uses AAuth for all requests (always human consent).
	PolicyModeHuman PolicyMode = "human"

	// PolicyModeHybrid routes based on scope policies.
	PolicyModeHybrid PolicyMode = "hybrid"
)

Policy modes.

type PreAuthorization

type PreAuthorization struct {
	ID        string     `json:"id" db:"id"`
	UserID    string     `json:"user_id" db:"user_id"`
	AgentID   string     `json:"agent_id" db:"agent_id"`
	Scopes    string     `json:"scopes" db:"scopes"`
	CreatedAt time.Time  `json:"created_at" db:"created_at"`
	ExpiresAt *time.Time `json:"expires_at,omitempty" db:"expires_at"`
}

PreAuthorization allows users to pre-approve certain scopes for agents.

func (*PreAuthorization) Covers

func (p *PreAuthorization) Covers(requestedScopes []string) bool

Covers returns true if this pre-authorization covers the requested scopes.

type Protocol

type Protocol string

Protocol identifies the authorization protocol.

const (
	// ProtocolIDJAG uses ID-JAG for policy-based automatic authorization.
	ProtocolIDJAG Protocol = "idjag"

	// ProtocolAAuth uses AAuth for human consent-based authorization.
	ProtocolAAuth Protocol = "aauth"
)

Supported protocols.

func DetectTokenProtocol

func DetectTokenProtocol(token string) Protocol

DetectTokenProtocol attempts to detect the protocol from token claims. Returns empty string if unable to determine.

type Provider

type Provider interface {
	// Authorize requests authorization for the given scopes.
	// Returns AuthResult with token if approved, or consent info if pending.
	Authorize(ctx context.Context, req *AuthRequest) (*AuthResult, error)

	// CheckConsent checks the status of a pending consent request.
	CheckConsent(ctx context.Context, statusURI string) (*AuthResult, error)

	// WaitForConsent polls for consent approval with timeout.
	WaitForConsent(ctx context.Context, statusURI string, timeout time.Duration) (*AuthResult, error)

	// Revoke revokes an existing authorization.
	Revoke(ctx context.Context, token string) error

	// Protocol returns the protocol this provider implements.
	Protocol() Protocol

	// HTTPClient returns an HTTP client that automatically adds authorization.
	HTTPClient(ctx context.Context, req *AuthRequest) (*http.Client, error)
}

Provider is the interface for authorization providers.

type ScopePolicy

type ScopePolicy struct {
	// Pattern is the scope pattern to match.
	// Supports wildcards: "calendar:*", "admin:**", "email:read"
	Pattern string `json:"pattern" yaml:"pattern"`

	// Protocol is the protocol to use for matching scopes.
	Protocol Protocol `json:"protocol" yaml:"protocol"`

	// RequireConsent forces human consent even for ID-JAG.
	RequireConsent bool `json:"require_consent,omitempty" yaml:"require_consent,omitempty"`

	// InteractionType is the AAuth interaction type for this scope.
	InteractionType string `json:"interaction_type,omitempty" yaml:"interaction_type,omitempty"`

	// MaxDuration is the maximum authorization duration for this scope.
	MaxDuration string `json:"max_duration,omitempty" yaml:"max_duration,omitempty"`

	// Description describes what this scope allows.
	Description string `json:"description,omitempty" yaml:"description,omitempty"`

	// Priority determines matching order (higher = checked first).
	Priority int `json:"priority,omitempty" yaml:"priority,omitempty"`
}

ScopePolicy defines how a scope pattern should be authorized.

type Store

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

Store provides shared persistence for the authorization servers.

func NewStore

func NewStore(dbPath string) (*Store, error)

NewStore creates a new SQLite-backed store.

func (*Store) ApproveMission

func (s *Store) ApproveMission(ctx context.Context, id string, duration time.Duration) error

ApproveMission approves a mission.

func (*Store) Close

func (s *Store) Close() error

Close closes the database connection.

func (*Store) CreateAgent

func (s *Store) CreateAgent(ctx context.Context, agent *Agent) error

CreateAgent creates a new agent.

func (*Store) CreateMission

func (s *Store) CreateMission(ctx context.Context, mission *Mission) error

CreateMission creates a new mission.

func (*Store) CreatePreAuthorization

func (s *Store) CreatePreAuthorization(ctx context.Context, preAuth *PreAuthorization) error

CreatePreAuthorization creates a pre-authorization.

func (*Store) CreateScopePolicy

func (s *Store) CreateScopePolicy(ctx context.Context, policy *StoredScopePolicy) error

CreateScopePolicy creates a scope policy.

func (*Store) CreateToken

func (s *Store) CreateToken(ctx context.Context, token *Token) error

CreateToken creates a new token record.

func (*Store) CreateUser

func (s *Store) CreateUser(ctx context.Context, user *User) error

CreateUser creates a new user.

func (*Store) DB

func (s *Store) DB() *sql.DB

DB returns the underlying database connection for advanced use cases.

func (*Store) DeletePreAuthorization

func (s *Store) DeletePreAuthorization(ctx context.Context, userID, agentID string) error

DeletePreAuthorization deletes a pre-authorization.

func (*Store) DeleteScopePolicy

func (s *Store) DeleteScopePolicy(ctx context.Context, id string) error

DeleteScopePolicy deletes a scope policy.

func (*Store) DenyMission

func (s *Store) DenyMission(ctx context.Context, id, reason string) error

DenyMission denies a mission.

func (*Store) GetAgent

func (s *Store) GetAgent(ctx context.Context, id string) (*Agent, error)

GetAgent retrieves an agent by ID.

func (*Store) GetMission

func (s *Store) GetMission(ctx context.Context, id string) (*Mission, error)

GetMission retrieves a mission by ID.

func (*Store) GetPreAuthorization

func (s *Store) GetPreAuthorization(ctx context.Context, userID, agentID string) (*PreAuthorization, error)

GetPreAuthorization retrieves a pre-authorization for a user/agent pair.

func (*Store) GetToken

func (s *Store) GetToken(ctx context.Context, id string) (*Token, error)

GetToken retrieves a token by ID.

func (*Store) GetUser

func (s *Store) GetUser(ctx context.Context, id string) (*User, error)

GetUser retrieves a user by ID.

func (*Store) GetUserByEmail

func (s *Store) GetUserByEmail(ctx context.Context, email string) (*User, error)

GetUserByEmail retrieves a user by email.

func (*Store) ListAgents

func (s *Store) ListAgents(ctx context.Context) ([]*Agent, error)

ListAgents lists all agents.

func (*Store) ListMissionsByUser

func (s *Store) ListMissionsByUser(ctx context.Context, userID string) ([]*Mission, error)

ListMissionsByUser lists missions for a user.

func (*Store) ListPendingMissions

func (s *Store) ListPendingMissions(ctx context.Context) ([]*Mission, error)

ListPendingMissions lists all pending missions.

func (*Store) ListScopePolicies

func (s *Store) ListScopePolicies(ctx context.Context) ([]*StoredScopePolicy, error)

ListScopePolicies lists all scope policies.

func (*Store) ListUsers

func (s *Store) ListUsers(ctx context.Context) ([]*User, error)

ListUsers lists all users.

func (*Store) RevokeToken

func (s *Store) RevokeToken(ctx context.Context, id string) error

RevokeToken revokes a token.

type StoredScopePolicy

type StoredScopePolicy struct {
	ID              string    `json:"id" db:"id"`
	Pattern         string    `json:"pattern" db:"pattern"`
	Protocol        string    `json:"protocol" db:"protocol"`
	InteractionType string    `json:"interaction_type,omitempty" db:"interaction_type"`
	Description     string    `json:"description,omitempty" db:"description"`
	Priority        int       `json:"priority" db:"priority"`
	CreatedAt       time.Time `json:"created_at" db:"created_at"`
}

StoredScopePolicy represents a scope policy stored in the database.

type Storer

type Storer interface {
	// Close closes the store connection.
	Close() error

	// User operations
	CreateUser(ctx context.Context, user *User) error
	GetUser(ctx context.Context, id string) (*User, error)
	GetUserByEmail(ctx context.Context, email string) (*User, error)
	ListUsers(ctx context.Context) ([]*User, error)

	// Agent operations
	CreateAgent(ctx context.Context, agent *Agent) error
	GetAgent(ctx context.Context, id string) (*Agent, error)
	ListAgents(ctx context.Context) ([]*Agent, error)

	// Mission operations
	CreateMission(ctx context.Context, mission *Mission) error
	GetMission(ctx context.Context, id string) (*Mission, error)
	ApproveMission(ctx context.Context, id string, duration time.Duration) error
	DenyMission(ctx context.Context, id, reason string) error
	ListPendingMissions(ctx context.Context) ([]*Mission, error)
	ListMissionsByUser(ctx context.Context, userID string) ([]*Mission, error)

	// Token operations
	CreateToken(ctx context.Context, token *Token) error
	GetToken(ctx context.Context, id string) (*Token, error)
	RevokeToken(ctx context.Context, id string) error

	// Pre-authorization operations
	CreatePreAuthorization(ctx context.Context, preAuth *PreAuthorization) error
	GetPreAuthorization(ctx context.Context, userID, agentID string) (*PreAuthorization, error)
	DeletePreAuthorization(ctx context.Context, userID, agentID string) error

	// Scope policy operations
	CreateScopePolicy(ctx context.Context, policy *StoredScopePolicy) error
	ListScopePolicies(ctx context.Context) ([]*StoredScopePolicy, error)
	DeleteScopePolicy(ctx context.Context, id string) error
}

Storer defines the interface for authorization storage backends. Both SQLite and DynamoDB implementations satisfy this interface.

type Token

type Token struct {
	ID        string     `json:"id" db:"id"`
	MissionID string     `json:"mission_id,omitempty" db:"mission_id"`
	AgentID   string     `json:"agent_id" db:"agent_id"`
	UserID    string     `json:"user_id" db:"user_id"`
	Scopes    string     `json:"scopes" db:"scopes"`
	TokenType string     `json:"token_type" db:"token_type"`
	Protocol  string     `json:"protocol" db:"protocol"`
	IssuedAt  time.Time  `json:"issued_at" db:"issued_at"`
	ExpiresAt time.Time  `json:"expires_at" db:"expires_at"`
	RevokedAt *time.Time `json:"revoked_at,omitempty" db:"revoked_at"`
}

Token represents an issued auth token.

func (*Token) IsValid

func (t *Token) IsValid() bool

IsValid returns true if the token is still valid.

type TokenClaims

type TokenClaims struct {
	// Protocol indicates which protocol verified this token.
	Protocol Protocol `json:"protocol"`

	// Issuer is the token issuer.
	Issuer string `json:"iss"`

	// Subject is the token subject (agent ID).
	Subject string `json:"sub"`

	// Audience is the token audience.
	Audience []string `json:"aud"`

	// Scopes are the granted scopes (space-separated in token).
	Scopes []string `json:"scopes"`

	// ExpiresAt is when the token expires.
	ExpiresAt time.Time `json:"exp"`

	// IssuedAt is when the token was issued.
	IssuedAt time.Time `json:"iat"`

	// Actor contains delegation information (who the agent acts for).
	Actor *ActorClaims `json:"act,omitempty"`

	// Raw contains the raw claims map for protocol-specific data.
	Raw map[string]any `json:"raw,omitempty"`
}

TokenClaims represents verified token claims.

func (*TokenClaims) HasAnyScope

func (c *TokenClaims) HasAnyScope(scopes ...string) bool

HasAnyScope checks if the claims include any of the specified scopes.

func (*TokenClaims) HasScope

func (c *TokenClaims) HasScope(scope string) bool

HasScope checks if the claims include a specific scope.

type TokenRefresher

type TokenRefresher interface {
	// Refresh refreshes an expired or expiring token.
	Refresh(ctx context.Context, token string) (*AuthResult, error)

	// NeedsRefresh returns true if the token should be refreshed.
	NeedsRefresh(expiresAt time.Time) bool
}

TokenRefresher handles token refresh.

type TokenVerifier

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

TokenVerifier verifies tokens and enforces action-based policies.

func NewTokenVerifier

func NewTokenVerifier(config *VerifierConfig) *TokenVerifier

NewTokenVerifier creates a new hybrid token verifier.

func (*TokenVerifier) AddAAuthIssuer

func (v *TokenVerifier) AddAAuthIssuer(issuerURL, jwksURL string)

AddAAuthIssuer adds a trusted AAuth issuer.

func (*TokenVerifier) AddIDJAGIssuer

func (v *TokenVerifier) AddIDJAGIssuer(issuerURL, jwksURL string)

AddIDJAGIssuer adds a trusted ID-JAG issuer.

func (*TokenVerifier) GetRequiredProtocol

func (v *TokenVerifier) GetRequiredProtocol(action string) Protocol

GetRequiredProtocol returns the required protocol for an action.

func (*TokenVerifier) IsSensitiveAction

func (v *TokenVerifier) IsSensitiveAction(action string) bool

IsSensitiveAction returns true if the action requires AAuth.

func (*TokenVerifier) Verify

func (v *TokenVerifier) Verify(ctx context.Context, token string) (*TokenClaims, error)

Verify verifies a token without action checking. Returns the claims if valid.

func (*TokenVerifier) VerifyForAction

func (v *TokenVerifier) VerifyForAction(ctx context.Context, token, action string) (*TokenClaims, error)

VerifyForAction verifies a token and checks if it's valid for the given action. Returns an error if the token protocol doesn't match the action's required protocol.

type User

type User struct {
	ID        string    `json:"id" db:"id"`
	Email     string    `json:"email" db:"email"`
	Name      string    `json:"name" db:"name"`
	CreatedAt time.Time `json:"created_at" db:"created_at"`
	UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}

User represents a person who can authorize agents.

type VerifierConfig

type VerifierConfig struct {
	// IDJAGEnabled enables ID-JAG token verification.
	IDJAGEnabled bool `json:"idjag_enabled" yaml:"idjag_enabled"`

	// IDJAGIssuers maps issuer URLs to JWKS URLs for ID-JAG verification.
	// If JWKS URL is empty, defaults to {issuer}/.well-known/jwks.json
	IDJAGIssuers map[string]string `json:"idjag_issuers" yaml:"idjag_issuers"`

	// IDJAGAudience is the expected audience for ID-JAG tokens.
	IDJAGAudience string `json:"idjag_audience" yaml:"idjag_audience"`

	// AAuthEnabled enables AAuth token verification.
	AAuthEnabled bool `json:"aauth_enabled" yaml:"aauth_enabled"`

	// AAuthIssuers maps issuer URLs to JWKS URLs for AAuth verification.
	// If JWKS URL is empty, defaults to {issuer}/.well-known/jwks.json
	AAuthIssuers map[string]string `json:"aauth_issuers" yaml:"aauth_issuers"`

	// AAuthAudience is the expected audience for AAuth tokens.
	AAuthAudience string `json:"aauth_audience" yaml:"aauth_audience"`

	// ActionPolicy routes actions to protocols.
	// Key is the action name (e.g., "chat", "write", "delete").
	// Value is the required protocol for that action.
	ActionPolicy map[string]Protocol `json:"action_policy" yaml:"action_policy"`

	// DefaultProtocol is used when no action policy matches.
	// Defaults to ProtocolIDJAG (automatic).
	DefaultProtocol Protocol `json:"default_protocol" yaml:"default_protocol"`

	// SensitiveActions require AAuth (human consent).
	// These override ActionPolicy.
	SensitiveActions []string `json:"sensitive_actions" yaml:"sensitive_actions"`

	// CacheTTL is how long to cache JWKS keys.
	CacheTTL time.Duration `json:"cache_ttl" yaml:"cache_ttl"`
}

VerifierConfig configures the hybrid token verifier.

func DefaultVerifierConfig

func DefaultVerifierConfig() *VerifierConfig

DefaultVerifierConfig returns a sensible default configuration.

Directories

Path Synopsis
Package client provides a Go SDK for agents to interact with AgentAuth servers.
Package client provides a Go SDK for agents to interact with AgentAuth servers.

Jump to

Keyboard shortcuts

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