auth

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 10, 2025 License: MIT Imports: 15 Imported by: 0

README

Authentication Module

Go Reference

The Authentication module provides comprehensive authentication capabilities for the Modular framework, including JWT tokens, session management, password hashing, and OAuth2/OIDC integration.

Features

  • JWT Token Management: Generate, validate, and refresh JWT tokens with custom claims
  • Password Security: Secure password hashing using bcrypt with configurable strength requirements
  • Session Management: Create, manage, and track user sessions with configurable storage backends
  • OAuth2/OIDC Support: Integration with OAuth2 providers like Google, GitHub, etc.
  • Flexible Storage: Pluggable user and session storage interfaces with in-memory implementations included
  • Security: Built-in protection against common authentication vulnerabilities

Installation

go get github.com/CrisisTextLine/modular/modules/auth

Configuration

Basic Configuration
auth:
  jwt:
    secret: "your-jwt-secret-key"
    expiration: "24h"
    refresh_expiration: "168h"
    issuer: "your-app-name"
  
  password:
    min_length: 8
    require_upper: true
    require_lower: true
    require_digit: true
    require_special: false
    bcrypt_cost: 12
  
  session:
    store: "memory"
    cookie_name: "session_id"
    max_age: "24h"
    secure: true
    http_only: true
OAuth2 Configuration
auth:
  oauth2:
    providers:
      google:
        client_id: "your-google-client-id"
        client_secret: "your-google-client-secret"
        redirect_url: "http://localhost:8080/auth/google/callback"
        scopes: ["openid", "email", "profile"]
        auth_url: "https://accounts.google.com/o/oauth2/auth"
        token_url: "https://oauth2.googleapis.com/token"
        user_info_url: "https://www.googleapis.com/oauth2/v2/userinfo"

Usage

Basic Setup
package main

import (
    "github.com/CrisisTextLine/modular"
    "github.com/CrisisTextLine/modular/modules/auth"
)

func main() {
    app := modular.NewApplication()
    
    // Register the auth module
    app.RegisterModule(auth.NewModule())
    
    // Start the application
    app.Start()
}
Using the Auth Service
// Get the auth service from the application
var authService auth.AuthService
err := app.GetService(auth.ServiceName, &authService)
if err != nil {
    log.Fatal(err)
}

// Hash a password
hashedPassword, err := authService.HashPassword("userpassword123")
if err != nil {
    log.Fatal(err)
}

// Verify a password
err = authService.VerifyPassword(hashedPassword, "userpassword123")
if err != nil {
    log.Println("Invalid password")
}

// Generate JWT tokens
customClaims := map[string]interface{}{
    "email": "user@example.com",
    "roles": []string{"user", "admin"},
    "permissions": []string{"read", "write"},
}

tokenPair, err := authService.GenerateToken("user-123", customClaims)
if err != nil {
    log.Fatal(err)
}

// Validate a token
claims, err := authService.ValidateToken(tokenPair.AccessToken)
if err != nil {
    log.Println("Invalid token:", err)
    return
}

log.Printf("User ID: %s, Email: %s", claims.UserID, claims.Email)
Session Management
// Create a session
metadata := map[string]interface{}{
    "ip_address": "127.0.0.1",
    "user_agent": "Mozilla/5.0...",
}

session, err := authService.CreateSession("user-123", metadata)
if err != nil {
    log.Fatal(err)
}

// Get a session
retrievedSession, err := authService.GetSession(session.ID)
if err != nil {
    log.Println("Session not found:", err)
    return
}

// Refresh a session (extend expiration)
refreshedSession, err := authService.RefreshSession(session.ID)
if err != nil {
    log.Fatal(err)
}

// Delete a session
err = authService.DeleteSession(session.ID)
if err != nil {
    log.Fatal(err)
}
OAuth2 Integration
// Get OAuth2 authorization URL
state := "random-state-string"
authURL, err := authService.GetOAuth2AuthURL("google", state)
if err != nil {
    log.Fatal(err)
}

// Redirect user to authURL...

// Exchange authorization code for user info
code := "authorization-code-from-callback"
result, err := authService.ExchangeOAuth2Code("google", code, state)
if err != nil {
    log.Fatal(err)
}

log.Printf("OAuth2 Result: %+v", result)
Custom User and Session Stores

You can implement custom storage backends by implementing the UserStore and SessionStore interfaces:

type DatabaseUserStore struct {
    db *sql.DB
}

func (s *DatabaseUserStore) GetUser(ctx context.Context, userID string) (*auth.User, error) {
    // Implement database query
}

func (s *DatabaseUserStore) CreateUser(ctx context.Context, user *auth.User) error {
    // Implement database insert
}

// Implement other UserStore methods...

// Register custom stores
app.RegisterService("user_store", &DatabaseUserStore{db: db})
app.RegisterService("session_store", &RedisSessionStore{client: redisClient})

API Reference

AuthService Interface

The main authentication service interface provides the following methods:

JWT Operations
  • GenerateToken(userID string, claims map[string]interface{}) (*TokenPair, error)
  • ValidateToken(token string) (*Claims, error)
  • RefreshToken(refreshToken string) (*TokenPair, error)
Password Operations
  • HashPassword(password string) (string, error)
  • VerifyPassword(hashedPassword, password string) error
  • ValidatePasswordStrength(password string) error
Session Operations
  • CreateSession(userID string, metadata map[string]interface{}) (*Session, error)
  • GetSession(sessionID string) (*Session, error)
  • DeleteSession(sessionID string) error
  • RefreshSession(sessionID string) (*Session, error)
OAuth2 Operations
  • GetOAuth2AuthURL(provider, state string) (string, error)
  • ExchangeOAuth2Code(provider, code, state string) (*OAuth2Result, error)
Data Structures
User
type User struct {
    ID           string                 `json:"id"`
    Email        string                 `json:"email"`
    PasswordHash string                 `json:"-"`
    Roles        []string               `json:"roles"`
    Permissions  []string               `json:"permissions"`
    Active       bool                   `json:"active"`
    CreatedAt    time.Time              `json:"created_at"`
    UpdatedAt    time.Time              `json:"updated_at"`
    LastLoginAt  *time.Time             `json:"last_login_at,omitempty"`
    Metadata     map[string]interface{} `json:"metadata,omitempty"`
}
Session
type Session struct {
    ID        string                 `json:"id"`
    UserID    string                 `json:"user_id"`
    CreatedAt time.Time              `json:"created_at"`
    ExpiresAt time.Time              `json:"expires_at"`
    IPAddress string                 `json:"ip_address"`
    UserAgent string                 `json:"user_agent"`
    Active    bool                   `json:"active"`
    Metadata  map[string]interface{} `json:"metadata,omitempty"`
}
TokenPair
type TokenPair struct {
    AccessToken  string    `json:"access_token"`
    RefreshToken string    `json:"refresh_token"`
    TokenType    string    `json:"token_type"`
    ExpiresIn    int64     `json:"expires_in"`
    ExpiresAt    time.Time `json:"expires_at"`
}

Testing

The module includes comprehensive tests covering all functionality:

cd modules/auth
go test -v
Test Coverage
  • Configuration validation
  • JWT token generation and validation
  • Password hashing and verification
  • Session management
  • OAuth2 integration
  • Memory store implementations
  • Module lifecycle and dependency injection

Security Considerations

  1. JWT Secret: Use a strong, randomly generated secret for JWT signing
  2. Password Hashing: bcrypt cost should be at least 12 for production
  3. Session Security: Enable secure and httpOnly flags for session cookies
  4. OAuth2: Validate state parameters to prevent CSRF attacks
  5. Token Expiration: Set appropriate expiration times for access and refresh tokens

Examples

See the examples/ directory for complete usage examples including:

  • Basic authentication setup
  • OAuth2 integration
  • Custom middleware implementation
  • Database integration patterns

Dependencies

  • github.com/golang-jwt/jwt/v5 - JWT token handling
  • golang.org/x/crypto - Password hashing
  • golang.org/x/oauth2 - OAuth2 client implementation

License

This module is part of the Modular framework and is licensed under the same terms.

Documentation

Overview

Package auth provides authentication and authorization functionality for modular applications. This module supports JWT tokens, session management, and OAuth2 flows.

The auth module provides:

  • User authentication with configurable stores
  • JWT token generation and validation
  • Session management with configurable backends
  • OAuth2 integration support
  • Password hashing and validation

Usage:

app.RegisterModule(auth.NewModule())

The module registers an "auth" service that implements the AuthService interface, providing methods for user login, token validation, and session management.

Configuration:

The module requires an "auth" configuration section with JWT secrets,
session settings, and OAuth2 configuration.

Index

Constants

View Source
const (
	// ServiceName is the name used to register the auth service.
	// Other modules can reference this service by this name for dependency injection.
	ServiceName = "auth"
)

Variables

View Source
var (
	ErrInvalidConfig      = errors.New("invalid auth configuration")
	ErrInvalidCredentials = errors.New("invalid credentials")
	ErrTokenExpired       = errors.New("token has expired")
	ErrTokenInvalid       = errors.New("token is invalid")
	ErrTokenMalformed     = errors.New("token is malformed")
	ErrUserNotFound       = errors.New("user not found")
	ErrUserAlreadyExists  = errors.New("user already exists")
	ErrPasswordTooWeak    = errors.New("password does not meet requirements")
	ErrSessionNotFound    = errors.New("session not found")
	ErrSessionExpired     = errors.New("session has expired")
	ErrOAuth2Failed       = errors.New("oauth2 authentication failed")
	ErrProviderNotFound   = errors.New("oauth2 provider not found")
)

Auth module specific errors

Functions

func NewModule

func NewModule() modular.Module

NewModule creates a new authentication module. The returned module must be registered with the application before use.

Example:

authModule := auth.NewModule()
app.RegisterModule(authModule)

Types

type AuthContext

type AuthContext struct {
	User        *User    `json:"user"`
	Session     *Session `json:"session"`
	Claims      *Claims  `json:"claims"`
	Permissions []string `json:"permissions"`
	Roles       []string `json:"roles"`
}

AuthContext represents authentication context in HTTP requests

type AuthService

type AuthService interface {
	// JWT operations
	GenerateToken(userID string, claims map[string]interface{}) (*TokenPair, error)
	ValidateToken(token string) (*Claims, error)
	RefreshToken(refreshToken string) (*TokenPair, error)

	// Password operations
	HashPassword(password string) (string, error)
	VerifyPassword(hashedPassword, password string) error
	ValidatePasswordStrength(password string) error

	// Session operations
	CreateSession(userID string, metadata map[string]interface{}) (*Session, error)
	GetSession(sessionID string) (*Session, error)
	DeleteSession(sessionID string) error
	RefreshSession(sessionID string) (*Session, error)

	// OAuth2 operations
	GetOAuth2AuthURL(provider, state string) (string, error)
	ExchangeOAuth2Code(provider, code, state string) (*OAuth2Result, error)
}

AuthService defines the main authentication service interface

type Claims

type Claims struct {
	UserID      string                 `json:"user_id"`
	Email       string                 `json:"email"`
	Roles       []string               `json:"roles"`
	Permissions []string               `json:"permissions"`
	IssuedAt    time.Time              `json:"iat"`
	ExpiresAt   time.Time              `json:"exp"`
	Issuer      string                 `json:"iss"`
	Subject     string                 `json:"sub"`
	Custom      map[string]interface{} `json:"custom,omitempty"`
}

Claims represents JWT token claims

type Config

type Config struct {
	JWT      JWTConfig      `yaml:"jwt" env:"JWT"`
	Session  SessionConfig  `yaml:"session" env:"SESSION"`
	OAuth2   OAuth2Config   `yaml:"oauth2" env:"OAUTH2"`
	Password PasswordConfig `yaml:"password" env:"PASSWORD"`
}

Config represents the authentication module configuration

func (*Config) Validate

func (c *Config) Validate() error

Validate validates the authentication configuration

type JWTConfig

type JWTConfig struct {
	Secret            string        `yaml:"secret" required:"true" env:"SECRET"`
	Expiration        time.Duration `yaml:"expiration" default:"24h" env:"EXPIRATION"`
	RefreshExpiration time.Duration `yaml:"refresh_expiration" default:"168h" env:"REFRESH_EXPIRATION"` // 7 days
	Issuer            string        `yaml:"issuer" default:"modular-auth" env:"ISSUER"`
	Algorithm         string        `yaml:"algorithm" default:"HS256" env:"ALGORITHM"`
}

JWTConfig contains JWT-related configuration

type MemorySessionStore

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

MemorySessionStore implements SessionStore interface using in-memory storage

func NewMemorySessionStore

func NewMemorySessionStore() *MemorySessionStore

NewMemorySessionStore creates a new in-memory session store

func (*MemorySessionStore) Cleanup

func (s *MemorySessionStore) Cleanup(ctx context.Context) error

Cleanup removes expired sessions

func (*MemorySessionStore) Delete

func (s *MemorySessionStore) Delete(ctx context.Context, sessionID string) error

Delete removes a session

func (*MemorySessionStore) Get

func (s *MemorySessionStore) Get(ctx context.Context, sessionID string) (*Session, error)

Get retrieves a session by ID

func (*MemorySessionStore) Store

func (s *MemorySessionStore) Store(ctx context.Context, session *Session) error

Store stores a session

type MemoryUserStore

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

MemoryUserStore implements UserStore interface using in-memory storage

func NewMemoryUserStore

func NewMemoryUserStore() *MemoryUserStore

NewMemoryUserStore creates a new in-memory user store

func (*MemoryUserStore) CreateUser

func (s *MemoryUserStore) CreateUser(ctx context.Context, user *User) error

CreateUser creates a new user

func (*MemoryUserStore) DeleteUser

func (s *MemoryUserStore) DeleteUser(ctx context.Context, userID string) error

DeleteUser deletes a user

func (*MemoryUserStore) GetUser

func (s *MemoryUserStore) GetUser(ctx context.Context, userID string) (*User, error)

GetUser retrieves a user by ID

func (*MemoryUserStore) GetUserByEmail

func (s *MemoryUserStore) GetUserByEmail(ctx context.Context, email string) (*User, error)

GetUserByEmail retrieves a user by email

func (*MemoryUserStore) UpdateUser

func (s *MemoryUserStore) UpdateUser(ctx context.Context, user *User) error

UpdateUser updates an existing user

type Middleware

type Middleware interface {
	RequireAuth(next http.Handler) http.Handler
	OptionalAuth(next http.Handler) http.Handler
	RequireRole(role string) func(http.Handler) http.Handler
	RequirePermission(permission string) func(http.Handler) http.Handler
}

Middleware defines authentication middleware interface

type Module

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

Module implements the modular.Module interface for authentication. It provides comprehensive authentication and authorization functionality including JWT tokens, sessions, and OAuth2 support.

The module is designed to work with pluggable stores for users and sessions, defaulting to in-memory implementations if external stores are not provided.

func (*Module) Constructor

func (m *Module) Constructor() modular.ModuleConstructor

Constructor provides dependency injection for the module. This method creates the authentication service with injected dependencies, using fallback implementations for optional services that aren't provided.

The constructor pattern allows the module to be reconstructed with proper dependency injection after all required services have been resolved.

Dependencies resolved:

  • user_store: External user storage (falls back to memory store)
  • session_store: External session storage (falls back to memory store)

func (*Module) Dependencies

func (m *Module) Dependencies() []string

Dependencies returns the module dependencies. The auth module has no required module dependencies, making it suitable for use as a foundation module that other modules can depend on.

func (*Module) Init

func (m *Module) Init(app modular.Application) error

Init initializes the authentication module. This method validates the configuration and prepares the module for use. The actual service creation happens in the Constructor method to support dependency injection of user and session stores.

func (*Module) Name

func (m *Module) Name() string

Name returns the module name. This name is used for dependency resolution and service registration.

func (*Module) ProvidesServices

func (m *Module) ProvidesServices() []modular.ServiceProvider

ProvidesServices returns the services provided by this module. The auth module provides an authentication service that implements the AuthService interface, offering methods for user login, token validation, and session management.

func (*Module) RegisterConfig

func (m *Module) RegisterConfig(app modular.Application) error

RegisterConfig registers the module's configuration requirements. This method sets up the configuration structure for the auth module, allowing the application to load authentication-related settings.

The auth module expects configuration for:

  • JWT secret keys and token expiration
  • Session configuration (timeouts, secure flags)
  • OAuth2 provider settings
  • Password policy settings

func (*Module) RequiresServices

func (m *Module) RequiresServices() []modular.ServiceDependency

RequiresServices returns the services required by this module. The auth module can optionally use external user and session stores. If these services are not provided, the module will fall back to in-memory implementations suitable for development and testing.

Optional services:

  • user_store: Implementation of UserStore interface for persistent user data
  • session_store: Implementation of SessionStore interface for session persistence

func (*Module) Start

func (m *Module) Start(ctx context.Context) error

Start starts the authentication module. Currently the auth module doesn't require any startup operations, but this method is available for future enhancements like background token cleanup or session maintenance tasks.

func (*Module) Stop

func (m *Module) Stop(ctx context.Context) error

Stop stops the authentication module. This method can be used for cleanup operations like closing database connections or stopping background tasks when they are added in the future.

type OAuth2Config

type OAuth2Config struct {
	Providers map[string]OAuth2Provider `yaml:"providers" env:"PROVIDERS"`
}

OAuth2Config contains OAuth2/OIDC configuration

type OAuth2Provider

type OAuth2Provider struct {
	ClientID     string   `yaml:"client_id" required:"true" env:"CLIENT_ID"`
	ClientSecret string   `yaml:"client_secret" required:"true" env:"CLIENT_SECRET"`
	RedirectURL  string   `yaml:"redirect_url" required:"true" env:"REDIRECT_URL"`
	Scopes       []string `yaml:"scopes" env:"SCOPES"`
	AuthURL      string   `yaml:"auth_url" env:"AUTH_URL"`
	TokenURL     string   `yaml:"token_url" env:"TOKEN_URL"`
	UserInfoURL  string   `yaml:"user_info_url" env:"USER_INFO_URL"`
}

OAuth2Provider represents an OAuth2 provider configuration

type OAuth2Result

type OAuth2Result struct {
	Provider     string                 `json:"provider"`
	UserInfo     map[string]interface{} `json:"user_info"`
	AccessToken  string                 `json:"access_token"`
	RefreshToken string                 `json:"refresh_token"`
	ExpiresAt    time.Time              `json:"expires_at"`
}

OAuth2Result represents the result of OAuth2 authentication

type PasswordConfig

type PasswordConfig struct {
	Algorithm      string `yaml:"algorithm" default:"bcrypt" env:"ALGORITHM"` // bcrypt, argon2
	MinLength      int    `yaml:"min_length" default:"8" env:"MIN_LENGTH"`
	RequireUpper   bool   `yaml:"require_upper" default:"true" env:"REQUIRE_UPPER"`
	RequireLower   bool   `yaml:"require_lower" default:"true" env:"REQUIRE_LOWER"`
	RequireDigit   bool   `yaml:"require_digit" default:"true" env:"REQUIRE_DIGIT"`
	RequireSpecial bool   `yaml:"require_special" default:"false" env:"REQUIRE_SPECIAL"`
	BcryptCost     int    `yaml:"bcrypt_cost" default:"12" env:"BCRYPT_COST"`
}

PasswordConfig contains password-related configuration

type Service

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

Service implements the AuthService interface

func NewService

func NewService(config *Config, userStore UserStore, sessionStore SessionStore) *Service

NewService creates a new authentication service

func (*Service) CreateSession

func (s *Service) CreateSession(userID string, metadata map[string]interface{}) (*Session, error)

CreateSession creates a new user session

func (*Service) DeleteSession

func (s *Service) DeleteSession(sessionID string) error

DeleteSession removes a session

func (*Service) ExchangeOAuth2Code

func (s *Service) ExchangeOAuth2Code(provider, code, state string) (*OAuth2Result, error)

ExchangeOAuth2Code exchanges an OAuth2 authorization code for user info

func (*Service) GenerateToken

func (s *Service) GenerateToken(userID string, customClaims map[string]interface{}) (*TokenPair, error)

GenerateToken creates a new JWT token pair

func (*Service) GetOAuth2AuthURL

func (s *Service) GetOAuth2AuthURL(provider, state string) (string, error)

GetOAuth2AuthURL returns the OAuth2 authorization URL for a provider

func (*Service) GetSession

func (s *Service) GetSession(sessionID string) (*Session, error)

GetSession retrieves a session by ID

func (*Service) HashPassword

func (s *Service) HashPassword(password string) (string, error)

HashPassword hashes a password using bcrypt

func (*Service) RefreshSession

func (s *Service) RefreshSession(sessionID string) (*Session, error)

RefreshSession extends a session's expiration time

func (*Service) RefreshToken

func (s *Service) RefreshToken(refreshTokenString string) (*TokenPair, error)

RefreshToken creates a new token pair using a refresh token

func (*Service) ValidatePasswordStrength

func (s *Service) ValidatePasswordStrength(password string) error

ValidatePasswordStrength validates password against configured requirements

func (*Service) ValidateToken

func (s *Service) ValidateToken(tokenString string) (*Claims, error)

ValidateToken validates a JWT token and returns the claims

func (*Service) VerifyPassword

func (s *Service) VerifyPassword(hashedPassword, password string) error

VerifyPassword verifies a password against its hash

type Session

type Session struct {
	ID        string                 `json:"id"`
	UserID    string                 `json:"user_id"`
	CreatedAt time.Time              `json:"created_at"`
	ExpiresAt time.Time              `json:"expires_at"`
	IPAddress string                 `json:"ip_address"`
	UserAgent string                 `json:"user_agent"`
	Active    bool                   `json:"active"`
	Metadata  map[string]interface{} `json:"metadata,omitempty"`
}

Session represents a user session

type SessionConfig

type SessionConfig struct {
	Store      string        `yaml:"store" default:"memory" env:"STORE"` // memory, redis, database
	CookieName string        `yaml:"cookie_name" default:"session_id" env:"COOKIE_NAME"`
	MaxAge     time.Duration `yaml:"max_age" default:"24h" env:"MAX_AGE"`
	Secure     bool          `yaml:"secure" default:"true" env:"SECURE"`
	HTTPOnly   bool          `yaml:"http_only" default:"true" env:"HTTP_ONLY"`
	SameSite   string        `yaml:"same_site" default:"strict" env:"SAME_SITE"` // strict, lax, none
	Domain     string        `yaml:"domain" env:"DOMAIN"`
	Path       string        `yaml:"path" default:"/" env:"PATH"`
}

SessionConfig contains session-related configuration

type SessionStore

type SessionStore interface {
	Store(ctx context.Context, session *Session) error
	Get(ctx context.Context, sessionID string) (*Session, error)
	Delete(ctx context.Context, sessionID string) error
	Cleanup(ctx context.Context) error // Remove expired sessions
}

SessionStore defines the interface for session storage operations

type TokenPair

type TokenPair struct {
	AccessToken  string    `json:"access_token"`
	RefreshToken string    `json:"refresh_token"`
	TokenType    string    `json:"token_type"`
	ExpiresIn    int64     `json:"expires_in"`
	ExpiresAt    time.Time `json:"expires_at"`
}

TokenPair represents an access token and refresh token pair

type User

type User struct {
	ID           string                 `json:"id"`
	Email        string                 `json:"email"`
	PasswordHash string                 `json:"-"` // Never serialize password hash
	Roles        []string               `json:"roles"`
	Permissions  []string               `json:"permissions"`
	Active       bool                   `json:"active"`
	CreatedAt    time.Time              `json:"created_at"`
	UpdatedAt    time.Time              `json:"updated_at"`
	LastLoginAt  *time.Time             `json:"last_login_at,omitempty"`
	Metadata     map[string]interface{} `json:"metadata,omitempty"`
}

User represents a user in the authentication system

type UserStore

type UserStore interface {
	GetUser(ctx context.Context, userID string) (*User, error)
	GetUserByEmail(ctx context.Context, email string) (*User, error)
	CreateUser(ctx context.Context, user *User) error
	UpdateUser(ctx context.Context, user *User) error
	DeleteUser(ctx context.Context, userID string) error
}

UserStore defines the interface for user storage operations

Jump to

Keyboard shortcuts

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