Skip to main content
CoreSDK
SDK Reference

Go SDK Reference

Complete API reference for the CoreSDK Go module

Phase 2 — not yet available. The Go SDK ships in Phase 2. The API documented below reflects the planned design.

Go SDK Reference

Complete API reference for the github.com/coresdk-dev/sdk-go module. For a working example see the Go Quickstart.

go get github.com/coresdk-dev/sdk-go

Go 1.21+ required.


sdk.New(cfg Config)

Initializes a new *SDK instance. Validates configuration, fetches JWKS, and compiles Rego policies. Returns an error if any step fails.

Signature

func New(cfg Config) (*SDK, error)

Config fields

FieldTypeRequiredDescription
TenantstringYesTenant identifier for this service instance
JWKSUrlstringYesURL of the JWKS endpoint used to verify JWTs
PolicyDirstringNoDirectory of .rego files. Defaults to "./policies"
OtelEndpointstringNoOTLP gRPC endpoint for traces and metrics
TokenHeaderstringNoHTTP header carrying the bearer token. Defaults to "Authorization"
ClockSkewtime.DurationNoAcceptable JWT clock skew. Defaults to 30 * time.Second
ErrorMapperErrorMapperNoInterface for customizing error responses

Example

import (
    "time"
    "github.com/coresdk-dev/sdk-go/sdk"
)

coreSDK, err := sdk.New(sdk.Config{
    Tenant:        "acme",
    JWKSUrl:       "https://your-idp.com/.well-known/jwks.json",
    PolicyDir:     "./policies",
    OtelEndpoint:  "http://localhost:4317",
    ClockSkew:     45 * time.Second,
})
if err != nil {
    log.Fatalf("failed to init CoreSDK: %v", err)
}

sdk.Handler(next http.Handler)

Returns an http.Handler middleware that authenticates every request, attaches User and Tenant to the context, and emits OTEL spans. Compatible with net/http, Chi, Gorilla Mux, and any http.Handler-based router.

Signature

func (s *SDK) Handler(next http.Handler) http.Handler

Usage

import (
    "net/http"
    "github.com/go-chi/chi/v5"
)

r := chi.NewRouter()
r.Use(coreSDK.Handler)

r.Get("/api/orders", listOrders)

http.ListenAndServe(":3000", r)

Unauthenticated requests receive 401. Policy-denied requests receive 403. Both return RFC 9457 application/problem+json.


sdk.Require(action string)

Returns an http.Handler middleware that enforces a policy action check. Must be composed inside sdk.Handler.

Signature

func (s *SDK) Require(action string) func(http.Handler) http.Handler

Parameters

ParameterTypeDescription
actionstringPolicy action string, e.g. "orders:read"

Usage with Chi

r := chi.NewRouter()
r.Use(coreSDK.Handler)

r.With(coreSDK.Require("orders:read")).Get("/api/orders", listOrders)
r.With(coreSDK.Require("orders:write")).Post("/api/orders", createOrder)

Usage with net/http

mux := http.NewServeMux()
mux.Handle("/api/orders", coreSDK.Require("orders:read")(http.HandlerFunc(listOrders)))
http.ListenAndServe(":3000", coreSDK.Handler(mux))

sdk.CurrentUser(ctx context.Context)

Retrieves the authenticated User from a request context. Returns an error if the context was not populated by sdk.Handler.

Signature

func (s *SDK) CurrentUser(ctx context.Context) (*User, error)

Returns (*User, error)

Usage

func listOrders(w http.ResponseWriter, r *http.Request) {
    user, err := coreSDK.CurrentUser(r.Context())
    if err != nil {
        http.Error(w, "unauthorized", http.StatusUnauthorized)
        return
    }
    fmt.Fprintf(w, "hello %s", user.Email)
}

sdk.CurrentTenant(ctx context.Context)

Retrieves the Tenant from a request context.

Signature

func (s *SDK) CurrentTenant(ctx context.Context) (*Tenant, error)
func listOrders(w http.ResponseWriter, r *http.Request) {
    tenant, err := coreSDK.CurrentTenant(r.Context())
    if err != nil {
        http.Error(w, "tenant not found", http.StatusInternalServerError)
        return
    }
    fmt.Fprintf(w, "tenant: %s plan: %s", tenant.ID, tenant.Plan)
}

Types

User

type User struct {
    ID        string                 // JWT sub claim
    Email     string                 // JWT email claim
    Role      string                 // Mapped role for this tenant
    TenantID  string                 // Tenant the user belongs to
    RawClaims map[string]interface{} // Full decoded JWT claims
}

Tenant

type Tenant struct {
    ID       string                 // Tenant identifier
    Name     string                 // Display name
    Plan     TenantPlan             // free | team | business | enterprise
    Metadata map[string]interface{} // Arbitrary metadata
}

TenantPlan

type TenantPlan string

const (
    PlanFree       TenantPlan = "free"
    PlanTeam       TenantPlan = "team"
    PlanBusiness   TenantPlan = "business"
    PlanEnterprise TenantPlan = "enterprise"
)

Config

See sdk.New() for the full field list.


sdk.Policy().Evaluate(ctx, rule, input)

Evaluates an OPA policy rule directly, outside the middleware path. Use this for business-logic gates not tied to an HTTP handler.

Signature

func (p *PolicyClient) Evaluate(
    ctx context.Context,
    rule string,
    input interface{},
) (*PolicyResult, error)

Parameters

ParameterTypeDescription
ctxcontext.ContextRequest context
rulestringDot-separated Rego rule path, e.g. "data.billing.can_upgrade"
inputinterface{}Input document, marshalled to JSON

PolicyResult

type PolicyResult struct {
    Allowed bool
    Reason  string // empty string if none provided
}

Usage

result, err := coreSDK.Policy().Evaluate(ctx, "data.billing.can_upgrade", map[string]interface{}{
    "user":        user,
    "target_plan": "enterprise",
})
if err != nil {
    return err
}
if !result.Allowed {
    return fmt.Errorf("upgrade denied: %s", result.Reason)
}

Tenant management

sdk.Tenants().Get(ctx, id)

func (t *TenantClient) Get(ctx context.Context, id string) (*Tenant, error)
tenant, err := coreSDK.Tenants().Get(ctx, "acme")

sdk.Tenants().Create(ctx, options)

func (t *TenantClient) Create(ctx context.Context, opts CreateTenantOptions) (*Tenant, error)

type CreateTenantOptions struct {
    ID       string
    Name     string
    Plan     TenantPlan             // optional, defaults to PlanFree
    Metadata map[string]interface{} // optional
}
tenant, err := coreSDK.Tenants().Create(ctx, sdk.CreateTenantOptions{
    ID:   "newcorp",
    Name: "New Corp",
    Plan: sdk.PlanBusiness,
})

sdk.Tenants().Update(ctx, id, options)

func (t *TenantClient) Update(ctx context.Context, id string, opts UpdateTenantOptions) (*Tenant, error)

type UpdateTenantOptions struct {
    Name     *string
    Plan     *TenantPlan
    Metadata map[string]interface{}
}
plan := sdk.PlanEnterprise
tenant, err := coreSDK.Tenants().Update(ctx, "newcorp", sdk.UpdateTenantOptions{
    Plan: &plan,
})

sdk.Tenants().Delete(ctx, id)

func (t *TenantClient) Delete(ctx context.Context, id string) error
err := coreSDK.Tenants().Delete(ctx, "oldcorp")

sdk.Tenants().List(ctx)

func (t *TenantClient) List(ctx context.Context) ([]*Tenant, error)
tenants, err := coreSDK.Tenants().List(ctx)
for _, t := range tenants {
    fmt.Printf("%s: %s\n", t.ID, t.Plan)
}

Error types

All SDK functions return standard error values. Use errors.As to inspect specific error types.

import "github.com/coresdk-dev/sdk-go/sdk/sdkerr"

var tokenExpired *sdkerr.TokenExpiredError
var policyDenied *sdkerr.PolicyDeniedError

if errors.As(err, &tokenExpired) {
    log.Printf("token expired at %v", tokenExpired.ExpiredAt)
} else if errors.As(err, &policyDenied) {
    log.Printf("denied: %s%s", policyDenied.Action, policyDenied.Reason)
}
Error typeFieldsDescription
*TokenExpiredErrorExpiredAt time.TimeJWT exp is in the past
*TokenInvalidErrorReason stringBad signature, malformed JWT, or missing claims
*PolicyDeniedErrorAction, Reason stringOPA policy returned false
*TenantNotFoundErrorTenantID stringTenant lookup returned no record
*JwksFetchErrorURL string, Cause errorNetwork or parse failure fetching JWKS
*ConfigurationErrorMessage stringMissing required field or invalid value

Custom ErrorMapper

type ErrorMapper interface {
    Map(err error) (body []byte, statusCode int, contentType string)
}
type MyMapper struct{}

func (m *MyMapper) Map(err error) ([]byte, int, string) {
    var denied *sdkerr.PolicyDeniedError
    if errors.As(err, &denied) {
        body, _ := json.Marshal(map[string]string{
            "type":   "https://errors.acme.com/forbidden",
            "detail": fmt.Sprintf("'%s' is not allowed", denied.Action),
        })
        return body, http.StatusForbidden, "application/problem+json"
    }
    return sdkerr.DefaultMap(err)
}

coreSDK, err := sdk.New(sdk.Config{
    Tenant:      "acme",
    JWKSUrl:     "https://your-idp.com/.well-known/jwks.json",
    ErrorMapper: &MyMapper{},
})

On this page