CoreForge 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
- 🔐 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
- 🌐 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
go get github.com/grokify/coreforgeCoreForge provides Ent schemas with cf_ table prefix for side-by-side migration.
package main
import (
"context"
"github.com/grokify/coreforge/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("[email protected]").
SetName("Example User").
Save(context.Background())
}Compose CoreForge 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/coreforge/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/coreforge/session/jwt"
"github.com/grokify/coreforge/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/coreforge/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/coreforge/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/coreforge/authz"
"github.com/grokify/coreforge/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/coreforge/
├── 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
│
└── 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 |
CoreForge 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, CoreForge 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 CoreForge 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.