💎 🔐 Advanced Authentication with TuskLang Ruby

Ruby Documentation

🔐 Advanced Authentication with TuskLang Ruby

"We don't bow to any king" - Ruby Edition

Build enterprise-grade authentication systems with TuskLang's advanced authentication features. From multi-factor authentication to OAuth2 integration, TuskLang provides the security and flexibility you need to protect your Ruby applications.

🚀 Quick Start

Basic Authentication Setup

require 'tusklang'
require 'tusklang/auth'

Initialize authentication system

auth_system = TuskLang::Auth::System.new

Configure authentication

auth_system.configure do |config| config.jwt_secret = ENV['JWT_SECRET'] config.session_timeout = 24.hours config.password_min_length = 8 config.require_mfa = true end

Register authentication strategies

auth_system.register_strategy(:jwt, TuskLang::Auth::Strategies::JWTStrategy.new) auth_system.register_strategy(:oauth2, TuskLang::Auth::Strategies::OAuth2Strategy.new) auth_system.register_strategy(:mfa, TuskLang::Auth::Strategies::MFAStrategy.new)

TuskLang Configuration

config/authentication.tsk

[authentication] enabled: true default_strategy: "jwt" session_timeout: "24h" password_min_length: 8 require_mfa: true

[authentication.jwt] secret: @env("JWT_SECRET", "default-secret") algorithm: "HS256" expiration: "24h" refresh_expiration: "7d"

[authentication.oauth2] providers: { google: { client_id: @env("GOOGLE_CLIENT_ID"), client_secret: @env("GOOGLE_CLIENT_SECRET"), redirect_uri: "https://app.example.com/auth/google/callback" }, github: { client_id: @env("GITHUB_CLIENT_ID"), client_secret: @env("GITHUB_CLIENT_SECRET"), redirect_uri: "https://app.example.com/auth/github/callback" } }

[authentication.mfa] enabled: true methods: ["totp", "sms", "email"] backup_codes_count: 10 totp_issuer: "MyApp"

[authentication.security] password_policy: { min_length: 8, require_uppercase: true, require_lowercase: true, require_numbers: true, require_special: true, prevent_common: true } rate_limiting: { login_attempts: 5, lockout_duration: "15m", reset_after: "1h" }

🎯 Core Features

1. Multi-Strategy Authentication

require 'tusklang/auth'

class AuthenticationController < ApplicationController include TuskLang::Auth::Controller def initialize @auth_system = TuskLang::Auth::System.new @config = TuskLang.parse_file('config/authentication.tsk') setup_strategies end private def setup_strategies # JWT Strategy jwt_strategy = TuskLang::Auth::Strategies::JWTStrategy.new( secret: @config['authentication']['jwt']['secret'], algorithm: @config['authentication']['jwt']['algorithm'], expiration: parse_duration(@config['authentication']['jwt']['expiration']) ) @auth_system.register_strategy(:jwt, jwt_strategy) # OAuth2 Strategy oauth2_strategy = TuskLang::Auth::Strategies::OAuth2Strategy.new( providers: @config['authentication']['oauth2']['providers'] ) @auth_system.register_strategy(:oauth2, oauth2_strategy) # MFA Strategy mfa_strategy = TuskLang::Auth::Strategies::MFAStrategy.new( enabled: @config['authentication']['mfa']['enabled'], methods: @config['authentication']['mfa']['methods'], backup_codes_count: @config['authentication']['mfa']['backup_codes_count'] ) @auth_system.register_strategy(:mfa, mfa_strategy) end def authenticate_user(credentials) # Try different authentication strategies strategies = [:jwt, :oauth2, :mfa] strategies.each do |strategy| begin result = @auth_system.authenticate(strategy, credentials) return result if result.success? rescue => e Rails.logger.warn "Authentication strategy #{strategy} failed: #{e.message}" end end AuthenticationResult.failure("Invalid credentials") end end

2. JWT Authentication Strategy

require 'tusklang/auth'
require 'jwt'

class JWTStrategy include TuskLang::Auth::Strategy def initialize(secret:, algorithm: 'HS256', expiration: 24.hours) @secret = secret @algorithm = algorithm @expiration = expiration end def authenticate(credentials) return AuthenticationResult.failure("Missing token") unless credentials[:token] begin # Decode and verify JWT decoded_token = JWT.decode( credentials[:token], @secret, true, { algorithm: @algorithm } ) payload = decoded_token[0] user_id = payload['user_id'] # Find user user = User.find(user_id) return AuthenticationResult.failure("User not found") unless user # Check if token is expired if payload['exp'] && Time.at(payload['exp']) < Time.now return AuthenticationResult.failure("Token expired") end # Check if user is active return AuthenticationResult.failure("User account disabled") unless user.active? AuthenticationResult.success(user, { token: credentials[:token] }) rescue JWT::DecodeError => e AuthenticationResult.failure("Invalid token: #{e.message}") rescue => e AuthenticationResult.failure("Authentication error: #{e.message}") end end def generate_token(user) payload = { user_id: user.id, email: user.email, role: user.role, exp: (Time.now + @expiration).to_i, iat: Time.now.to_i } JWT.encode(payload, @secret, @algorithm) end def refresh_token(token) begin decoded_token = JWT.decode(token, @secret, false, { algorithm: @algorithm }) payload = decoded_token[0] # Create new token with extended expiration new_payload = payload.merge( exp: (Time.now + @expiration).to_i, iat: Time.now.to_i ) JWT.encode(new_payload, @secret, @algorithm) rescue JWT::DecodeError nil end end end

3. OAuth2 Authentication Strategy

require 'tusklang/auth'
require 'oauth2'

class OAuth2Strategy include TuskLang::Auth::Strategy def initialize(providers:) @providers = providers @clients = {} setup_clients end def authenticate(credentials) provider = credentials[:provider] code = credentials[:code] return AuthenticationResult.failure("Missing provider or code") unless provider && code provider_config = @providers[provider.to_sym] return AuthenticationResult.failure("Unknown provider") unless provider_config begin # Exchange code for access token client = @clients[provider] token = client.auth_code.get_token(code, redirect_uri: provider_config['redirect_uri']) # Get user info from provider user_info = get_user_info(provider, token) # Find or create user user = find_or_create_user(provider, user_info) # Generate JWT token jwt_strategy = TuskLang::Auth::Strategies::JWTStrategy.new( secret: ENV['JWT_SECRET'], algorithm: 'HS256' ) token = jwt_strategy.generate_token(user) AuthenticationResult.success(user, { token: token, provider: provider }) rescue OAuth2::Error => e AuthenticationResult.failure("OAuth2 error: #{e.message}") rescue => e AuthenticationResult.failure("Authentication error: #{e.message}") end end private def setup_clients @providers.each do |provider, config| @clients[provider] = OAuth2::Client.new( config['client_id'], config['client_secret'], authorize_url: get_authorize_url(provider), token_url: get_token_url(provider) ) end end def get_authorize_url(provider) case provider when :google 'https://accounts.google.com/o/oauth2/auth' when :github 'https://github.com/login/oauth/authorize' else raise "Unknown provider: #{provider}" end end def get_token_url(provider) case provider when :google 'https://oauth2.googleapis.com/token' when :github 'https://github.com/login/oauth/access_token' else raise "Unknown provider: #{provider}" end end def get_user_info(provider, token) case provider when :google response = token.get('https://www.googleapis.com/oauth2/v2/userinfo') JSON.parse(response.body) when :github response = token.get('https://api.github.com/user') JSON.parse(response.body) else raise "Unknown provider: #{provider}" end end def find_or_create_user(provider, user_info) # Find existing user by provider ID user = User.find_by(provider: provider.to_s, provider_id: user_info['id']) unless user # Create new user user = User.create!( email: user_info['email'], name: user_info['name'], provider: provider.to_s, provider_id: user_info['id'], avatar_url: user_info['picture'] || user_info['avatar_url'] ) end user end end

4. Multi-Factor Authentication Strategy

require 'tusklang/auth'
require 'rotp'
require 'securerandom'

class MFAStrategy include TuskLang::Auth::Strategy def initialize(enabled: true, methods: ['totp'], backup_codes_count: 10) @enabled = enabled @methods = methods @backup_codes_count = backup_codes_count end def authenticate(credentials) user = credentials[:user] mfa_code = credentials[:mfa_code] mfa_method = credentials[:mfa_method] || 'totp' return AuthenticationResult.failure("MFA not enabled") unless @enabled return AuthenticationResult.failure("User not found") unless user return AuthenticationResult.failure("MFA code required") unless mfa_code case mfa_method when 'totp' authenticate_totp(user, mfa_code) when 'sms' authenticate_sms(user, mfa_code) when 'email' authenticate_email(user, mfa_code) when 'backup' authenticate_backup_code(user, mfa_code) else AuthenticationResult.failure("Unknown MFA method") end end def setup_mfa(user) return { error: "MFA not enabled" } unless @enabled # Generate TOTP secret totp_secret = ROTP::Base32.random # Generate backup codes backup_codes = generate_backup_codes # Save to user user.update!( totp_secret: totp_secret, backup_codes: backup_codes, mfa_enabled: true ) # Generate QR code for TOTP totp = ROTP::TOTP.new(totp_secret, issuer: 'MyApp') qr_code = totp.provisioning_uri(user.email, name: user.name) { totp_secret: totp_secret, qr_code: qr_code, backup_codes: backup_codes } end private def authenticate_totp(user, code) return AuthenticationResult.failure("TOTP not set up") unless user.totp_secret totp = ROTP::TOTP.new(user.totp_secret) if totp.verify(code, drift_behind: 30) AuthenticationResult.success(user, { mfa_method: 'totp' }) else AuthenticationResult.failure("Invalid TOTP code") end end def authenticate_sms(user, code) # Check if SMS code is valid and not expired sms_code = user.sms_codes.find_by( code: code, expires_at: Time.now.., used: false ) if sms_code sms_code.update!(used: true) AuthenticationResult.success(user, { mfa_method: 'sms' }) else AuthenticationResult.failure("Invalid or expired SMS code") end end def authenticate_email(user, code) # Check if email code is valid and not expired email_code = user.email_codes.find_by( code: code, expires_at: Time.now.., used: false ) if email_code email_code.update!(used: true) AuthenticationResult.success(user, { mfa_method: 'email' }) else AuthenticationResult.failure("Invalid or expired email code") end end def authenticate_backup_code(user, code) backup_codes = user.backup_codes || [] if backup_codes.include?(code) # Remove used backup code user.update!(backup_codes: backup_codes - [code]) AuthenticationResult.success(user, { mfa_method: 'backup' }) else AuthenticationResult.failure("Invalid backup code") end end def generate_backup_codes Array.new(@backup_codes_count) { SecureRandom.hex(4).upcase } end end

5. Password Policy Enforcement

require 'tusklang/auth'

class PasswordPolicy def initialize(policy_config) @min_length = policy_config['min_length'] || 8 @require_uppercase = policy_config['require_uppercase'] || false @require_lowercase = policy_config['require_lowercase'] || false @require_numbers = policy_config['require_numbers'] || false @require_special = policy_config['require_special'] || false @prevent_common = policy_config['prevent_common'] || false end def validate(password) errors = [] # Check minimum length if password.length < @min_length errors << "Password must be at least #{@min_length} characters long" end # Check for uppercase letters if @require_uppercase && !password.match?(/[A-Z]/) errors << "Password must contain at least one uppercase letter" end # Check for lowercase letters if @require_lowercase && !password.match?(/[a-z]/) errors << "Password must contain at least one lowercase letter" end # Check for numbers if @require_numbers && !password.match?(/\d/) errors << "Password must contain at least one number" end # Check for special characters if @require_special && !password.match?(/[!@#$%^&*(),.?":{}|<>]/) errors << "Password must contain at least one special character" end # Check against common passwords if @prevent_common && common_password?(password) errors << "Password is too common, please choose a stronger password" end { valid: errors.empty?, errors: errors } end private def common_password?(password) common_passwords = [ 'password', '123456', '123456789', 'qwerty', 'abc123', 'password123', 'admin', 'letmein', 'welcome', 'monkey' ] common_passwords.include?(password.downcase) end end

6. Rate Limiting and Security

require 'tusklang/auth'

class SecurityManager def initialize(config) @config = config @rate_limiter = TuskLang::RateLimiter.new @failed_attempts = {} end def check_rate_limit(identifier, action) key = "#{identifier}:#{action}" # Check if account is locked if account_locked?(identifier) return { allowed: false, reason: "Account temporarily locked" } end # Check rate limit if @rate_limiter.exceeded?(key, @config['rate_limiting']['login_attempts']) lock_account(identifier) return { allowed: false, reason: "Too many attempts, account locked" } end { allowed: true } end def record_failed_attempt(identifier) key = "#{identifier}:failed_attempts" @failed_attempts[key] ||= 0 @failed_attempts[key] += 1 # Check if we should lock the account if @failed_attempts[key] >= @config['rate_limiting']['login_attempts'] lock_account(identifier) end end def record_successful_attempt(identifier) key = "#{identifier}:failed_attempts" @failed_attempts[key] = 0 # Unlock account if it was locked unlock_account(identifier) end private def account_locked?(identifier) lock_key = "#{identifier}:locked" locked_until = @rate_limiter.get(lock_key) return false unless locked_until return false if Time.now > locked_until true end def lock_account(identifier) lock_key = "#{identifier}:locked" lockout_duration = parse_duration(@config['rate_limiting']['lockout_duration']) locked_until = Time.now + lockout_duration @rate_limiter.set(lock_key, locked_until, lockout_duration) end def unlock_account(identifier) lock_key = "#{identifier}:locked" @rate_limiter.delete(lock_key) end def parse_duration(duration_string) case duration_string when /(\d+)m/ $1.to_i * 60 when /(\d+)h/ $1.to_i * 3600 else 900 # Default 15 minutes end end end

🔧 Advanced Configuration

Session Management

require 'tusklang/auth'

class SessionManager def initialize(config) @config = config @sessions = {} end def create_session(user, strategy = 'jwt') session_id = SecureRandom.uuid session_data = { user_id: user.id, strategy: strategy, created_at: Time.now, expires_at: Time.now + parse_duration(@config['session_timeout']), ip_address: request.remote_ip, user_agent: request.user_agent } @sessions[session_id] = session_data # Store in database for persistence Session.create!( session_id: session_id, user: user, data: session_data, expires_at: session_data[:expires_at] ) session_id end def validate_session(session_id) session = @sessions[session_id] return nil unless session # Check if session is expired if session[:expires_at] < Time.now delete_session(session_id) return nil end # Extend session if needed extend_session(session_id) session end def delete_session(session_id) @sessions.delete(session_id) # Remove from database Session.where(session_id: session_id).destroy_all end private def extend_session(session_id) session = @sessions[session_id] return unless session session[:expires_at] = Time.now + parse_duration(@config['session_timeout']) # Update database Session.where(session_id: session_id).update_all( expires_at: session[:expires_at] ) end end

Audit Logging

require 'tusklang/auth'

class AuditLogger def initialize @config = TuskLang.parse_file('config/authentication.tsk') end def log_auth_event(user, event_type, details = {}) audit_entry = { user_id: user&.id, event_type: event_type, timestamp: Time.now, ip_address: request.remote_ip, user_agent: request.user_agent, details: details } # Store in database AuditLog.create!(audit_entry) # Send to external logging service if configured if @config['audit']['external_logging'] send_to_external_logger(audit_entry) end end def log_login_success(user, strategy) log_auth_event(user, 'login_success', { strategy: strategy, session_id: session[:session_id] }) end def log_login_failure(email, reason) log_auth_event(nil, 'login_failure', { email: email, reason: reason }) end def log_logout(user) log_auth_event(user, 'logout', { session_id: session[:session_id] }) end def log_password_change(user) log_auth_event(user, 'password_change') end def log_mfa_setup(user, method) log_auth_event(user, 'mfa_setup', { method: method }) end private def send_to_external_logger(audit_entry) # Implementation for external logging service # e.g., Splunk, ELK, etc. end end

🚀 Performance Optimization

Authentication Caching

require 'tusklang/auth'

class AuthenticationCache def initialize @cache = TuskLang::Cache::RedisCache.new @config = TuskLang.parse_file('config/authentication.tsk') end def cache_user_session(user_id, session_data) cache_key = "user_session:#{user_id}" ttl = parse_duration(@config['session_timeout']) @cache.set(cache_key, session_data, ttl) end def get_cached_session(user_id) cache_key = "user_session:#{user_id}" @cache.get(cache_key) end def invalidate_user_cache(user_id) cache_key = "user_session:#{user_id}" @cache.delete(cache_key) end def cache_user_permissions(user_id, permissions) cache_key = "user_permissions:#{user_id}" ttl = 1.hour @cache.set(cache_key, permissions, ttl) end def get_cached_permissions(user_id) cache_key = "user_permissions:#{user_id}" @cache.get(cache_key) end end

🔒 Security Best Practices

Secure Password Hashing

require 'bcrypt'

class PasswordHasher def self.hash_password(password) BCrypt::Password.create(password, cost: 12) end def self.verify_password(password, hash) BCrypt::Password.new(hash) == password end def self.needs_rehash?(hash) BCrypt::Password.new(hash).cost < 12 end end

CSRF Protection

require 'tusklang/auth'

class CSRFProtection def initialize @config = TuskLang.parse_file('config/authentication.tsk') end def generate_token SecureRandom.hex(32) end def verify_token(token, stored_token) return false unless token && stored_token # Use constant-time comparison Rack::Utils.secure_compare(token, stored_token) end def validate_csrf_token(request) token = request.headers['X-CSRF-Token'] || request.params['csrf_token'] stored_token = session[:csrf_token] verify_token(token, stored_token) end end

📊 Monitoring and Analytics

Authentication Analytics

require 'tusklang/auth'

class AuthenticationAnalytics def initialize @metrics = TuskLang::Metrics::Collector.new end def track_login_attempt(strategy, success) @metrics.increment("auth.login_attempts.#{strategy}") @metrics.increment("auth.login_attempts.#{strategy}.#{success ? 'success' : 'failure'}") end def track_mfa_usage(method) @metrics.increment("auth.mfa_usage.#{method}") end def track_session_duration(duration) @metrics.histogram("auth.session_duration", duration) end def get_auth_stats { total_logins: @metrics.get("auth.login_attempts.total"), success_rate: @metrics.get_success_rate("auth.login_attempts"), popular_strategies: @metrics.get_top("auth.login_attempts", 5), mfa_adoption: @metrics.get("auth.mfa_usage.total") } end end

This comprehensive authentication system provides enterprise-grade security features while maintaining the flexibility and power of TuskLang. The combination of multiple authentication strategies, MFA support, and advanced security features creates a robust foundation for protecting Ruby applications.