Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 1 addition & 209 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -142,215 +142,7 @@ buffer_size = 100

[plugins]

# --- Config Manager Plugin (allows runtime configuration changes via the Admin API) ---

# [plugins.config_manager]
# enabled = true

# --- Access Control Plugin (role based access control) ---

# [plugins.access_control]
# enabled = true

# --- Admin Plugin (user, state, and impersonation operations) ---

# [plugins.admin]
# enabled = true
# impersonation_max_expires_in = "15m"

# --- Secondary Storage Plugin (provides secondary storage backends for other plugins) ---

[plugins.secondary_storage]
enabled = true
provider = "memory" # Options: "memory", "database", "redis"

[plugins.secondary_storage.memory]
cleanup_interval = "1m"

# [plugins.secondary_storage.database]
# cleanup_interval = "1m"

# [plugins.secondary_storage.redis]
# SECURITY NOTE: It is recommended to set the 'url' via the
# REDIS_URL environment variable rather than hardcoding it here.
# url = ""
# max_retries = 3
# pool_size = 10
# pool_timeout = "30s"

# --- Email Plugin (handles email sending via SMTP or Resend) ---

[plugins.email]
enabled = true
provider = "smtp" # Options: "smtp", "resend"
# Can also be set via FROM_ADDRESS environment variable
from_address = ""
tls_mode = "starttls" # Options: "off", "starttls", "tls"
# Optional: Fallback provider if primary fails
# fallback_provider = "resend"

# SMTP Configuration (when provider = "smtp")
# [plugins.email.smtp]
# host = ""
# port = # Options: 25, 465, 587, 2525,
# user = ""
# pass = ""

# Resend Configuration (when provider = "resend")
# [plugins.email.resend]
# NOTE: it is recommended to set the Resend API key via the RESEND_API_KEY environment variable rather than hardcoding it here.
# api_key = ""

# --- CSRF Plugin (for protecting against CSRF attacks) ---

[plugins.csrf]
enabled = true
cookie_name = "authula_csrf_token"
header_name = "X-AUTHULA-CSRF-TOKEN"
max_age = "24h"
secure = false
same_site = "lax" # Options: "lax", "strict", "none" (Note: HttpOnly=false and Secure=true are hardcoded for Double-Submit Cookie pattern)
# Go 1.25+ Header-based CSRF Protection (Recommended)
# When enabled, validates cross-origin requests using Sec-Fetch-Site and Origin/Host headers.
# This provides defense-in-depth alongside token validation.
# Disabled by default for specific clients (mobile apps, CLI tools, webhooks).
enable_header_protection = false

# --- Email/Password Plugin ---

[plugins.email_password]
enabled = true
min_password_length = 8
max_password_length = 128
disable_sign_up = false
require_email_verification = true
auto_sign_in = true
send_email_on_sign_up = true
send_email_on_sign_in = false
email_verification_expires_in = "24h"
password_reset_expires_in = "1h"
request_email_change_expires_in = "1h"

# --- OAuth2 Plugin (for social logins) ---

# [plugins.oauth2]
# enabled = true

# SECURITY NOTE: It is recommended to set the 'client_secret' for each of these via their
# respective environment variables as shown in the .env.example file rather than hardcoding it here.
# [plugins.oauth2.providers.discord]
# enabled = true
# client_id = "your-client-id"
# client_secret = "your-client-secret"
# redirect_url = "http://localhost:8080/auth/oauth2/callback/discord"
# scopes = []

# [plugins.oauth2.providers.github]
# enabled = true
# client_id = "your-client-id"
# client_secret = "your-client-secret"
# redirect_url = "http://localhost:8080/auth/oauth2/callback/github"
# scopes = []

# [plugins.oauth2.providers.google]
# enabled = true
# client_id = "your-client-id"
# client_secret = "your-client-secret"
# redirect_url = "http://localhost:8080/auth/oauth2/callback/google"
# scopes = []

# Example: Additional fields for a custom OAuth2 provider
# auth_url = "https://provider.com/oauth2/authorize"
# token_url = "https://provider.com/oauth2/token"
# user_info_url = "https://provider.com/oauth2/userinfo"
# user_id_field = "sub"
# email_field = "email"
# name_field = "name"
# picture_field = "picture"

# Example: Generic OAuth2 Provider Configuration
# You can add any custom OAuth2 provider by specifying a new section under [plugins.oauth2.providers.<provider_name>]
# Replace <provider_name> with your desired provider key (e.g., "mycustom")
# The following is a template for a generic OAuth2 provider:
#
# [plugins.oauth2.providers.mycustom]
# enabled = true
# client_id = "your-client-id"
# client_secret = "your-client-secret"
# redirect_url = "http://localhost:8080/auth/oauth2/callback/mycustom"
# auth_url = "https://provider.com/oauth2/authorize"
# token_url = "https://provider.com/oauth2/token"
# user_info_url = "https://provider.com/oauth2/userinfo"
# scopes = ["profile", "email"]
# # Optional: Custom field mappings if your provider returns non-standard fields
# user_id_field = "sub"
# email_field = "email_address"
# name_field = "full_name"
# picture_field = "avatar_url"

# --- Session Plugin (use for SSR apps) ---

# Cookie-based session authentication that stores session tokens as HTTP-only cookies
# Note: Client IP address and User-Agent are automatically captured from the request and
# stored in the session record for security audit trails and session management features.
[plugins.session]
enabled = true

# --- JWT Plugin (use for SPAs and mobile apps) ---

# [plugins.jwt]
# enabled = true
# algorithm = "eddsa"
# key_rotation_interval = "720h"
# key_rotation_grace_period = "1h"
# expires_in = "15m"
# refresh_expires_in = "168h"
# jwks_cache_ttl = "5m"
# refresh_grace_period = "1m"

# --- Bearer Plugin (use for SPAs and mobile apps) ---

# [plugins.bearer]
# enabled = true
# header_name = "Authorization"

# --- Rate Limit Plugin (to prevent abuse and brute-force attacks) ---

# [plugins.ratelimit]
# enabled = true
# window = "1m"
# max = 100
# prefix = "ratelimit:"
# provider = "memory" # Options: "memory", "redis", "database"
# [plugins.ratelimit.custom_rules]
# "/path/to/your/endpoint" = { disabled = false, window = "1m", max = 5, prefix = "" }
#
# Optional: Configure cleanup intervals for storage providers
# [plugins.ratelimit.memory]
# cleanup_interval = "1m" # How often to remove expired entries (default: 1m)
#
# [plugins.ratelimit.database]
# cleanup_interval = "1m" # How often to remove expired entries from database (default: 1m)

# --- Magic Link Plugin (Passwordless Authentication) ---

# [plugins.magic_link]
# enabled = true
# expires_in = "15m"
# disable_sign_up = false

# --- TOTP Plugin (Time-based One-Time Password) ---

# [plugins.totp]
# enabled = true
# skip_verification_on_enable = false
# backup_code_count = 10
# trusted_device_duration = "720h"
# trusted_devices_auto_cleanup = true
# trusted_devices_cleanup_interval = "1h"
# pending_token_expiry = "10m"
# secure_cookie = false
# same_site = "lax" # Options: "lax", "strict", "none"
# Follow the docs for plugin-specific configuration options under the "Plugins" section.

# -----------------------------------
# - Route-to-Plugin Mappings (Standalone Mode)
Expand Down
19 changes: 7 additions & 12 deletions models/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,15 @@ const (
ServiceSession ServiceID = "session_service"
ServiceVerification ServiceID = "verification_service"
ServiceToken ServiceID = "token_service"
ServicePassword ServiceID = "password_service"

// EMAIL
ServicePassword ServiceID = "password_service"
ServiceMailer ServiceID = "mailer_service"

// JWT
ServiceJWT ServiceID = "jwt_service"

// CONFIG
ServiceConfigManager ServiceID = "config_manager_service"
ServiceAdmin ServiceID = "admin_service"

// STORAGE
// Plugins
ServiceAccessControl ServiceID = "access_control_service"
ServiceAdmin ServiceID = "admin_service"
ServiceSecondaryStorage ServiceID = "secondary_storage_service"
ServiceMailer ServiceID = "mailer_service"
ServiceJWT ServiceID = "jwt_service"
ServiceConfigManager ServiceID = "config_manager_service"
)

func (id ServiceID) String() string {
Expand Down
4 changes: 4 additions & 0 deletions plugins/access-control/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ func (p *AccessControlPlugin) Init(ctx *models.PluginContext) error {
userRolesService := services.NewUserRolesService(userRolesRepo, rolesRepo)
userPermissionsService := services.NewUserPermissionsService(userPermissionsRepo)

accessControlService := services.NewAccessControlService(rolesService)

useCases := usecases.NewAccessControlUseCases(
usecases.NewRolesUseCase(rolesService),
usecases.NewPermissionsUseCase(permissionsService),
Expand All @@ -63,6 +65,8 @@ func (p *AccessControlPlugin) Init(ctx *models.PluginContext) error {
)
p.Api = NewAPI(useCases)

ctx.ServiceRegistry.Register(models.ServiceAccessControl.String(), accessControlService)

return nil
}

Expand Down
20 changes: 20 additions & 0 deletions plugins/access-control/services/access_control_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package services

import "context"

type AccessControlService struct {
rolesService *RolesService
}

func NewAccessControlService(rolesService *RolesService) *AccessControlService {
return &AccessControlService{rolesService: rolesService}
}

func (s *AccessControlService) RoleExists(ctx context.Context, roleName string) (bool, error) {
role, err := s.rolesService.GetRoleByName(ctx, roleName)
if err != nil {
return false, err
}

return role != nil && role.ID != "", nil
}
7 changes: 7 additions & 0 deletions services/access_control.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package services

import "context"

type AccessControlService interface {
RoleExists(ctx context.Context, roleName string) (bool, error)
}