### Launch Example Applications Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/README.md Demonstrates how to launch the example applications included with the shinyauthr package to showcase integration patterns. ```r # Launch example apps shinyauthr::runExample("basic") shinyauthr::runExample("shinydashboard") shinyauthr::runExample("navbarPage") # Test credentials: user1/pass1 or user2/pass2 ``` -------------------------------- ### Run Example Shiny Apps Source: https://github.com/paulc91/shinyauthr/blob/master/README.md Launch pre-built example applications demonstrating different UI frameworks and functionalities of the shinyauthr package. These examples can be run using the `runExample` function. ```r # login with user1 pass1 or user2 pass2 shinyauthr::runExample("basic") shinyauthr::runExample("shinydashboard") shinyauthr::runExample("navbarPage") ``` -------------------------------- ### Resolving 'Example App Not Found' Error Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/errors.md Addresses the 'Could not find example directory' error, which typically indicates a corrupted package installation. Provides instructions to reinstall the `shinyauthr` package to fix this issue. ```r # WRONG - Package installation corrupted runExample("basic") # Error: Could not find example directory. Try re-installing `shinyauthr`. # Reinstall the package install.packages("shinyauthr") # Or from GitHub remotes::install_github("paulc91/shinyauthr") # Then try again runExample("basic") ``` -------------------------------- ### Basic Authentication Setup Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/module-reference.md Minimal setup for simple credential checking using shinyauthr. Requires 'shiny' and 'shinyauthr' libraries. ```r library(shiny) library(shinyauthr) user_base <- data.frame( user = c("user1", "user2"), password = c("pass1", "pass2") ) ui <- fluidPage( div(class = "pull-right", shinyauthr::logoutUI(id = "logout")), shinyauthr::loginUI(id = "login"), textOutput("welcome") ) server <- function(input, output, session) { logout_init <- shinyauthr::logoutServer( id = "logout", active = reactive(credentials()$user_auth) ) credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) output$welcome <- renderText({ req(credentials()$user_auth) credentials()$info$user }) } shinyApp(ui, server) ``` -------------------------------- ### runExample Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/README.md Launches an example Shiny application to demonstrate the package's functionality. It accepts a character string specifying which example to run. ```APIDOC ## runExample ### Description Launches an example Shiny application. ### Parameters #### Arguments - **example** (character) - "basic", "shinydashboard", or "navbarPage" ### Returns No return value (launches app) ``` -------------------------------- ### runExample Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/runExample.md Launches an example Shiny application to demonstrate shinyauthr authentication. Users can choose from 'basic', 'shinydashboard', or 'navbarPage' examples. ```APIDOC ## runExample ### Description Launches an example Shiny application to demonstrate shinyauthr authentication. Users can choose from 'basic', 'shinydashboard', or 'navbarPage' examples. ### Method `runExample(example = c("basic", "shinydashboard", "navbarPage"))` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters * **example** (character) - Optional - The name of the example app to launch. Must be one of: "basic", "shinydashboard", or "navbarPage". If not specified, an error prompts the user to select one. ### Request Example ```r # Launch the basic example shinyauthr::runExample("basic") # Launch the shinydashboard example shinyauthr::runExample("shinydashboard") # Launch the navbarPage example shinyauthr::runExample("navbarPage") # Interactive mode - select which example to run if (interactive()) { shinyauthr::runExample() # Prompts user to select an example } ``` ### Response #### Success Response No return value. A Shiny application is launched and displayed in the default browser. #### Response Example None ### Errors * **Invalid example name**: Error in argument selection - If `example` is not one of the three valid options. * **Example files not found**: "Could not find example directory. Try re-installing `shinyauthr`." - If the example files cannot be located. ``` -------------------------------- ### Cookie-Based Authentication Setup with RSQLite Source: https://github.com/paulc91/shinyauthr/blob/master/README.md Sets up a local SQLite database for storing and retrieving user session IDs for cookie-based authentication. This example includes connecting to the database, defining session expiry, and functions to add and get session data. ```r library(shiny) library(dplyr) library(lubridate) library(DBI) library(RSQLite) # connect to, or setup and connect to local SQLite db if (file.exists("my_db_file")) { db <- dbConnect(SQLite(), "my_db_file") } else { db <- dbConnect(SQLite(), "my_db_file") dbCreateTable(db, "sessionids", c(user = "TEXT", sessionid = "TEXT", login_time = "TEXT")) } # a user who has not visited the app for this many days # will be asked to login with user name and password again cookie_expiry <- 7 # Days until session expires # This function must accept two parameters: user and sessionid. It will be called whenever the user # successfully logs in with a password. This function saves to your database. add_sessionid_to_db <- function(user, sessionid, conn = db) { tibble(user = user, sessionid = sessionid, login_time = as.character(now())) %>% dbWriteTable(conn, "sessionids", ., append = TRUE) } # This function must return a data.frame with columns user and sessionid Other columns are also okay # and will be made available to the app after log in as columns in credentials()$user_auth get_sessionids_from_db <- function(conn = db, expiry = cookie_expiry) { dbReadTable(conn, "sessionids") %>% mutate(login_time = ymd_hms(login_time)) %>% as_tibble() %>% filter(login_time > now() - days(expiry)) } ``` -------------------------------- ### Launch Specific Example App Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/runExample.md Launches a specific example Shiny application demonstrating shinyauthr authentication. Choose from 'basic', 'shinydashboard', or 'navbarPage'. ```r shinyauthr::runExample("basic") ``` ```r shinyauthr::runExample("shinydashboard") ``` ```r shinyauthr::runExample("navbarPage") ``` -------------------------------- ### runExample Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/MANIFEST.txt Launches example applications to demonstrate Shinyauthr's functionality. This is useful for testing and learning. ```APIDOC ## runExample ### Description Launches example applications to demonstrate Shinyauthr's functionality. This is useful for testing and learning. ### Parameters - **Parameters table** ### Available Examples - **Documentation for available example applications** ### Credentials for Testing - **Information on credentials required for testing examples** ### Learning Resources - **Links to learning resources related to the examples** ### Error Conditions - **Documentation of potential error conditions when running examples** ``` -------------------------------- ### Cookie-Based Persistence Setup (SQLite) Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md Demonstrates the initial setup for cookie-based persistent logins using SQLite. This requires packages like DBI, RSQLite, dplyr, and lubridate. ```r library(DBI) library(RSQLite) library(dplyr) library(lubridate) ``` -------------------------------- ### Setup PostgreSQL Database for Sessions Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md Establishes a connection to a PostgreSQL database and creates a 'sessions' table with appropriate data types for session management. ```r library(RPostgres) library(DBI) library(dplyr) # Setup connection db <- dbConnect( RPostgres::Postgres(), dbname = "myapp", user = "postgres", password = "password", host = "localhost" ) # Create sessions table dbCreateTable(db, "sessions", list( user = "TEXT", sessionid = "TEXT", login_time = "TIMESTAMP" )) ``` -------------------------------- ### Interactive Example Selection Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/runExample.md Launches the runExample function interactively, prompting the user to select which example Shiny application to run. This is useful for exploring different authentication integrations. ```r if (interactive()) { shinyauthr::runExample() # Prompts user to select an example } ``` -------------------------------- ### Load Database at Startup Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/integration-guide.md Connects to an SQLite database named 'users.db' once when the application starts. The user base is reloaded reactively every hour. ```r db <- dbConnect(SQLite(), "users.db") user_base <- reactive({ invalidateLater(3600000) # Reload every hour dbReadTable(db, "users") %>% as_tibble() }) credentials <- shinyauthr::loginServer( id = "login", data = user_base, # Reactive, updates hourly user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) ``` -------------------------------- ### Setup SQLite Database for Sessions Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md Initializes an SQLite database and creates a 'sessions' table if it doesn't exist. This is used for storing user session information. ```r db <- dbConnect(SQLite(), "app_sessions.db") if (!dbExistsTable(db, "sessions")) { dbCreateTable(db, "sessions", list( user = "TEXT", sessionid = "TEXT", login_time = "TEXT" )) } ``` -------------------------------- ### Install shinyauthr from CRAN Source: https://github.com/paulc91/shinyauthr/blob/master/README.md Install the stable version of the shinyauthr package from the Comprehensive R Archive Network (CRAN). ```r install.packages("shinyauthr") ``` -------------------------------- ### Install shinyauthr Development Version from GitHub Source: https://github.com/paulc91/shinyauthr/blob/master/README.md Install the latest development version of the shinyauthr package directly from its GitHub repository using the remotes package. ```r remotes::install_github("paulc91/shinyauthr") ``` -------------------------------- ### Global Application Configuration Example Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md Sets global configuration options for the Shiny application, including cookie expiry, session timeouts, and password hashing preferences. ```r library(shiny) library(dplyr) library(sodium) # Global configuration app_config <- list( cookie_expiry = 14, session_timeout_days = 7, password_hashing = TRUE, reload_on_logout = FALSE ) ``` -------------------------------- ### Migrating deprecated hashed/algo parameters to sodium_hashed Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/deprecated-functions.md This example demonstrates how to migrate from the deprecated 'hashed' and 'algo' parameters to the new 'sodium_hashed = TRUE' parameter. It involves re-hashing passwords using sodium::password_store(). ```r # Old code (no longer works) credentials <- shiny::callModule( shinyauthr::login, id = "login", data = user_base, user_col = user, pwd_col = password, hashed = TRUE, # DEPRECATED - causes error algo = "sha256" # DEPRECATED - causes error ) # New code - re-hash with sodium library(sodium) user_base_rehashed <- user_base %>% mutate(password = purrr::map_chr(password, sodium::password_store)) credentials <- shinyauthr::loginServer( id = "login", data = user_base_rehashed, user_col = user, pwd_col = password, sodium_hashed = TRUE ) ``` -------------------------------- ### Hash Multiple Passwords with Sodium Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/types.md Example of hashing multiple passwords efficiently using purrr::map_chr with sodium::password_store. ```r # Hash multiple passwords hashed_passwords <- purrr::map_chr( c("pass1", "pass2", "pass3"), sodium::password_store ) ``` -------------------------------- ### Example User Data Frame Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/types.md A tibble demonstrating the structure of a user data frame with optional metadata columns like permissions, name, and email. ```r library(tibble) user_base <- tibble( user = c("user1", "user2", "admin"), password = c("pass1", "pass2", "adminpass"), permissions = c("standard", "standard", "admin"), name = c("John Doe", "Jane Smith", "Admin User"), email = c("john@example.com", "jane@example.com", "admin@example.com"), department = c("Sales", "Marketing", "IT") ) ``` -------------------------------- ### Hash a Single Password with Sodium Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/types.md Example of using the sodium package to securely hash a single password using Argon2i. ```r library(sodium) # Hash a single password hashed <- sodium::password_store("mypassword") # Result: A 102-character string like: # "$argon2i$v=19$m=65536,t=2,p=1$..." ``` -------------------------------- ### Login Server with Cookie-Based Authentication Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/types.md Example of configuring loginServer to use cookie-based logins, requiring a function to retrieve valid sessions from a database and another to add new sessions. ```r library(DBI) library(RSQLite) db <- dbConnect(SQLite(), "sessions.db") get_valid_sessions <- function(conn = db, expiry_days = 7) { dbReadTable(conn, "sessions") %>% as_tibble() %>% filter( login_time > as.character( lubridate::now() - lubridate::days(expiry_days) ) ) %>% select(user, sessionid, login_time) } # Usage credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, cookie_logins = TRUE, sessionid_col = sessionid, cookie_getter = get_valid_sessions, cookie_setter = add_session_to_db, log_out = reactive(logout_init()) ) ``` -------------------------------- ### Reactive User Data for loginServer Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md Configure loginServer to use a reactive data source for user credentials, allowing for dynamic updates to the user database. This example refreshes user data every 5 seconds. ```r # Fetch users from database that updates periodically user_base_reactive <- reactive({ invalidateLater(5000) # Refresh every 5 seconds query_user_database() }) credentials <- shinyauthr::loginServer( id = "login", data = user_base_reactive, user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) ``` -------------------------------- ### Source Code Organization Overview Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/README.md Provides a directory structure overview of the shinyauthr package, detailing the location of UI, server, example, and helper functions. ```r R/ ├── login.R # loginUI(), loginServer(), login() [deprecated] ├── logout.R # logoutUI(), logoutServer(), logout() [deprecated] ├── runExample.R # runExample() └── internal.R # Helper functions, JavaScript generation inst/ ├── shiny-examples/ # Example applications │ ├── basic/ │ ├── shinydashboard/ │ └── navbarPage/ └── js-cookie/ # JavaScript cookie library ``` -------------------------------- ### Login Server with Cookie-Based Persistence Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/loginServer.md Implement cookie-based authentication for persistent logins. This example sets up an SQLite database to store session information and defines functions to manage session cookies. ```r library(DBI) library(RSQLite) db <- dbConnect(SQLite(), "sessions.db") # Database setup (run once) dbCreateTable(db, "sessions", list( user = "TEXT", sessionid = "TEXT", login_time = "TEXT" )) # Functions to manage session cookies add_session_to_db <- function(user, sessionid, conn = db) { tibble( user = user, sessionid = sessionid, login_time = as.character(lubridate::now()) ) %>% dbWriteTable(conn, "sessions", ., append = TRUE) } get_valid_sessions <- function(conn = db, expiry_days = 7) { dbReadTable(conn, "sessions") %>% as_tibble() %>% filter( login_time > as.character(lubridate::now() - lubridate::days(expiry_days)) ) } # Use in server credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, cookie_logins = TRUE, sessionid_col = sessionid, cookie_getter = get_valid_sessions, cookie_setter = add_session_to_db, log_out = reactive(logout_init()) ) ``` -------------------------------- ### Session ID Generation Example Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/types.md Illustrates the internal generation of a 64-character session ID using random sampling. This code is for reference and not typically called directly by users. ```r # Generated internally by randomString() # Each login creates a new session ID sessionid <- paste( sample( c(letters, LETTERS, 0:9), size = 64, replace = TRUE ), collapse = "" ) # Example: "aB3cD9eFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDe" ``` -------------------------------- ### Interactive Usage in R Console Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/runExample.md Demonstrates how to use the runExample function interactively within an R console session. It shows launching a specific example and conditionally launching another. ```r library(shinyauthr) # This will work in interactive R sessions runExample("basic") # In Rmarkdown or scripts, wrap in if(interactive()) if (interactive()) { runExample("shinydashboard") } ``` -------------------------------- ### Login Server with Sodium-Hashed Passwords Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/loginServer.md Use this snippet when your user data includes passwords that have been securely hashed using the sodium package. Ensure the sodium package is installed. ```r library(sodium) user_base <- tibble( user = c("user1", "user2"), password = purrr::map_chr(c("pass1", "pass2"), sodium::password_store), permissions = c("admin", "standard") ) credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, sodium_hashed = TRUE, log_out = reactive(logout_init()) ) ``` -------------------------------- ### Basic Shiny App with Shinyauthr Login Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/loginServer.md A complete Shiny application example demonstrating basic login functionality using static user data. It includes UI elements for login/logout and displays user information upon successful authentication. ```r library(shiny) library(dplyr) # Static user database user_base <- tibble( user = c("user1", "user2"), password = c("pass1", "pass2"), permissions = c("admin", "standard"), name = c("User One", "User Two") ) ui <- fluidPage( shinyauthr::logoutUI(id = "logout"), shinyauthr::loginUI(id = "login"), tableOutput("user_info") ) server <- function(input, output, session) { # Initialize logout module logout_init <- shinyauthr::logoutServer( id = "logout", active = reactive(credentials()$user_auth) ) # Initialize login module credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) # Use credentials in app logic output$user_info <- renderTable({ req(credentials()$user_auth) # Only render if authenticated credentials()$info }) } shinyApp(ui = ui, server = server) ``` -------------------------------- ### Create User Base with Hashed Passwords Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/types.md Example of creating a user data frame with securely hashed passwords using sodium, suitable for saving to a file or database. ```r library(sodium) library(tibble) # Create user base with hashed passwords user_base <- tibble( user = c("user1", "user2"), password = map_chr(c("pass1", "pass2"), sodium::password_store), permissions = c("admin", "standard") ) # Save to file or database saveRDS(user_base, "user_base.rds") ``` -------------------------------- ### Customize Login Button Class Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/types.md Applies a custom Bootstrap class to the login button for styling. This example changes the button to a green color using 'btn-success'. ```r shinyauthr::loginUI( id = "login", login_btn_class = "btn-success" # Green button ) ``` -------------------------------- ### Missing Sodium Package Error Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/errors.md This error occurs when sodium_hashed is TRUE but the 'sodium' package is not installed. Install the package before proceeding. ```r # WRONG - sodium_hashed = TRUE but sodium not installed # install.packages("sodium") # Missing credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, sodium_hashed = TRUE ) ``` ```r # Install sodium package install.packages("sodium") # Then use with sodium_hashed = TRUE library(sodium) credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, sodium_hashed = TRUE, log_out = reactive(logout_init()) ) ``` -------------------------------- ### Initialize Login and Logout Modules Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/module-reference.md Instantiate the login and logout server modules. These modules handle user authentication and session management. ```r # 1. Module pair is instantiated logout_init <- shinyauthr::logoutServer(id = "logout", ...) credentials <- shinyauthr::loginServer(id = "login", ...) ``` -------------------------------- ### Login Server with Static User Data Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/loginServer.md This snippet demonstrates initializing the login server with a static data frame for user credentials. It's suitable for applications with a fixed user list. ```r # Static data credentials <- shinyauthr::loginServer( id = "login", data = static_user_base, user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) ``` -------------------------------- ### User Data Frame with Sodium Hashing Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/types.md Example of creating a user data frame where passwords are sodium-hashed using password_store. ```r library(sodium) library(purrr) user_base <- tibble( user = c("user1", "user2"), password = map_chr(c("pass1", "pass2"), sodium::password_store), permissions = c("standard", "admin"), name = c("User One", "User Two") ) ``` -------------------------------- ### loginServer with Sodium-Hashed Passwords Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/loginServer.md Demonstrates how to use loginServer when user passwords are pre-hashed using the sodium package. This enhances security by avoiding storage of plain text passwords. ```APIDOC ## shinyauthr::loginServer with Sodium Hashing ### Description Configures the loginServer to authenticate users against a dataset where passwords have been securely hashed using the `sodium` package. This is a recommended practice for enhanced security. ### Parameters * **id**: The Shiny module instance ID. * **data**: A data frame or reactive expression containing user data, including a column for sodium-hashed passwords. * **user_col**: The name of the username column. * **pwd_col**: The name of the sodium-hashed password column. * **log_out**: A reactive expression that triggers logout. * **sodium_hashed = TRUE**: This crucial argument tells `loginServer` to use `sodium::password_verify` to compare the entered password against the stored hash. ### Returns A reactive list containing authentication status (`user_auth`) and user information (`info`). ### Example ```r library(sodium) user_base <- tibble( user = c("user1", "user2"), password = purrr::map_chr(c("pass1", "pass2"), sodium::password_store), permissions = c("admin", "standard") ) credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = "user", pwd_col = "password", sodium_hashed = TRUE, log_out = reactive(logout_init()) ) ``` ``` -------------------------------- ### Minimal loginUI Configuration Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md Use this minimal configuration for a basic login panel with default settings. ```r shinyauthr::loginUI(id = "login") ``` -------------------------------- ### Server-side integration of loginServer Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/loginUI.md This snippet illustrates the server-side counterpart to loginUI. It shows how to initialize loginServer, providing user data and column mappings, and how to handle logout events. ```r server <- function(input, output, session) { credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) } shinyApp(ui = ui, server = server) ``` -------------------------------- ### Integration with loginServer Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/logoutUI.md Illustrates how to pair logoutUI with logoutServer and loginServer to manage user authentication and session termination. ```r server <- function(input, output, session) { # Login module credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) # Logout module - controls when the button is shown/hidden logout_init <- shinyauthr::logoutServer( id = "logout", active = reactive(credentials()$user_auth) ) } shinyApp(ui = ui, server = server) ``` -------------------------------- ### Initializing Login Server with Hashed Passwords Source: https://github.com/paulc91/shinyauthr/blob/master/README.md This snippet demonstrates how to configure the `loginServer` module to handle pre-hashed passwords by setting `sodium_hashed = TRUE`. This ensures that the package correctly compares the stored hash with the provided password during login. ```r credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, sodium_hashed = TRUE, log_out = reactive(logout_init()) ) ``` -------------------------------- ### Get Valid Sessions from PostgreSQL Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md Queries the PostgreSQL 'sessions' table to retrieve active sessions based on a time interval, using SQL for efficiency. ```r get_valid_sessions <- function(conn = db, hours = 168) { query <- glue::glue_sql( "SELECT user, sessionid FROM sessions\n WHERE login_time > NOW() - INTERVAL '{hours} hours'", .con = conn ) dbGetQuery(conn, query) } ``` -------------------------------- ### Basic Shinyauthr App Structure Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md This snippet demonstrates a complete Shiny app with user authentication using Shinyauthr. It includes setting up a user database, defining the UI with login and logout components, and implementing the server logic for authentication. ```r library(shiny) library(shinyauthr) library(dplyr) # User database user_base <- tribble( ~user, ~password, ~permissions, ~name, "admin", sodium::password_store("adminpass"), "admin", "Admin User", "user1", sodium::password_store("userpass1"), "standard", "User One", "user2", sodium::password_store("userpass2"), "standard", "User Two" ) ui <- fluidPage( # Logout button div( class = "pull-right", shinyauthr::logoutUI( id = "logout", label = "Sign Out", icon = icon("sign-out-alt") ) ), # Login panel shinyauthr::loginUI( id = "login", title = "MyApp Authentication", cookie_expiry = app_config$cookie_expiry ), # Protected content textOutput("welcome") ) server <- function(input, output, session) { # Logout module logout_init <- shinyauthr::logoutServer( id = "logout", active = reactive(credentials()$user_auth), anim = TRUE, time = 300 ) # Login module credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, sodium_hashed = app_config$password_hashing, reload_on_logout = app_config$reload_on_logout, log_out = reactive(logout_init()) ) # Protected content output$welcome <- renderText({ req(credentials()$user_auth) paste("Welcome", credentials()$info$name) }) } shinyApp(ui = ui, server = server) ``` -------------------------------- ### Get Valid Sessions from SQLite Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md Retrieves active sessions from the SQLite database, filtering by login time to include only those within a specified number of days. ```r get_valid_sessions <- function(conn = db, days = 7) { dbReadTable(conn, "sessions") %>% as_tibble() %>% mutate(login_time = ymd_hms(login_time)) %>% filter(login_time > now() - days(days)) } ``` -------------------------------- ### loginUI with additional UI elements Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/loginUI.md Shows how to integrate custom UI elements, such as action links for 'Forgot password?' or 'Create account', below the standard login form. ```r # With additional UI elements shinyauthr::loginUI( id = "login", additional_ui = shiny::tagList( shiny::actionLink("forgot_password", "Forgot password?"), shiny::actionLink("sign_up", "Create account") ) ) ``` -------------------------------- ### Configure Cookie Expiry in loginUI Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/types.md Set the duration for which the session ID cookie will be retained in the user's browser. This example sets the expiry to 7 days. ```r shinyauthr::loginUI( id = "login", cookie_expiry = 7 # Days to retain cookie ) ``` -------------------------------- ### Shinydashboard Integration with Logout in Sidebar Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/integration-guide.md Demonstrates placing the shinyauthr logout button within the shinydashboard sidebar. This example focuses on the UI structure for the logout button placement. ```r ui <- dashboardPage( dashboardHeader(title = "My Dashboard"), dashboardSidebar( sidebarMenu( menuItem("Home", tabName = "home"), menuItem("Analytics", tabName = "analytics"), # Logout button in sidebar br(), div( style = "padding: 15px; border-top: 1px solid #eee;", shinyauthr::logoutUI(id = "logout", label = "Sign Out") ) ) ), dashboardBody( # ... content ... ) ) ``` -------------------------------- ### Initialize Logout Server Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/types.md Initializes the logout server, which returns a reactive value signaling when the logout button is clicked. ```r # In server function logout_init <- shinyauthr::logoutServer( id = "logout", active = reactive(credentials()$user_auth) ) ``` -------------------------------- ### Internationalization for loginUI Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md Adapt the login panel's text for different languages by providing translated strings for titles and labels. This example shows English, Spanish, and French. ```r # English shinyauthr::loginUI( id = "login", title = "Please log in", user_title = "User Name", pass_title = "Password" ) # Spanish shinyauthr::loginUI( id = "login", title = "Por favor inicie sesión", user_title = "Nombre de usuario", pass_title = "Contraseña" ) # French shinyauthr::loginUI( id = "login", title = "Veuillez vous connecter", user_title = "Nom d'utilisateur", pass_title = "Mot de passe" ) ``` -------------------------------- ### login (deprecated) Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/MANIFEST.txt Deprecated function for initiating the login process. Migration to `loginUI` and `loginServer` is recommended. ```APIDOC ## login (deprecated) ### Description Deprecated function for initiating the login process. Migration to `loginUI` and `loginServer` is recommended. ### Parameters - **Documentation for the deprecated `login()` function parameters** ### Migration Guide - **Guide to migrate from `login()` to modern functions** ### Parameter Mapping - **Reference for mapping parameters from `login()` to new functions** ### Known Issues - **Information on known issues with deprecated parameters** ``` -------------------------------- ### Initialize Logout and Login Modules Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/module-reference.md Call the logout module first, then the login module, passing the logout trigger to the login module. The 'active' parameter for logout should reflect the authentication state from the login module. ```r # In server function, call in correct order: # 1. Define logout first (it's needed by login) logout_init <- shinyauthr::logoutServer( id = "logout", active = reactive(credentials()$user_auth) ) # 2. Call login module, passing logout trigger credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) # Both modules now communicate: # - credentials()$user_auth reflects authentication state # - logoutServer() show/hides button based on credentials()$user_auth # - logoutServer() click triggers logout in loginServer() ``` -------------------------------- ### Login Server with Reactive User Data Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/loginServer.md Initialize the login server with reactive user data, allowing the user list to be updated dynamically. This is useful when user data is fetched from a database or API. ```r # Reactive data (updates when underlying data changes) user_base_reactive <- reactive({ # Fetch from database or API load_users_from_db() }) credentials <- shinyauthr::loginServer( id = "login", data = user_base_reactive, user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) ``` -------------------------------- ### Shinyauthr Module Architecture Overview Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/README.md Illustrates the paired UI and server functions that implement Shiny's module pattern for authentication. Shows communication flow and return types. ```r UI Layer: loginUI() → HTML form with inputs logoutUI() → Action button Server Layer: loginServer() → Processes credentials, manages auth state logoutServer() → Controls button visibility, triggers logout Communication: loginServer() returns: reactive list(user_auth, info) logoutServer() returns: reactive click value Linked via: log_out parameter in loginServer() ``` -------------------------------- ### Debugging Cookie Setter Failures Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/errors.md Shows how to test the `cookie_setter` function to diagnose issues where cookies are not stored. Includes an example of implementing `cookie_setter` with error handling and logging within `loginServer`. ```r # Test your cookie_setter function save_session <- function(user, sessionid, conn = db) { result <- tryCatch({ tibble(user = user, sessionid = sessionid, login_time = Sys.time()) %>% dbAppendTable(conn, "sessions", .) TRUE }, error = function(e) { message("Error saving session:", e$message) FALSE }) return(result) } # In your app, you could log these failures credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, cookie_logins = TRUE, sessionid_col = sessionid, cookie_getter = get_valid_sessions, cookie_setter = function(user, sessionid) { tryCatch({ save_session(user, sessionid) }, error = function(e) { warning("Failed to save session:", e$message) }) }, log_out = reactive(logout_init()) ) ``` -------------------------------- ### Hashing Passwords with Sodium Source: https://github.com/paulc91/shinyauthr/blob/master/README.md This snippet demonstrates how to hash user passwords using the sodium package before storing them. It's recommended for security when hosting passwords online. Ensure plain text passwords are character vectors, not factors. ```r library(sodium) user_base <- tibble::tibble( user = c("user1", "user2"), password = purrr::map_chr(c("pass1", "pass2"), sodium::password_store), permissions = c("admin", "standard"), name = c("User One", "User Two") ) saveRDS(user_base, "user_base.rds") ``` -------------------------------- ### Customize Logout Button Styling Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/types.md Applies custom styling to the logout button, including Bootstrap classes and inline styles. This example uses 'btn-warning' and adds margin and bold font weight. ```r shinyauthr::logoutUI( id = "logout", class = "btn-warning", style = "margin: 10px; font-weight: bold;" ) ``` -------------------------------- ### Basic Logout Server Configuration Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md Initializes the logout server functionality, controlling its visibility based on the user authentication status. ```r logout_init <- shinyauthr::logoutServer( id = "logout", active = reactive(credentials()$user_auth) ) ``` -------------------------------- ### Debugging Cookie Getter Failures Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/errors.md Provides an example of how to independently test the `cookie_getter` function to ensure it connects to the database and returns valid session data. Debugging involves checking the function's return value. ```r # Test your cookie_getter function independently get_valid_sessions <- function(conn = db) { dbReadTable(conn, "sessions") %>% filter(login_time > ...) # Filtering logic } # Debug: Check return value test_result <- get_valid_sessions() print(test_result) # Should show: data.frame with 'user' and 'sessionid' columns ``` -------------------------------- ### Basic Login Module Usage with `req()` Source: https://github.com/paulc91/shinyauthr/blob/master/README.md Ensures that reactive elements like tables are only rendered after a successful login. This is achieved by using `req()` with the user's authentication status. ```r renderTable({ req(credentials()$user_auth) # Code to render table based on user information }) ``` -------------------------------- ### Shinyauthr Authentication with Cookie-Based Persistence Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/README.md This example shows how to enable persistent logins using cookies with shinyauthr. It includes functions for adding and retrieving session data from an SQLite database, which are passed to `loginServer` via `cookie_getter` and `cookie_setter`. ```r library(DBI) library(RSQLite) db <- dbConnect(SQLite(), "sessions.db") # Cookie setter add_session <- function(user, sessionid, conn = db) { data.frame(user = user, sessionid = sessionid, login_time = Sys.time()) %>% rbind(dbReadTable(conn, "sessions"), .) %>% dbWriteTable(conn, "sessions", ., overwrite = TRUE) } # Cookie getter get_sessions <- function(conn = db, days = 7) { dbReadTable(conn, "sessions") %>% filter(login_time > Sys.time() - (days * 86400)) } credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, cookie_logins = TRUE, sessionid_col = sessionid, cookie_getter = get_sessions, cookie_setter = add_session, log_out = reactive(logout_init()) ) ``` -------------------------------- ### Customized loginUI with specific labels and styling Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/loginUI.md Demonstrates how to customize the appearance and text of the login panel. This includes changing the main title, labels for username and password, the login button text, its CSS class, and the error message. ```r # Or with custom styling and labels shinyauthr::loginUI( id = "login", title = "Welcome - Please Sign In", user_title = "Email Address", pass_title = "Secret Password", login_title = "Sign In", login_btn_class = "btn-success", error_message = "Login failed. Please check your credentials.", cookie_expiry = 14 ) ``` -------------------------------- ### Migrating from callModule to moduleServer for login Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/deprecated-functions.md This snippet shows the old code using callModule for the login function and the new code using moduleServer for loginServer. The functionality remains the same, only the module invocation method changes. ```r server <- function(input, output, session) { credentials <- shiny::callModule( shinyauthr::login, id = "login", data = user_base, user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) logout_init <- shiny::callModule( shinyauthr::logout, id = "logout", active = reactive(credentials()$user_auth) ) } ``` ```r server <- function(input, output, session) { credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) logout_init <- shinyauthr::logoutServer( id = "logout", active = reactive(credentials()$user_auth) ) } ``` -------------------------------- ### Plain Text Passwords for loginServer (Development) Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/configuration.md Configure loginServer with plain text passwords for development or testing purposes. Ensure you use hashed passwords for production environments. ```r user_base <- data.frame( user = c("user1", "user2"), password = c("pass1", "pass2"), permissions = c("admin", "standard") ) credentials <- shinyauthr::loginServer( id = "login", data = user_base, user_col = user, pwd_col = password, log_out = reactive(logout_init()) ) ``` -------------------------------- ### loginServer Function Signature and Parameters Source: https://github.com/paulc91/shinyauthr/blob/master/_autodocs/api-reference/loginServer.md This snippet details the signature and parameters of the loginServer function, outlining how to configure user data, authentication methods, and session management. ```APIDOC ## loginServer ### Description `loginServer` is a Shiny server module that handles user authentication. It processes login attempts, validates credentials against a user database, manages session state, and optionally supports cookie-based persistent authentication. Returns a reactive list containing authentication status and user information. ### Signature ```r loginServer( id, data, user_col, pwd_col, sodium_hashed = FALSE, log_out = shiny::reactiveVal(), reload_on_logout = FALSE, cookie_logins = FALSE, sessionid_col, cookie_getter, cookie_setter ) ``` ### Parameters #### Required Parameters - **id** (character): An ID string that must match the `id` provided to `loginUI()`. - **data** (data.frame, tibble, or reactive): Data frame or tibble containing user credentials and optional user metadata. Can be a static object or a Shiny reactive that returns a data frame. All text columns are automatically converted from factors to character class. - **user_col** (symbol or character): Name of the column in `data` containing usernames. Can be provided bare (e.g., `user`) or quoted (e.g., `"user"`). - **pwd_col** (symbol or character): Name of the column in `data` containing passwords. Can be provided bare (e.g., `password`) or quoted (e.g., `"password"`). If `sodium_hashed = TRUE`, these should be hashed values created with `sodium::password_store()`. #### Optional Parameters - **sodium_hashed** (logical): Whether passwords in the `pwd_col` have been encrypted using `sodium::password_store()`. If TRUE, password verification uses `sodium::password_verify()`. If FALSE, passwords are compared using exact string matching. Default: `FALSE`. - **log_out** (reactive): A reactive value supplied from `logoutServer()` to trigger user logout. When this reactive triggers (typically on logout button click), the authentication state resets. Default: `shiny::reactiveVal()`. - **reload_on_logout** (logical): If TRUE, the Shiny session reloads entirely when the user logs out via `session$reload()`. If FALSE, the login panel is shown again without reloading the page. Default: `FALSE`. - **cookie_logins** (logical): If TRUE, enables automatic login via browser cookies for returning users. When TRUE, `sessionid_col`, `cookie_getter`, and `cookie_setter` must all be provided. Default: `FALSE`. #### Conditional Parameters (Required if `cookie_logins = TRUE`) - **sessionid_col** (symbol or character): Name of the column in the data returned by `cookie_getter()` containing session IDs. Can be provided bare or quoted. - **cookie_getter** (function): A function that takes no parameters and returns a data frame with at least two columns: the user column (matching `user_col`) and the session ID column (matching `sessionid_col`). The function should query your persistent database for active sessions. - **cookie_setter** (function): A function with two parameters: `user` (character string of username) and `session` (character string of session ID). This function should save the user-session pair to your persistent database. ### Return Value A reactive list with two elements: ```r list( user_auth = logical, # TRUE if user successfully authenticated, FALSE otherwise info = data.frame # If user_auth is TRUE: the row(s) from 'data' matching the logged-in user # If user_auth is FALSE: NULL ) ``` When cookie-based authentication is enabled (`cookie_logins = TRUE`), the `info` list also includes all additional columns returned by `cookie_getter()` (except the user column which would be duplicated). ### Details #### Authentication Flow 1. **Initial State**: `user_auth = FALSE`, `info = NULL` 2. **Cookie Check** (if enabled): On app load, JavaScript checks for a valid session cookie. If found and valid in the database, user is automatically logged in. 3. **Manual Login**: User enters username and password and clicks the login button. 4. **Credential Validation**: The entered username is matched against the `user_col`, and the password is validated: - If `sodium_hashed = FALSE`: exact string match using `identical()` - If `sodium_hashed = TRUE`: cryptographic verification using `sodium::password_verify()` 5. **Success**: If credentials match, `user_auth = TRUE` and `info` is set to the matching user row. 6. **Failure**: If credentials don't match, error message briefly displays (5 second fade animation). 7. **Logout**: When `log_out` reactive triggers, `user_auth` resets to FALSE and `info` to NULL. ```