Module Access Management with `rAccess`
Source:vignettes/module-access-management.Rmd
module-access-management.RmdThis vignette demonstrates how to implement module-level access
control in teal applications using the rAccess
package integration provided by uteals.
Overview
The rAccess package enables role-based access control
for teal modules, allowing you to:
- Restrict module access based on user permissions
- Implement admin-only functionality
- Dynamically filter modules at runtime
- Provide graceful handling for unauthorized access
Users will only see and interact with modules they are authorized to use.
Quick Start
Here’s a minimal example to get started:
# 1. Create modules
mods <- modules(
tm_data_table("Data Table"),
tm_variable_browser("Variable Browser")
)
# 2. Extract module structure
extract_modules_to_yaml(mods, "panel_str.yml")
# 3. Filter modules by user permissions
filtered_mods <- keep_by_label(mods, c("Data Table"))Configuration
Step 1: Generate Module Structure
Use the extract_modules_to_yaml() function to
automatically generate the module structure:
# Define your teal modules
mods <- modules(
tm_data_table("Data Table"),
tm_variable_browser("Variable Browser"),
tm_g_scatterplot("Scatterplot", x = ..., y = ...),
tm_outliers("Summary Statistics", outlier_var = ...)
)
# Generate YAML structure
extract_modules_to_yaml(mods, "panel_str.yml")This creates:
Step 2: Create rAccess Configuration
Create your main configuration file
(rAccess_config.yml):
# rAccess_config.yml
module: rAccess
parameters:
app_name: TealAccessDemo
board_type: local
access_mode: default
unit_display: 'dropdown'
user_df: !expr tibble::tribble(
~userid, ~username,
"user1", "Regular User",
"user2", "Limited User")
use_rconnect_users: FALSE
verbose: FALSE
secure_mode: FALSE
# Copy the panel_str section from generated file
panel_str:
- access_panel: ADMIN
- access_panel: Modules
access_units:
- unit: Data Table
- unit: Variable Browser
- unit: Scatterplot
- unit: Summary StatisticsImplementation
Pattern 1: Basic Module Filtering
# Filter modules based on user access
user_modules <- c("Data Table", "Variable Browser")
filtered_modules <- keep_by_label(all_modules, user_modules)
# Remove specific modules
restricted_modules <- remove_by_label(all_modules, c("Admin Panel"))Pattern 2: Dynamic Access Control
server <- function(input, output, session) {
# Get user identity
user_id <- ifelse(interactive(), Sys.getenv("USER"), session$user)
# Initialize rAccess
iam <- rAccess$new(user = user_id, config = "rAccess_config.yml")
# Get user permissions
user_access <- iam$get_user_accesslist()
allowed_modules <- unlist(user_access, use.names = FALSE)
# Filter modules
filtered_modules <- keep_by_label(all_modules, allowed_modules)
# Handle edge cases
if (is.null(filtered_modules)) {
filtered_modules <- create_no_access_module()
}
}Complete Application Example
Configuration
# rAccess_config.yml
module: rAccess
parameters:
app_name: TealAccessDemo
board_type: local
access_mode: default
unit_display: 'dropdown'
user_df: !expr tibble::tribble(
~userid, ~username,
"user1", "Regular User",
"user2", "Limited User")
use_rconnect_users: FALSE
verbose: FALSE
secure_mode: FALSE
### Data Setup
# Prepare sample data
data <- teal.data::teal_data(
IRIS = iris,
MTCARS = mtcars,
code = c("IRIS <- iris", "MTCARS <- mtcars")
)
### Module Definition
# Define all available modules
all_modules <- modules(
tm_data_table("Data Table"),
tm_variable_browser("Variable Browser"),
tm_g_scatterplot(
label = "Scatterplot",
x = data_extract_spec(
dataname = "IRIS",
select = select_spec(choices = variable_choices(iris))
),
y = data_extract_spec(
dataname = "IRIS",
select = select_spec(choices = variable_choices(iris))
)
),
tm_outliers(
label = "Summary Statistics",
outlier_var = data_extract_spec(
dataname = "MTCARS",
select = select_spec(choices = variable_choices(mtcars, c("mpg", "hp", "wt")))
)
)
)
### UI Implementation
ui <- bslib::page_navbar(
title = "Teal Access Demo",
# Main application tab
bslib::nav_panel(
"Analytics Modules",
uiOutput("teal_ui")
),
# Admin panel (conditionally visible)
bslib::nav_panel(
"Access Control",
rAccess::module_iam_ui("access_control"),
tags$div(
class = "alert alert-info",
tags$h5("Administrator Panel"),
tags$p("Manage user access and permissions here.")
)
)
)
### Server Implementation
server <- function(input, output, session) {
# User authentication
user_id <- ifelse(interactive(), "user1", session$user)
# Initialize access control
iam <- rAccess$new(user = user_id, config = "rAccess_config.yml")
# Admin module server (conditional)
if (iam$no_admin() || iam$is_admin()) {
rAccess::module_iam_server("access_control", iam)
}
# Filter modules based on permissions
user_access_list <- iam$get_user_accesslist()
users_modules <- unlist(user_access_list, use.names = FALSE)
filtered_modules <- keep_by_label(all_modules, users_modules)
# Handle no access
if (is.null(filtered_modules)) {
filtered_modules <- modules(
module(
label = "No Access",
ui = function(id) tags$div(
class = "alert alert-warning",
h4("Access Restricted"),
p("You do not have permission to access any modules."),
p("Please contact your administrator.")
)
)
)
}
# Render teal UI
output$teal_ui <- renderUI({
tagList(
ui_teal("teal_app", filtered_modules),
ui_session_info("session_info")
)
})
# Teal server
srv_teal("teal_app", data = data, modules = filtered_modules)
srv_session_info("session_info")
}
### Application Launch
# Create and run the application
app <- shinyApp(ui, server)
# For development
if (interactive()) {
runApp(app)
}Running the Example
The app will show different modules based on the user: -
admin: Access to admin panel - other users:
Access based on rAccess permissions - Unauthorized users:
“No Access” message
Note: Until you define and add at least one admin, the admin tab will be accessible by everyone. Once there is at least one admin defined, access control becomes enforced.
Access-boards Storage Setup
In this example, with board_type: local configured in
rAccess_config.yml, access lists are stored locally in the
./data/ directory within your application. Alternative
storage options include AWS S3 or
Posit Connect pins - refer to the rAccess
documentation for configuration details.
Debugging Tips
# Ensure the rAccess configuration (`rAccess_config.yml` in the example) is
accessible by your app.
# Ensure module labels match exactly between configuration and code
# Enable verbose logging
iam <- rAccess$new(user = user_id, config = "config.yml", verbose = TRUE)
# Check user access list
print(iam$get_user_accesslist())
# Verify module labels
print(sapply(all_modules$children, function(x) x$label))Summary
The uteals package provides essential utilities for implementing access control in teal applications:
-
extract_modules_to_yaml(): Automates configuration generation -
keep_by_label(): Filters modules by user permissions -
remove_by_label(): Excludes restricted modules
This integration enables secure, role-based access control while maintaining the flexibility and power of the teal framework.