torii

package module
v0.0.10 Latest Latest
Warning

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

Go to latest
Published: Jul 26, 2026 License: MIT Imports: 14 Imported by: 0

README

torii-sdk-go

The official Go backend SDK for torii — verify end-user JWTs without a per-request round trip and manage users from your Go server.

v0.x — API may still change.

Setup

  1. Sign in to app.torii.so and from your dashboard copy:

    • your issuer URL (e.g. https://acme.torii.so)
    • a secret key (sk_test_… for development, sk_live_… for production)
  2. Install the SDK:

    go get github.com/Torii-ApS/torii-sdk-go
    

    Go 1.22+.

  3. Verify an end-user JWT:

    import (
        "context"
        torii "github.com/Torii-ApS/torii-sdk-go"
    )
    
    auth, err := torii.VerifyToken(ctx, token, torii.VerifyOptions{
        Issuer: "https://acme.torii.so",
    })
    if err != nil {
        // handle invalid / expired token
    }
    fmt.Println(auth.UserID, auth.EnvironmentID, auth.EmailVerified)
    

    The first call fetches the issuer's JWKS; subsequent calls reuse the cache and rotate keys automatically (handled by lestrrat-go/jwx). No round trip per request.

  4. Call the backend REST API:

    client, err := torii.New(torii.Options{
        SecretKey: os.Getenv("TORII_SECRET_KEY"),
    })
    if err != nil {
        log.Fatal(err)
    }
    
    user, err := client.Users().Get(ctx, userID)
    

net/http middleware

import (
    "net/http"
    torii "github.com/Torii-ApS/torii-sdk-go"
    "github.com/Torii-ApS/torii-sdk-go/middleware"
)

auth := middleware.Middleware(middleware.Options{
    Verify: torii.VerifyOptions{Issuer: "https://acme.torii.so"},
})

mux := http.NewServeMux()
mux.HandleFunc("/me", func(w http.ResponseWriter, r *http.Request) {
    a, _ := middleware.AuthFromContext(r.Context())
    fmt.Fprintf(w, "hello %s", a.UserID)
})

http.ListenAndServe(":8080", auth(mux))

Middleware writes a 401 by default; override via Options.OnError. Skip auth on specific routes (health, metrics, …) via Options.Skip.

Authenticate a single request

auth, err := torii.AuthenticateRequest(ctx, r.Header, torii.VerifyOptions{
    Issuer: "https://acme.torii.so",
})

Reads Authorization: Bearer <token> and forwards to VerifyToken.

Backend REST API

// List users
page, err := client.Users().List(ctx, torii.ListUsersOptions{
    Limit: ptr.Int32(50),
})

// Create a user
created, err := client.Users().Create(ctx, torii.CreateUserInput{
    Email: ptr.String("x@y.com"),
})

// Ban a user
banned, err := client.Users().Ban(ctx, created.ID)

// Manage sessions
sessions, err := client.Sessions().ListForUser(ctx, created.ID)
err = client.Sessions().RevokeAllForUser(ctx, created.ID)
Tri-state PATCH semantics

UpdateUserInput fields use the generic Patch[T any] wrapper. This lets callers express three distinct intents:

client.Users().Update(ctx, userID, torii.UpdateUserInput{
    Name:    torii.SetPatch("Acme Inc"),     // change to "Acme Inc"
    Address: torii.ClearPatch[string](),     // clear (JSON null)
    // Phone is the zero value — leave unchanged (field omitted from request)
})

License

MIT

Documentation

Overview

Package torii is the official Go SDK for torii (https://torii.so).

Use it to:

  • Verify end-user JWTs minted by torii without a per-request round trip (see VerifyToken / AuthenticateRequest).
  • Call the torii backend API to manage users and sessions (see New, Client).
  • React to outbound webhooks (VerifyWebhook — currently a stub; the subsystem is not yet available).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type APIError

type APIError struct {
	Status    int
	Code      string
	SupportID string
	Body      []byte
	Message   string
}

APIError wraps a non-2xx response from the torii backend API.

func (*APIError) Error

func (e *APIError) Error() string

type Auth

type Auth struct {
	// UserID is the end-user ID (JWT `sub`).
	UserID string
	// EnvironmentID is the environment this token was issued in (JWT `pid`).
	EnvironmentID string
	// Issuer is the JWT `iss` claim — canonical FAPI URL for this environment.
	Issuer string
	// EmailVerified is true if at least one of the end-user's emails is verified.
	EmailVerified bool
	// ProfileComplete is true if all environment-required profile fields are
	// filled. Defaults to true if the claim is absent.
	ProfileComplete bool
	// Impersonating is true if the token is being used for admin impersonation.
	Impersonating bool
	// Locale is the end-user's preferred locale when set on the profile, else nil.
	Locale *string
	// Raw is the full JWT payload — escape hatch for custom claims, audience
	// checks, etc.
	Raw map[string]any
}

Auth is the subset of fields the SDK exposes from a verified torii access token. Callers who need raw claims can read Raw.

func AuthenticateRequest

func AuthenticateRequest(ctx context.Context, headers http.Header, opts VerifyOptions) (*Auth, error)

AuthenticateRequest reads a Bearer token from the request headers and verifies it. Returns *Auth on success, *Error on failure.

The header read is "Authorization" by default. Gateways that forward the token in a different header should call VerifyToken directly.

func VerifyToken

func VerifyToken(ctx context.Context, token string, opts VerifyOptions) (*Auth, error)

VerifyToken validates a torii-issued JWT and returns the verified subset of claims as *Auth. It performs networkless verification once the issuer's JWKS has been cached.

Verification enforces:

  • ES256 signature against the issuer's JWKS (with kid rotation handled by jwx)
  • exp / nbf with VerifyOptions.ClockTolerance leeway (default 30s)
  • strict `iss` equality with VerifyOptions.Issuer
  • optional `aud` if VerifyOptions.Audience is set
  • presence of required claims (sub, iat, exp, iss, pid)

type Client

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

Client is the top-level entrypoint to the torii backend API. Construct with New and reuse a single instance for the lifetime of your process — Client is safe for concurrent use.

func New

func New(opts Options) (*Client, error)

New constructs a *Client from the given Options. Returns an error if SecretKey is empty or APIURL is invalid.

func (*Client) Sessions

func (c *Client) Sessions() Sessions

Sessions returns the resource client for /sessions endpoints.

func (*Client) Users

func (c *Client) Users() Users

Users returns the resource client for /users endpoints.

type CreateUserInput

type CreateUserInput struct {
	Email     *string
	Password  *string
	FirstName *string
	LastName  *string
	// Metadata bags. Optional: a nil map is omitted from the request, and the
	// server defaults an absent bag to {} (a new user has nothing to clobber).
	PublicMetadata  map[string]any
	PrivateMetadata map[string]any
	UnsafeMetadata  map[string]any
}

CreateUserInput is the request body for Users.Create.

type CursorPage

type CursorPage[T any] struct {
	Items      []T
	NextCursor *string
	HasMore    bool
}

CursorPage is a single page of cursor-paginated results.

type Error

type Error struct {
	Message string
	Cause   error
}

Error is the SDK's auth / verification error type. REST errors from the backend API surface as APIError.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type ListUsersOptions

type ListUsersOptions struct {
	Limit         *int32
	Cursor        *string
	Name          *string
	Email         *string
	Statuses      []UserStatus
	CreatedAfter  *time.Time
	CreatedBefore *time.Time
}

ListUsersOptions controls the search payload for Users.List.

type Locale

type Locale string

Locale is the end-user's preferred display language.

const (
	LocaleEN Locale = "en"
	LocaleDA Locale = "da"
)

type Options

type Options struct {
	// SecretKey is the backend secret (e.g. sk_live_... / sk_test_...). Required.
	SecretKey string

	// APIURL overrides the default backend API base URL.
	// Defaults to "https://api.torii.so".
	APIURL string

	// HTTPClient lets callers inject a custom *http.Client (timeouts, transport,
	// proxies, etc). When nil, http.DefaultClient is used.
	HTTPClient *http.Client
}

Options configures the torii backend API Client.

type ProblemDetail

type ProblemDetail = generated.ProblemDetail

ProblemDetail is re-exported from the generated package so callers can type-assert against torii API error bodies (RFC 7807). All torii API errors that ship a body use this shape.

type Session

type Session struct {
	ID            string
	UserID        string
	EnvironmentID string
	UserAgent     *string
	IPAddress     *string
	CreatedAt     time.Time
	ExpiresAt     time.Time
	LastUsedAt    time.Time
}

Session represents an active end-user session for a given user.

type Sessions

type Sessions interface {
	ListForUser(ctx context.Context, userID string) ([]Session, error)
	RevokeAllForUser(ctx context.Context, userID string) error
	Revoke(ctx context.Context, userID, sessionID string) error
}

Sessions is the resource interface for /sessions endpoints.

type UpdateUserRequest added in v0.0.7

type UpdateUserRequest = generated.UpdateUserRequest

UpdateUserRequest is the tri-state PATCH body for Users.Update, re-exported from the generated package so a new spec field flows through with zero hand edits. Build it with NewUpdateUserRequest and the generated setters:

  • SetFirstName(v) / SetLocale(v) ... -> set the field
  • SetFirstNameNil() / SetLastNameNil() / SetLocaleNil() -> clear (JSON null)
  • leave a field unset -> omit it (server leaves it unchanged)

Metadata bags are 2-state (omit vs object); a null-valued key inside a bag deletes that key. The pinned wire contract lives in contract-tests/fixtures/patch-wire and is asserted in patch_wire_test.go.

func NewUpdateUserRequest added in v0.0.7

func NewUpdateUserRequest() *UpdateUserRequest

NewUpdateUserRequest returns an empty tri-state PATCH body (all fields unset).

type User

type User struct {
	ID              string
	EnvironmentID   string
	Name            *string
	FirstName       *string
	LastName        *string
	Email           *string
	Locale          *Locale
	Status          UserStatus
	CreatedAt       time.Time
	UpdatedAt       time.Time
	EmailVerifiedAt *time.Time
	DeletedAt       *time.Time
	PublicMetadata  map[string]any
	PrivateMetadata map[string]any
	UnsafeMetadata  map[string]any
}

User represents a torii end-user as returned by the backend API. Nullable fields use pointer types so callers can distinguish "not present" (nil) from "present and empty" (*string == "").

type UserStatus

type UserStatus string

UserStatus enumerates server-side user lifecycle states.

const (
	UserStatusPendingVerification UserStatus = "pending_verification"
	UserStatusActive              UserStatus = "active"
	UserStatusBanned              UserStatus = "banned"
	UserStatusDeleted             UserStatus = "deleted"
)

type Users

type Users interface {
	List(ctx context.Context, opts ListUsersOptions) (CursorPage[User], error)
	Get(ctx context.Context, userID string) (*User, error)
	Create(ctx context.Context, in CreateUserInput) (*User, error)
	Update(ctx context.Context, userID string, in UpdateUserRequest) (*User, error)
	Delete(ctx context.Context, userID string) error
	Ban(ctx context.Context, userID string) (*User, error)
	Unban(ctx context.Context, userID string) (*User, error)
}

Users is the resource interface for /users endpoints.

type VerifyOptions

type VerifyOptions struct {
	// Issuer is the expected JWT `iss` claim — required and strictly enforced.
	// For torii this is the FAPI URL for the environment, e.g.
	// "https://acme.torii.so" or a verified custom domain.
	Issuer string

	// Audience optionally enforces the JWT `aud` claim. torii does not set
	// `aud` today, so leaving this empty skips the check. Reserved for
	// future-compat.
	Audience string

	// ClockTolerance is the leeway applied to exp/nbf checks.
	// Defaults to 30 seconds when zero.
	ClockTolerance time.Duration
}

VerifyOptions configures JWT verification.

type WebhookEvent

type WebhookEvent struct {
	Type      string
	ID        string
	CreatedAt string
	Data      map[string]any
}

WebhookEvent is the shape of a verified outbound webhook payload. The fields are tentative until torii's webhook subsystem ships; they're declared here so that adopting VerifyWebhook later doesn't break callers that already type their handler around this struct.

func VerifyWebhook

func VerifyWebhook(secret string, headers http.Header, payload []byte) (*WebhookEvent, error)

VerifyWebhook will, in a future release, verify a torii outbound webhook signature and decode the event payload. Today it is a stub — torii's outbound webhook subsystem is not yet available.

The signature is published now so that adopting this function later does not break callers.

Directories

Path Synopsis
internal
Package middleware provides a net/http middleware that verifies a torii JWT on incoming requests and stores the resulting *torii.Auth in the request context.
Package middleware provides a net/http middleware that verifies a torii JWT on incoming requests and stores the resulting *torii.Auth in the request context.

Jump to

Keyboard shortcuts

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