Provides permission checking functionality for API requests.
This module implements a flexible permission system that can verify whether a user has the right to execute a specific request. Permissions can be disabled, or configured to check that certain request arguments match the requesting user's identity.
Permission Modes
Disabled Permissions (false)
When check_permission: false is set in the FunConfig, all permission checks pass.
This is useful for public endpoints that don't require authentication or authorization.
Any Authenticated (:any_authenticated)
When check_permission: :any_authenticated is configured, the system verifies that
the request has a valid user_id. Any authenticated user is allowed access.
Argument-Based Permissions ({:arg, arg_name})
When check_permission: {:arg, arg_name} is configured, the system verifies that
the value of the specified argument matches the request's user_id. This ensures
users can only access their own data.
For example, with {:arg, "user_id"}, a request from user "123" will only be
allowed if request.args["user_id"] == "123".
Role-Based Permissions ({:role, allowed_roles})
When check_permission: {:role, allowed_roles} is configured, the system verifies
that the user has one of the allowed roles. Roles are checked against the
request.user_roles field (must be a list of strings or atoms).
For example, with {:role, ["admin", "moderator"]}, only users with those roles
are allowed access.
Examples
# Public endpoint - no permission check
config = %FunConfig{
request_type: "get_public_data",
check_permission: false
}
request = %Request{user_id: "any_user"}
Permission.check_permission(request, config)
# => true
# Any authenticated user
config = %FunConfig{
request_type: "get_profile",
check_permission: :any_authenticated
}
request = %Request{user_id: "user_123"}
Permission.check_permission(request, config)
# => true
request = %Request{user_id: nil}
Permission.check_permission(request, config)
# => false
# User-specific endpoint - must match user_id
config = %FunConfig{
request_type: "get_user_profile",
check_permission: {:arg, "user_id"}
}
# This passes - user accessing their own data
request = %Request{
user_id: "user_123",
args: %{"user_id" => "user_123"}
}
Permission.check_permission(request, config)
# => true
# This fails - user trying to access another user's data
request = %Request{
user_id: "user_123",
args: %{"user_id" => "user_999"}
}
Permission.check_permission(request, config)
# => false
# Role-based access
config = %FunConfig{
request_type: "delete_user",
check_permission: {:role, ["admin"]}
}
request = %Request{
user_id: "user_123",
user_roles: ["admin"]
}
Permission.check_permission(request, config)
# => trueSecurity Considerations
- Always use
check_permission!/2in the execution path to raise on failures - The
check_permission/2function is non-raising and returns a boolean - Missing arguments result in permission denial (returns
false) - Permission checks happen before argument validation and function execution
- All permission failures are logged for audit purposes
- Use specific permission modes rather than
falsewhen possible
Summary
Functions
Exception raised when a permission check fails.
Checks permission and raises an exception if the check fails.
Functions
Exception raised when a permission check fails.
Contains details about the request and the permission mode that was denied.
Checks permission and raises an exception if the check fails.
This is the raising version of check_permission/2. It should be used in the
request execution pipeline where permission failures should halt processing.
Parameters
request- TheRequeststruct containing user information and argumentsfun_config- TheFunConfigstruct with permission settings
Returns
nil- Permission check passed (function returns nothing on success)
Raises
PermissionDenied- If the permission check fails
Examples
request = %Request{
user_id: "user_123",
args: %{"user_id" => "user_999"}
}
config = %FunConfig{check_permission: {:arg, "user_id"}}
# This will raise because user_ids don't match
Permission.check_permission!(request, config)
# ** (PhoenixGenApi.Permission.PermissionDenied) Permission denied...Notes
- Logs a warning with request details when permission is denied
- Always called before request execution in the Executor module
- Returns nothing on success (only side effect is potential exception)