core

package module
v0.0.0-...-b140ed9 Latest Latest
Warning

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

Go to latest
Published: May 11, 2026 License: MIT Imports: 17 Imported by: 0

README

go-core

A multi-tenant authentication and authorization module for Go. Built on Gin, PostgreSQL (pgx/SQLC), and Redis, it handles JWT auth, OAuth2 social login, WebAuthn/passkeys, magic links, two-factor authentication, RBAC, an OIDC provider, webhooks, brute-force protection, GeoIP rules, session groups for cross-app SSO, and an embedded HTMX admin GUI. Drop it into your backend and skip building auth from scratch.

Quick Start

package main

import (
	"log"

	"github.com/gin-gonic/gin"

	core "github.com/MrF1ow/go-core"
	"github.com/MrF1ow/go-core/app"
)

func main() {
	cfg := core.DefaultConfig()
	cfg.Database.Host = "localhost"
	cfg.Database.Port = 5432
	cfg.Database.DBName = "myapp"
	cfg.Database.User = "postgres"
	cfg.Database.Password = "secret"
	cfg.JWT.Secret = "your-secret-at-least-32-characters-long"

	coreApp, err := app.New(cfg)
	if err != nil {
		log.Fatal(err)
	}
	defer coreApp.Close()

	r := gin.Default()
	coreApp.RegisterRoutes(r)
	r.Run(":8080")
}

That's it. You get registration, login, token refresh, password reset, email verification, 2FA, social login, and more out of the box.

Public API
Function Description
app.New(cfg) Validates config, connects to Postgres, initializes all services
app.NewWithDB(cfg, pool) Same as New but reuses an existing *pgxpool.Pool
app.RegisterRoutes(r) Mounts all routes onto a Gin engine
app.AuthMiddleware() Returns a gin.HandlerFunc for protecting your own routes
app.Close() Shuts down background services and connection pool

Required Config

These must be set or app.New() returns an error:

Field Description
Database.Host PostgreSQL host
Database.Port PostgreSQL port (default: 5432)
Database.DBName Database name
Database.User Database user
Database.Password Database password (not validated, but you need it)
JWT.Secret Signing key for all access and refresh tokens. Minimum 32 characters.

Optional Config

Everything below is off or defaulted until you configure it. DefaultConfig() gives you sensible CORS defaults and reasonable token lifetimes.

Field What it does When unset
Redis Redis connection for token blacklisting and sessions Nil pointer = in-memory cache. Fine for dev, use Redis in production.
Email SMTP config for sending emails Nil = email sending disabled. Magic links, 2FA email codes, and verification emails won't work.
CORS Cross-origin settings Sensible defaults via DefaultConfig(). Override if needed.
OIDC OpenID Connect provider config Disabled.
WebAuthn Passkey and biometric authentication Disabled.
SMS 2FA via Twilio Disabled.
Admin Admin GUI settings, API key, and branding Disabled.
Social OAuth2 social login (Google, Facebook, GitHub) Disabled.
GeoIP IP-based access rules, requires a MaxMind database file Disabled.
Session Session groups, trusted devices, cross-app SSO settings Defaults to single-app mode.
MultiTenant Enables multi-app mode with X-App-ID header False. Single-app mode.
PublicURL Base URL for API links in emails and redirects Empty.
FrontendURL Frontend app URL for redirect targets Empty.
AppName Application name used in emails and admin GUI Empty.
Port Server port for the reference cmd/api implementation Empty.
GinMode Gin framework mode (debug, release, test) Empty (Gin default).

Features

  • JWT authentication (access + refresh tokens)
  • Registration, login, password reset, email verification
  • Magic link authentication
  • OAuth2 social login (Google, Facebook, GitHub)
  • WebAuthn / passkeys
  • Two-factor auth (TOTP, SMS, email, passkey)
  • Role-based access control (RBAC)
  • Multi-tenant with per-app configuration
  • HTMX admin GUI (embedded, no extra files needed)
  • OpenID Connect provider (auth code + PKCE)
  • Webhooks
  • Brute-force protection and account lockout
  • GeoIP-based access rules
  • Session groups (cross-app SSO)
  • Activity logging

Running the Example

Check out examples/basic/main.go for a working setup. You'll need PostgreSQL running with migrations applied.

# Start dependencies
make docker-dev
make migrate-up

# Run the example
go run ./examples/basic

make docker-dev spins up PostgreSQL and Redis in Docker. make migrate-up applies the database schema.

Development

make dev          # Hot reload dev server
make test         # Run all tests
make fmt          # Format code
make lint         # golangci-lint
make security     # gosec + govulncheck scans
make ci           # Run full CI pipeline (fmt, lint, test, security, build)
make build-prod   # Production binary
make setup-admin  # Create admin account for Admin GUI
make swag-init    # Regenerate Swagger docs after API changes

Claude Code Skills

This project includes Claude Code skills for AI-assisted development. They live in .claude/skills/go-core/ and cover:

  • Project map — architecture overview and key directories
  • Route map — all API endpoints and middleware
  • Auth flows — registration, login, token lifecycle, 2FA, OAuth2
  • Data model — database schema and SQLC query patterns
  • Admin GUI — HTMX admin interface structure
  • Email system — email templates and sending logic
  • Security — brute-force protection, GeoIP, CSRF, rate limiting
  • New endpoint — guide for adding new API endpoints
  • Integration — how to consume the module in your app
  • Commits — commit message conventions and scopes

Invoke the hub skill with /go-core in Claude Code to get routed to the right reference.

Credits

Originally forked from gjovanovicst/golang-auth-api. Significantly reworked into a consumable Go module — migrated from GORM to pgx/SQLC, embedded all assets, added a public API, and cleaned up the architecture.

License

MIT.

Documentation

Overview

Package core defines the configuration types and shared interfaces for the go-core authentication module. Consuming applications build a Config struct and pass it to app.New.

Index

Constants

This section is empty.

Variables

View Source
var ErrCacheKeyNotFound = errors.New("cache: key not found")

ErrCacheKeyNotFound is returned when a key does not exist.

Functions

func RunCoreMigrations

func RunCoreMigrations(ctx context.Context, pool *pgxpool.Pool) error

RunCoreMigrations applies all go-core built-in migrations from the embedded migrations directory. Consumers should call this before RunMigrations to ensure the core schema (users, sessions, etc.) exists.

func RunMigrations

func RunMigrations(ctx context.Context, pool *pgxpool.Pool, migrationsDir string) error

RunMigrations applies pending SQL migrations from the given directory on disk. It skips rollback files (*_rollback.sql) and down migration files (*.down.sql). Migrations are tracked in the schema_migrations table.

func ValidateConfig

func ValidateConfig(cfg Config) error

ValidateConfig checks that all required Config fields are set. Returns a descriptive error for the first missing or invalid field. Called by app.New() before any initialization or connections.

Types

type AdminBrandingConfig

type AdminBrandingConfig struct {
	OrgName          string
	LogoURL          string
	PrimaryColor     string
	SecondaryColor   string
	BorderRadius     string
	SidebarColor     string
	SidebarTextColor string
}

AdminBrandingConfig customizes the admin dashboard appearance. All fields are optional — zero values produce the default Bootstrap look.

type AdminConfig

type AdminConfig struct {
	APIKey        string
	Email         string
	SessionTTL    time.Duration
	BaseURL       string
	AdminBasePath string // URL path prefix for admin GUI (default "/gui")
	Branding      AdminBrandingConfig
}

AdminConfig holds admin GUI / API settings.

type CORSConfig

type CORSConfig struct {
	AllowedOrigins   []string
	AllowedMethods   []string
	AllowedHeaders   []string
	ExposeHeaders    []string
	MaxAge           time.Duration
	AllowCredentials bool
}

CORSConfig holds Cross-Origin Resource Sharing settings.

type CacheStore

type CacheStore interface {
	// Key-value operations
	Get(ctx context.Context, key string) (string, error)
	Set(ctx context.Context, key string, value string, ttl time.Duration) error
	Delete(ctx context.Context, keys ...string) error
	Exists(ctx context.Context, key string) (bool, error)

	// Counter operations (for rate limiting, brute force tracking)
	Increment(ctx context.Context, key string, ttl time.Duration) (int64, error)

	// Hash operations (for sessions)
	HSet(ctx context.Context, key string, fields map[string]any) error
	HGetAll(ctx context.Context, key string) (map[string]string, error)
	HGet(ctx context.Context, key, field string) (string, error)

	// Set operations (for session indexes)
	SAdd(ctx context.Context, key string, members ...string) error
	SMembers(ctx context.Context, key string) ([]string, error)
	SRem(ctx context.Context, key string, members ...string) error

	// TTL operations
	Expire(ctx context.Context, key string, ttl time.Duration) error
	TTL(ctx context.Context, key string) (time.Duration, error)

	// Key scanning (for background jobs like session expiry detection)
	Scan(ctx context.Context, cursor uint64, pattern string, count int64) (keys []string, nextCursor uint64, err error)

	// Ping for health checks
	Ping(ctx context.Context) error
}

CacheStore abstracts key-value and hash storage for tokens, sessions, and rate limiting.

type Config

type Config struct {
	Database    DatabaseConfig
	Redis       *RedisConfig // nil = use in-memory store
	JWT         JWTConfig
	Email       *EmailConfig // nil = no email sending
	CORS        CORSConfig
	OIDC        OIDCConfig
	WebAuthn    WebAuthnConfig
	SMS         SMSConfig
	Admin       AdminConfig
	Social      SocialConfig
	GeoIP       GeoIPConfig
	Session     SessionConfig
	MultiTenant bool
	PublicURL   string
	FrontendURL string
	AppName     string
	Port        string
	GinMode     string
}

Config is the top-level configuration for the go-core module. Consuming applications construct this struct however they want (env vars, files, flags, etc.). The core module never reads environment variables itself.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config populated with sensible defaults that match the application's built-in Viper defaults.

type DatabaseConfig

type DatabaseConfig struct {
	Host     string
	Port     int
	User     string
	Password string
	DBName   string
	SSLMode  string
}

DatabaseConfig holds PostgreSQL connection parameters.

type EmailConfig

type EmailConfig struct {
	Host     string
	Port     int
	Username string
	Password string
	From     string
	UseTLS   bool
}

EmailConfig holds SMTP / email sending settings. Set Config.Email to nil to disable all email sending.

type EmailSender

type EmailSender interface {
	Send(ctx context.Context, to, subject, htmlBody, textBody string) error
}

EmailSender abstracts email transport. The core handles template rendering; this interface handles the actual sending.

type GeoIPConfig

type GeoIPConfig struct {
	DBPath string
}

GeoIPConfig holds GeoIP database settings.

type JWTConfig

type JWTConfig struct {
	Secret          string
	AccessTokenTTL  time.Duration
	RefreshTokenTTL time.Duration
}

JWTConfig holds JSON Web Token settings.

type MemoryCacheStore

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

MemoryCacheStore is a thread-safe in-memory implementation of CacheStore. Intended for development and testing only.

func NewMemoryCacheStore

func NewMemoryCacheStore() *MemoryCacheStore

NewMemoryCacheStore creates a MemoryCacheStore and starts the background GC.

func (*MemoryCacheStore) Close

func (m *MemoryCacheStore) Close()

Close stops the background GC goroutine.

func (*MemoryCacheStore) Delete

func (m *MemoryCacheStore) Delete(_ context.Context, keys ...string) error

Delete removes one or more keys.

func (*MemoryCacheStore) Exists

func (m *MemoryCacheStore) Exists(_ context.Context, key string) (bool, error)

Exists reports whether a key is present and not expired.

func (*MemoryCacheStore) Expire

func (m *MemoryCacheStore) Expire(_ context.Context, key string, ttl time.Duration) error

Expire sets the TTL on a key-value entry. Has no effect if the key does not exist.

func (*MemoryCacheStore) Get

func (m *MemoryCacheStore) Get(_ context.Context, key string) (string, error)

Get retrieves a string value. Returns ErrCacheKeyNotFound if absent or expired.

func (*MemoryCacheStore) HGet

func (m *MemoryCacheStore) HGet(_ context.Context, key, field string) (string, error)

HGet returns a single hash field. Returns ErrCacheKeyNotFound if absent.

func (*MemoryCacheStore) HGetAll

func (m *MemoryCacheStore) HGetAll(_ context.Context, key string) (map[string]string, error)

HGetAll returns all fields of a hash.

func (*MemoryCacheStore) HSet

func (m *MemoryCacheStore) HSet(_ context.Context, key string, fields map[string]any) error

HSet sets fields on a hash.

func (*MemoryCacheStore) Increment

func (m *MemoryCacheStore) Increment(_ context.Context, key string, ttl time.Duration) (int64, error)

Increment atomically increments a counter. The existing TTL is preserved; if the key is new the provided ttl is applied.

func (*MemoryCacheStore) Ping

Ping always returns nil for the in-memory store.

func (*MemoryCacheStore) SAdd

func (m *MemoryCacheStore) SAdd(_ context.Context, key string, members ...string) error

SAdd adds members to a set.

func (*MemoryCacheStore) SMembers

func (m *MemoryCacheStore) SMembers(_ context.Context, key string) ([]string, error)

SMembers returns all members of a set.

func (*MemoryCacheStore) SRem

func (m *MemoryCacheStore) SRem(_ context.Context, key string, members ...string) error

SRem removes members from a set.

func (*MemoryCacheStore) Scan

func (m *MemoryCacheStore) Scan(_ context.Context, cursor uint64, pattern string, count int64) ([]string, uint64, error)

Scan iterates keys matching a glob pattern. The cursor is an index into sorted keys. Returns matching keys, the next cursor (0 when done), and any error.

func (*MemoryCacheStore) Set

func (m *MemoryCacheStore) Set(_ context.Context, key string, value string, ttl time.Duration) error

Set stores a value. A zero ttl means no expiry.

func (*MemoryCacheStore) TTL

TTL returns the remaining time-to-live for a key. Returns -2 if the key does not exist, -1 if it has no expiry.

type OIDCConfig

type OIDCConfig struct {
	Enabled      bool
	DefaultAppID string
	IDTokenTTL   time.Duration
	AuthCodeTTL  time.Duration
}

OIDCConfig holds OpenID Connect provider settings.

type RedisCacheStore

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

RedisCacheStore implements CacheStore using a Redis client.

func NewRedisCacheStore

func NewRedisCacheStore(cfg RedisConfig) (*RedisCacheStore, error)

NewRedisCacheStore creates a Redis client from cfg, pings it, and returns the store.

func (*RedisCacheStore) Client

func (r *RedisCacheStore) Client() *redis.Client

Client returns the underlying *redis.Client for Redis-specific operations such as PubSub that cannot be abstracted behind CacheStore.

func (*RedisCacheStore) Delete

func (r *RedisCacheStore) Delete(ctx context.Context, keys ...string) error

Delete removes one or more keys.

func (*RedisCacheStore) Exists

func (r *RedisCacheStore) Exists(ctx context.Context, key string) (bool, error)

Exists reports whether a key is present.

func (*RedisCacheStore) Expire

func (r *RedisCacheStore) Expire(ctx context.Context, key string, ttl time.Duration) error

Expire sets the TTL on an existing key.

func (*RedisCacheStore) Get

func (r *RedisCacheStore) Get(ctx context.Context, key string) (string, error)

Get retrieves a string value by key. Returns ErrCacheKeyNotFound if key is absent.

func (*RedisCacheStore) HGet

func (r *RedisCacheStore) HGet(ctx context.Context, key, field string) (string, error)

HGet returns a single field from a hash. Returns ErrCacheKeyNotFound if absent.

func (*RedisCacheStore) HGetAll

func (r *RedisCacheStore) HGetAll(ctx context.Context, key string) (map[string]string, error)

HGetAll returns all field-value pairs for a hash key.

func (*RedisCacheStore) HSet

func (r *RedisCacheStore) HSet(ctx context.Context, key string, fields map[string]any) error

HSet sets multiple fields on a hash key.

func (*RedisCacheStore) Increment

func (r *RedisCacheStore) Increment(ctx context.Context, key string, ttl time.Duration) (int64, error)

Increment atomically increments a counter. If the key is new (value becomes 1), the TTL is set.

func (*RedisCacheStore) Ping

func (r *RedisCacheStore) Ping(ctx context.Context) error

Ping checks the Redis connection.

func (*RedisCacheStore) SAdd

func (r *RedisCacheStore) SAdd(ctx context.Context, key string, members ...string) error

SAdd adds members to a set.

func (*RedisCacheStore) SMembers

func (r *RedisCacheStore) SMembers(ctx context.Context, key string) ([]string, error)

SMembers returns all members of a set.

func (*RedisCacheStore) SRem

func (r *RedisCacheStore) SRem(ctx context.Context, key string, members ...string) error

SRem removes members from a set.

func (*RedisCacheStore) Scan

func (r *RedisCacheStore) Scan(ctx context.Context, cursor uint64, pattern string, count int64) ([]string, uint64, error)

Scan iterates keys matching a pattern. Returns matching keys, the next cursor, and any error.

func (*RedisCacheStore) Set

func (r *RedisCacheStore) Set(ctx context.Context, key string, value string, ttl time.Duration) error

Set stores a string value with a TTL.

func (*RedisCacheStore) TTL

func (r *RedisCacheStore) TTL(ctx context.Context, key string) (time.Duration, error)

TTL returns the remaining time-to-live for a key. Returns -2 if the key does not exist, -1 if it has no expiry.

type RedisConfig

type RedisConfig struct {
	Addr     string
	Password string
	DB       int
}

RedisConfig holds Redis connection parameters. Set Config.Redis to nil to use an in-memory store instead.

type SMSConfig

type SMSConfig struct {
	Provider         string
	TwilioAccountSID string
	TwilioAuthToken  string
	TwilioFromNumber string
}

SMSConfig holds SMS provider credentials.

type SessionConfig

type SessionConfig struct {
	TrustedDeviceCookieSameSite string
	GroupExpiryEnabled          bool
	GroupExpiryScanInterval     time.Duration
	GroupKeyspaceNotifEnabled   bool
	RedisNotifyKeyspaceEvents   string // value of REDIS_NOTIFY_KEYSPACE_EVENTS for expiry service
}

SessionConfig holds session and trusted-device settings.

type SocialConfig

type SocialConfig struct {
	AllowedRedirectDomains []string
	DefaultRedirectURI     string
}

SocialConfig holds OAuth2 social-login settings.

type WebAuthnConfig

type WebAuthnConfig struct {
	RPID      string
	RPName    string
	RPOrigins []string
}

WebAuthnConfig holds WebAuthn / passkey relying-party settings.

Directories

Path Synopsis
Package app provides the public entry point for the go-core authentication module.
Package app provides the public entry point for the go-core authentication module.
cmd
api command
migrate_oauth command
setup command
Package docs Code generated by swaggo/swag.
Package docs Code generated by swaggo/swag.
examples
basic command
internal
coreapp
Package coreapp provides the application entry point for go-core.
Package coreapp provides the application entry point for go-core.
log
sms
sso
pkg
dto
jwt
web
Package web provides the embedded admin GUI assets and HTML template renderer used by the go-core admin interface.
Package web provides the embedded admin GUI assets and HTML template renderer used by the go-core admin interface.

Jump to

Keyboard shortcuts

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