# SentryAgent.ai AgentIdP — Go SDK

Official Go client for the [SentryAgent.ai AgentIdP](https://sentryagent.ai) — an open-source Identity Provider for AI agents built on OAuth 2.0 (RFC 6749) and aligned with the [AGNTCY](https://agntcy.org) open standard.

## Requirements

- Go 1.21+
- A running AgentIdP server

## Installation

```bash
go get github.com/sentryagent/idp-sdk-go
```

## Quick Start

```go
package main

import (
    "context"
    "fmt"
    "log"

    agentidp "github.com/sentryagent/idp-sdk-go"
)

func main() {
    ctx := context.Background()

    client := agentidp.NewAgentIdPClient(agentidp.AgentIdPClientConfig{
        BaseURL:      "https://idp.example.com",
        ClientID:     "your-agent-client-id",
        ClientSecret: "sk_live_...",
    })

    // Register a new AI agent
    agent, err := client.Agents.RegisterAgent(ctx, agentidp.RegisterAgentRequest{
        Email:         "screener@example.com",
        AgentType:     "screener",
        Version:       "1.0.0",
        Capabilities:  []string{"read", "classify"},
        Owner:         "platform-team",
        DeploymentEnv: "production",
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Registered agent: %s\n", agent.AgentID)
}
```

## Authentication

The SDK handles OAuth 2.0 Client Credentials automatically. Tokens are cached and refreshed 60 seconds before expiry. All operations are goroutine-safe.

```go
client := agentidp.NewAgentIdPClient(agentidp.AgentIdPClientConfig{
    BaseURL:      "https://idp.example.com",
    ClientID:     "my-client-id",
    ClientSecret: "my-client-secret",
    Scope:        "agents:read agents:write", // optional, defaults to all four scopes
})
```

## Agent Registry

```go
ctx := context.Background()

// Register
agent, err := client.Agents.RegisterAgent(ctx, agentidp.RegisterAgentRequest{...})

// List (with optional filters)
agents, err := client.Agents.ListAgents(ctx, &agentidp.ListAgentsParams{
    Status:    "active",
    AgentType: "screener",
    Page:      1,
    Limit:     20,
})

// Get by ID
agent, err := client.Agents.GetAgent(ctx, "agent-uuid")

// Partial update
version := "2.0.0"
agent, err := client.Agents.UpdateAgent(ctx, "agent-uuid", agentidp.UpdateAgentRequest{
    Version: &version,
})

// Decommission (permanent)
err = client.Agents.DecommissionAgent(ctx, "agent-uuid")
```

## Credential Management

```go
// Generate (returns one-time ClientSecret)
cred, err := client.Credentials.GenerateCredential(ctx, "agent-uuid")
fmt.Println(cred.ClientSecret) // store this — it is never shown again

// List
creds, err := client.Credentials.ListCredentials(ctx, "agent-uuid", 1, 20)

// Rotate (old secret is immediately invalidated)
newCred, err := client.Credentials.RotateCredential(ctx, "agent-uuid", "cred-uuid")

// Revoke
revoked, err := client.Credentials.RevokeCredential(ctx, "agent-uuid", "cred-uuid")
```

## Token Operations

```go
// Introspect (RFC 7662)
result, err := client.Tokens.IntrospectToken(ctx, "access-token-to-check")
if result.Active {
    fmt.Printf("Token belongs to: %s\n", *result.Sub)
}

// Revoke
err = client.Tokens.RevokeToken(ctx, "access-token-to-revoke")
```

## Audit Log

```go
// Query with filters
events, err := client.Audit.QueryAuditLog(ctx, &agentidp.QueryAuditParams{
    AgentID:  "agent-uuid",
    Action:   "token.issued",
    Outcome:  "success",
    FromDate: "2026-01-01",
    ToDate:   "2026-01-31",
    Page:     1,
    Limit:    50,
})

// Get single event
event, err := client.Audit.GetAuditEvent(ctx, "event-uuid")
```

## Error Handling

All errors are returned as `*AgentIdPError`:

```go
agent, err := client.Agents.GetAgent(ctx, "unknown-id")
if err != nil {
    if apiErr, ok := err.(*agentidp.AgentIdPError); ok {
        fmt.Printf("code=%s status=%d\n", apiErr.Code, apiErr.HTTPStatus)
        // e.g. code=AgentNotFoundError status=404
    }
    return err
}
```

| Field        | Type                     | Description                                     |
|--------------|--------------------------|-------------------------------------------------|
| `Code`       | `string`                 | Machine-readable error code                     |
| `Message`    | `string`                 | Human-readable description                      |
| `HTTPStatus` | `int`                    | HTTP status code (0 for network/build errors)   |
| `Details`    | `map[string]interface{}` | Optional structured context from the API        |

## Custom HTTP Client

Inject a custom `*http.Client` for proxy support, custom timeouts, or test mocking:

```go
client := agentidp.NewAgentIdPClient(agentidp.AgentIdPClientConfig{
    BaseURL:      "https://idp.example.com",
    ClientID:     "cid",
    ClientSecret: "secret",
    HTTPClient:   &http.Client{Timeout: 5 * time.Second},
})
```

## API Coverage

| Endpoint                                         | Method | SDK Method                              |
|--------------------------------------------------|--------|-----------------------------------------|
| POST /api/v1/agents                              | POST   | `Agents.RegisterAgent`                  |
| GET  /api/v1/agents                              | GET    | `Agents.ListAgents`                     |
| GET  /api/v1/agents/:id                          | GET    | `Agents.GetAgent`                       |
| PATCH /api/v1/agents/:id                         | PATCH  | `Agents.UpdateAgent`                    |
| DELETE /api/v1/agents/:id                        | DELETE | `Agents.DecommissionAgent`              |
| POST /api/v1/agents/:id/credentials              | POST   | `Credentials.GenerateCredential`        |
| GET  /api/v1/agents/:id/credentials              | GET    | `Credentials.ListCredentials`           |
| POST /api/v1/agents/:id/credentials/:cid/rotate  | POST   | `Credentials.RotateCredential`          |
| DELETE /api/v1/agents/:id/credentials/:cid       | DELETE | `Credentials.RevokeCredential`          |
| POST /api/v1/token                               | POST   | (TokenManager — automatic)              |
| POST /api/v1/token/introspect                    | POST   | `Tokens.IntrospectToken`                |
| POST /api/v1/token/revoke                        | POST   | `Tokens.RevokeToken`                    |
| GET  /api/v1/audit                               | GET    | `Audit.QueryAuditLog`                   |
| GET  /api/v1/audit/:id                           | GET    | `Audit.GetAuditEvent`                   |

## License

Apache 2.0 — see [LICENSE](../LICENSE).
