Authentication
Securing your PromptEngine installation
PromptEngine Authentication Guide
PromptEngine provides flexible authentication options that integrate seamlessly with your Rails application's existing authentication system. Since prompt templates may contain sensitive business logic or data, it's important to properly secure access to the PromptEngine admin interface.
Authentication Options
Option 1: Route-level Authentication with Devise
If you're using Devise, you can authenticate at the routing level:
# config/routes.rb
Rails.application.routes.draw do
# Require any authenticated user
authenticate :user do
mount PromptEngine::Engine => "/prompt_engine"
end
# Or require specific role/permission
authenticate :user, ->(user) { user.admin? } do
mount PromptEngine::Engine => "/prompt_engine"
end
# Or with a more complex check
authenticate :user, ->(user) { user.has_role?(:prompt_manager) || user.admin? } do
mount PromptEngine::Engine => "/prompt_engine"
end
end
Option 2: Basic Authentication with Middleware
For simple deployments or staging environments, you can use HTTP Basic Authentication:
# config/initializers/prompt_engine.rb
PromptEngine::Engine.middleware.use(Rack::Auth::Basic) do |username, password|
ActiveSupport::SecurityUtils.secure_compare(
Rails.application.credentials.prompt_engine_username, username
) & ActiveSupport::SecurityUtils.secure_compare(
Rails.application.credentials.prompt_engine_password, password
)
end
Configure your credentials:
rails credentials:edit
prompt_engine_username: admin
prompt_engine_password: secure_password_here
Option 3: Custom Authentication with ActiveSupport Hooks
For maximum flexibility, you can extend PromptEngine's ApplicationController to use your application's authentication system:
# config/initializers/prompt_engine.rb
ActiveSupport.on_load(:prompt_engine_application_controller) do
# The context here is PromptEngine::ApplicationController
before_action :authenticate_admin!
private
def authenticate_admin!
unless current_user&.can_manage_prompts?
redirect_to main_app.root_path, alert: "Not authorized"
end
end
def current_user
# Use your app's current user method
# For example, if using Devise:
main_app.current_user
end
end
Option 4: Rails 8 Built-in Authentication
If you're using Rails 8's new authentication generator, PromptEngine works seamlessly:
First, generate Rails authentication if you haven't already:
rails generate authentication
Then use the route-level authentication:
# config/routes.rb
Rails.application.routes.draw do
# Using Rails 8's authenticated constraint
constraints ->(request) { Current.session = Session.find_by(id: request.session[:session_id]) } do
mount PromptEngine::Engine => "/prompt_engine"
end
end
Or customize via ActiveSupport hook:
# config/initializers/prompt_engine.rb
ActiveSupport.on_load(:prompt_engine_application_controller) do
include Authentication # Rails 8's authentication concern
before_action :require_authentication
# Optionally add role checking
before_action do
redirect_to root_path unless Current.user&.admin?
end
end
Option 5: Custom Authentication Systems
For other authentication systems (like Authlogic, Sorcery, or custom implementations):
# config/initializers/prompt_engine.rb
ActiveSupport.on_load(:prompt_engine_application_controller) do
# Include your authentication module
include MyApp::Authentication
before_action :require_login
before_action :require_admin_role
private
def require_admin_role
unless current_user.has_permission?(:manage_prompts)
render plain: "403 Forbidden", status: :forbidden
end
end
end
Disabling Authentication (Development Only)
For development environments where authentication isn't needed:
# config/initializers/prompt_engine.rb
ActiveSupport.on_load(:prompt_engine_application_controller) do
# Skip all authentication in development
skip_before_action :authenticate_user! if Rails.env.development?
end
⚠️ WARNING: Never disable authentication in production!
API Authentication
If you plan to build API endpoints that use PromptEngine, you can add token-based authentication:
# config/initializers/prompt_engine.rb
ActiveSupport.on_load(:prompt_engine_application_controller) do
before_action :authenticate_api_request, if: :api_request?
private
def api_request?
request.format.json? || request.headers['Accept']&.include?('application/json')
end
def authenticate_api_request
token = request.headers['Authorization']&.split(' ')&.last
unless valid_api_token?(token)
render json: { error: 'Unauthorized' }, status: :unauthorized
end
end
def valid_api_token?(token)
# Implement your token validation logic
ApiToken.active.exists?(token: token)
end
end
Multiple Authentication Methods
You can combine authentication methods for different scenarios:
# config/initializers/prompt_engine.rb
ActiveSupport.on_load(:prompt_engine_application_controller) do
# Skip default authentication
skip_before_action :authenticate_user!, raise: false
# Add custom authentication logic
before_action :authenticate_by_any_method!
private
def authenticate_by_any_method!
return if authenticated_via_session?
return if authenticated_via_basic_auth?
return if authenticated_via_api_token?
redirect_to main_app.login_path
end
def authenticated_via_session?
current_user.present?
end
def authenticated_via_basic_auth?
authenticate_with_http_basic do |username, password|
username == Rails.application.credentials.prompt_engine_username &&
password == Rails.application.credentials.prompt_engine_password
end
end
def authenticated_via_api_token?
# Check for API token in headers
request.headers['X-API-Key'] == Rails.application.credentials.prompt_engine_api_key
end
end
Testing with Authentication
When writing tests, you'll need to handle authentication:
# spec/support/prompt_engine_auth.rb
module PromptEngineAuthHelper
def login_as_admin
user = create(:user, :admin)
sign_in user # If using Devise
end
def with_basic_auth
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('admin', 'password')
{ 'HTTP_AUTHORIZATION' => credentials }
end
end
# In your tests
RSpec.describe "PromptEngine Admin", type: :request do
it "requires authentication" do
get prompt_engine.prompts_path
expect(response).to redirect_to(login_path)
end
it "allows authenticated access" do
login_as_admin
get prompt_engine.prompts_path
expect(response).to be_successful
end
end
Security Best Practices
- Always authenticate in production - Never leave the admin interface unprotected
- Use secure passwords - If using basic auth, use strong, unique passwords
- Implement proper authorization - Not just authentication, but also check permissions
- Audit access - Log who accesses and modifies prompts
- Use HTTPS - Always serve PromptEngine over HTTPS in production
- Rotate credentials - Regularly update API keys and passwords
Troubleshooting
"undefined method 'current_user'"
Make sure to define the method or include the appropriate module:
ActiveSupport.on_load(:prompt_engine_application_controller) do
def current_user
# Define how to get the current user in your app
User.find_by(id: session[:user_id])
end
end
Infinite redirect loops
Ensure you're not redirecting to a path that also requires authentication:
def authenticate_admin!
unless current_user&.admin?
redirect_to main_app.root_path # Not another protected path
end
end
Basic auth not working
Check that credentials are properly set:
rails credentials:show
Methods not available in engine controller
Use main_app
helper to access main application's routes and helpers:
redirect_to main_app.login_path
main_app.current_user
Summary
PromptEngine's authentication is designed to be flexible and work with your existing authentication system. Choose the approach that best fits your application:
- Devise users: Use route-level authentication
- Simple deployments: Use basic authentication
- Custom needs: Use ActiveSupport hooks
- Rails 8 apps: Use the built-in authentication
- API access: Add token-based authentication
The key principle is that PromptEngine doesn't impose its own authentication system but integrates with yours, giving you full control over who can access and manage your AI prompts.