Authentication
ActiveCanvas provides flexible authentication options for securing the admin interface. This guide covers every supported approach.
Default behavior
Warning: By default, the ActiveCanvas admin panel is open to everyone in development. In production, ActiveCanvas raises a
SecurityErrorand returns a 403 Forbidden response if no authentication is configured.
This is intentional β it lets you get started quickly in development while ensuring you never accidentally deploy an unprotected admin panel.
The production check triggers when both of these are true:
authenticate_adminis not setadmin_parent_controlleris still"ActionController::Base"
Configure at least one of these before deploying.
Option 1: Devise integration
If your app uses Devise, this is the simplest approach. Point authenticate_admin at your Devise authentication method:
# config/initializers/active_canvas.rb
ActiveCanvas.configure do |config|
config.authenticate_admin = :authenticate_user!
end
This calls authenticate_user! as a before_action on every admin controller. Unauthenticated users are redirected to Deviseβs sign-in page.
Restricting to admin users
If only certain users should access the CMS, use a lambda:
ActiveCanvas.configure do |config|
config.authenticate_admin = -> {
authenticate_user!
redirect_to main_app.root_path, alert: "Not authorized" unless current_user.admin?
}
end
Or with Pundit/CanCanCan:
ActiveCanvas.configure do |config|
config.authenticate_admin = -> {
authenticate_user!
authorize :active_canvas, :admin?
}
end
Option 2: Custom parent controller
If your app already has an admin base controller that handles authentication, you can tell ActiveCanvas to inherit from it:
ActiveCanvas.configure do |config|
config.admin_parent_controller = "Admin::ApplicationController"
end
ActiveCanvas admin controllers will inherit all before_action callbacks, authentication logic, and helper methods from your parent controller. This is the cleanest approach if you have an existing admin namespace.
Your parent controller might look like:
# app/controllers/admin/application_controller.rb
class Admin::ApplicationController < ApplicationController
before_action :authenticate_user!
before_action :require_admin!
private
def require_admin!
redirect_to root_path, alert: "Not authorized" unless current_user&.admin?
end
end
When admin_parent_controller is set to something other than "ActionController::Base", ActiveCanvas skips its own authentication checks entirely β it trusts that your parent controller handles everything.
Option 3: HTTP Basic Auth
For simple deployments or staging environments, HTTP Basic Auth provides quick protection without a user model:
ActiveCanvas.configure do |config|
config.authenticate_admin = :http_basic_auth
config.http_basic_user = "admin"
config.http_basic_password = Rails.application.credentials.active_canvas_password
end
Set the password in your Rails credentials:
bin/rails credentials:edit
active_canvas_password: your-secure-password-here
Or use an environment variable:
config.http_basic_password = ENV["ACTIVE_CANVAS_ADMIN_PASSWORD"]
Note: HTTP Basic Auth credentials are compared using
ActiveSupport::SecurityUtils.secure_compareto prevent timing attacks.
Option 4: Lambda-based auth
For full control, pass a lambda or proc. It runs in the context of the controller, so you have access to request, session, cookies, and params:
ActiveCanvas.configure do |config|
config.authenticate_admin = -> {
# Token-based authentication
token = request.headers["X-Admin-Token"] || params[:admin_token]
head :unauthorized unless token == ENV["ADMIN_TOKEN"]
}
end
Another example with IP restriction:
ActiveCanvas.configure do |config|
config.authenticate_admin = -> {
allowed_ips = %w[192.168.1.0/24 10.0.0.0/8]
unless allowed_ips.any? { |cidr| IPAddr.new(cidr).include?(request.remote_ip) }
head :forbidden
end
}
end
Protecting public pages
By default, published pages are accessible to anyone. If you need to restrict access (e.g., for an intranet or members-only site), use authenticate_public:
ActiveCanvas.configure do |config|
# Require login to view any published page
config.authenticate_public = :authenticate_user!
end
Or with custom logic:
ActiveCanvas.configure do |config|
config.authenticate_public = -> {
unless current_user&.active_subscription?
redirect_to main_app.pricing_path, alert: "Subscribe to access this content"
end
}
end
You can also use a custom parent controller for public pages:
ActiveCanvas.configure do |config|
config.public_parent_controller = "Members::ApplicationController"
end
Combining approaches
You can mix and match different strategies for admin and public access:
ActiveCanvas.configure do |config|
# Admin: inherit from your admin base controller
config.admin_parent_controller = "Admin::ApplicationController"
# Public pages: require a logged-in user
config.authenticate_public = :authenticate_user!
# Current user method (used for version tracking)
config.current_user_method = :current_user
end
Priority order
ActiveCanvas resolves authentication in this order:
- If
admin_parent_controlleris set to something other than"ActionController::Base", the parent controller handles everything.authenticate_adminis ignored. - If
authenticate_adminis:http_basic_auth, HTTP Basic Auth is used with the configured credentials. - If
authenticate_adminis a Symbol, it is called as a method on the controller (e.g.,:authenticate_user!). - If
authenticate_adminis a Proc or Lambda, it is executed withinstance_execin the controller context. - If nothing is configured, development allows access; production raises
SecurityError.
Current user tracking
ActiveCanvas uses the current_user_method to identify who made changes. This is used for:
- Version history β showing which user created each version
- AI request tracking β logging who triggered AI operations
ActiveCanvas.configure do |config|
# Default: :current_user (works with Devise out of the box)
config.current_user_method = :current_user
# Custom method name
config.current_user_method = :current_admin
end
If your authentication system does not expose a user object (e.g., HTTP Basic Auth), version tracking will record the change without a user association.
Next steps
- Getting Started β Initial setup guide
- Configuration β Full reference for all config options
- AI Features β AI features also respect authentication settings