SystemForge is a batteries-included Go platform module providing reusable identity, session, authorization, and feature flags for multi-tenant SaaS applications. Think of it as Django/Laravel-style conveniences for Go.
- π€ Users - Email, password hash (Argon2id), platform admin flag
- π’ Organizations - Multi-tenant with name, slug, plan, settings
- π Memberships - User-org relationships with flexible roles
- π Ownership Transfer - Transaction-safe organization ownership transfers
- π OAuth Accounts - External OAuth provider links (GitHub, Google)
- π API Keys - Machine-to-machine authentication with scopes
- π Authorization Code + PKCE - Secure browser-based auth
- π€ Client Credentials - Service-to-service auth
- π Refresh Token - With rotation and theft detection
- π JWT Bearer (RFC 7523) - Service account authentication
- βοΈ Service Accounts - Non-human identities with RSA/EC key pairs
- π Token Introspection & Revocation - RFC 7662/7009
- π« JWT Service - Access/refresh token generation with HS256/RS256/ES256
- π DPoP (RFC 9449) - Proof-of-possession token binding
- π₯οΈ BFF Pattern - Backend for Frontend with server-side sessions
- πΎ OmniStorage Backend - Production session storage with Redis, size limits, and observability
- π OAuth Handlers - GitHub and Google social login
- π‘οΈ Middleware - JWT Bearer and API key authentication
- π₯ RBAC/ReBAC - Role and relationship-based access control
- π SpiceDB Provider - Zanzibar-style fine-grained authorization
- β¨ Simple Provider - Lightweight permission checking
- π§ HTTP Middleware - Route protection for Chi and stdlib
- π Vendor-Agnostic - Integrates with omniobserve
- π Multiple Backends - OTLP, Datadog, New Relic, Dynatrace
- π Pre-Built Metrics - CoreAuth, rate limiting, JWT/API key validation
- π Distributed Tracing - Automatic span creation for OAuth flows
- π slog Integration - Trace-correlated structured logging
- π Listings - Product catalog with tiers and pricing
- π³ Stripe Integration - Subscription billing and webhooks
- π Licensing - Per-seat, unlimited, and time-limited licenses
- π₯ Seat Management - Assign and revoke user access
- π© Flag Engine - Boolean, percentage, and user list flags
- π’ Organization Scoping - Per-org flag evaluation
- πΎ In-Memory Store - Development and testing
- ποΈ PostgreSQL RLS - Policy generation and session variables
- π Tenant Isolation - Multi-tenant data separation
- π Ent Integration - Transaction helpers with tenant context
- ποΈ Multi-App Server - Run multiple SaaS apps on shared infrastructure
- π¦ Schema Isolation - Each app gets its own PostgreSQL schema
- π X-App-ID Routing - Header-based request routing to app backends
- π AppBackend Interface - Composable app registration with lifecycle hooks
- πΎ Shared Caching - Redis or in-memory with app-scoped prefixes
go get github.com/grokify/systemforgeSystemForge provides Ent schemas with cf_ table prefix for side-by-side migration.
package main
import (
"context"
"github.com/grokify/systemforge/identity/ent"
_ "github.com/lib/pq"
)
func main() {
client, err := ent.Open("postgres", "postgres://...")
if err != nil {
panic(err)
}
defer client.Close()
// Run migrations
if err := client.Schema.Create(context.Background()); err != nil {
panic(err)
}
// Create a user
user, err := client.User.Create().
SetEmail("user@example.com").
SetName("Example User").
Save(context.Background())
}Compose SystemForge mixins into your own schemas:
// your-app/ent/schema/user.go
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/field"
cfmixin "github.com/grokify/systemforge/identity/ent/mixin"
)
type User struct {
ent.Schema
}
func (User) Mixin() []ent.Mixin {
return []ent.Mixin{
cfmixin.UUIDMixin{}, // UUID primary key
cfmixin.TimestampMixin{}, // created_at, updated_at
}
}
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("username").Unique(),
// App-specific fields...
}
}import (
"github.com/grokify/systemforge/session/jwt"
"github.com/grokify/systemforge/session/middleware"
)
// Create JWT service
svc, err := jwt.NewService(&jwt.Config{
Secret: []byte("your-secret-key"),
AccessTokenExpiry: 15 * time.Minute,
RefreshTokenExpiry: 7 * 24 * time.Hour,
Issuer: "your-app",
})
// Generate tokens
pair, err := svc.GenerateTokenPair(userID, email, name)
// Middleware for protected routes
r.Use(middleware.JWT(svc))import "github.com/grokify/systemforge/session/dpop"
// Generate DPoP key pair (BFF side)
keyPair, err := dpop.GenerateKeyPair()
// Create proof for API request
proof, err := dpop.CreateProofWithOptions(keyPair, "POST", "https://api.example.com/data", dpop.ProofOptions{
AccessToken: accessToken,
})
// Verify proof (API side)
verifier := dpop.NewVerifier(dpop.VerificationConfig{
MaxAge: 5 * time.Minute,
})
result, err := verifier.Verify(proofJWT, dpop.VerificationRequest{
Method: "POST",
URI: "https://api.example.com/data",
AccessToken: accessToken,
})import "github.com/grokify/systemforge/session/bff"
// Create BFF proxy
proxy := bff.NewProxy(bff.ProxyConfig{
Backend: "https://api.internal.example.com",
AllowedOrigins: []string{"https://app.example.com"},
SessionStore: bff.NewMemoryStore(),
})
// Mount proxy handler
r.Handle("/api/*", proxy.Handler())import (
"github.com/grokify/systemforge/authz"
"github.com/grokify/systemforge/authz/simple"
)
// Create authorization provider
provider := simple.NewProvider(simple.Config{
AllowOwnerFullAccess: true,
AllowPlatformAdminAll: true,
})
// Add role permissions
provider.AddRolePermissions("admin", []string{
"users:read", "users:write",
"settings:read", "settings:write",
})
provider.AddRolePermissions("member", []string{
"users:read",
})
// Use middleware
mw := authz.NewMiddleware(provider)
r.With(mw.RequireAction(authz.ResourceType("users"), authz.ActionRead)).Get("/users", listUsers)github.com/grokify/systemforge/
βββ identity/ # User, Organization, Membership, OAuth
β βββ ent/schema/ # Ent schemas with cf_ prefix
β βββ apikey/ # API key service
β βββ oauth/ # OAuth 2.0 server (Fosite)
β βββ password.go # Argon2id hashing
β βββ service.go # Identity service interfaces
β
βββ session/ # Session management
β βββ jwt/ # JWT service with DPoP claims
β βββ dpop/ # DPoP proof-of-possession
β βββ bff/ # Backend for Frontend pattern
β βββ oauth/ # Social login handlers
β βββ middleware/ # Auth middleware
β βββ ratelimit/ # Rate limiting with observability
β
βββ observability/ # Vendor-agnostic observability
β βββ observability.go # Core wrapper for omniobserve
β βββ middleware.go # HTTP request tracing
β βββ metrics.go # Pre-defined metric names
β
βββ authz/ # Authorization
β βββ simple/ # Simple RBAC provider
β βββ spicedb/ # SpiceDB ReBAC provider
β βββ noop/ # No-op syncer for testing
β βββ providertest/ # Provider test suite
β βββ middleware.go # HTTP middleware
β
βββ marketplace/ # SaaS marketplace
β βββ listing.go # Product listings and tiers
β βββ license.go # License management
β βββ subscription.go # Subscription handling
β βββ stripe/ # Stripe billing integration
β
βββ featureflags/ # Feature flag engine
β βββ stores/ # Flag stores
β
βββ multiapp/ # Multi-app platform
β βββ server.go # Multi-app server with routing
β βββ app.go # AppBackend interface
β βββ database.go # Schema-per-app isolation
β βββ cache.go # Redis and memory cache
β βββ context.go # App context helpers
β
βββ rls/ # PostgreSQL Row-Level Security
βββ rls.go # Policy generation
βββ middleware.go # HTTP middleware
| Decision | Choice | Rationale |
|---|---|---|
| Table prefix | cf_ |
Avoids conflicts, enables side-by-side migration |
| Role storage | String field | Apps define own vocabularies (owner/admin/member) |
| OAuth pattern | Fosite library | Production-ready, RFC-compliant OAuth 2.0 |
| Refresh tokens | Database-backed | Enables revocation, theft detection |
| Primary keys | UUID | Modern, distributed-friendly |
| Password hashing | Argon2id | OWASP recommended, memory-hard |
SystemForge creates the following tables (all prefixed with cf_):
| Table | Description |
|---|---|
cf_users |
User accounts |
cf_organizations |
Multi-tenant organizations |
cf_memberships |
User-organization relationships |
cf_oauth_accounts |
External OAuth provider links |
cf_refresh_tokens |
JWT refresh token tracking |
cf_api_keys |
Developer API keys |
cf_oauth_apps |
OAuth client applications |
cf_oauth_app_secrets |
Client secrets (hashed) |
cf_oauth_tokens |
Issued OAuth tokens |
cf_oauth_auth_codes |
Authorization codes |
cf_oauth_consents |
User consent records |
cf_service_accounts |
Non-human identities |
cf_service_account_key_pairs |
RSA/EC key pairs |
For existing apps, SystemForge supports side-by-side migration:
- Side-by-Side: Create
cf_*tables alongside existing tables - Dual-Write: Write to both old and new tables
- Cutover: Switch reads to SystemForge tables
- Cleanup: Remove old tables
Full documentation is available via MkDocs:
# Install MkDocs
pip install mkdocs mkdocs-material
# Serve locally
mkdocs serve
# Build static site
mkdocs buildContributions are welcome! Please read the contributing guidelines before submitting PRs.
MIT License - see LICENSE file for details.