R
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Data Structures
-
Section 4: Data Manipulation
-
Section 5: Visualization and Statistics
-
Section 6: Advanced R
-
Section 7: Practical Projects
-
Section 8: Interview Practice
-
Section 9: More Practice Exercises
-
Section 10: Shiny Apps in Depth
-
Section 11: More Data Wrangling
-
Section 12: Tidyverse Deep Dive
-
Section 13: Statistical Modeling Deep Dive
-
Section 14: Machine Learning in R
-
Section 15: R Visualization Deep Dive
-
Section 16: R Package Development Deep Dive
-
Section 17: R for Reproducible Research
-
Section 18: R and Databases
-
Section 19: R Performance Optimization
-
Section 20: Bioinformatics and Specialized R
-
Section 21: More Shiny Practice
-
Section 22: More Practice Exercises
-
Section 23: R Data Structures Deep Dive
-
Section 24: More Interview and Review
-
Section 25: R for Business Analytics
-
Section 26: R Text Mining and NLP
-
Section 27: R Spatial Data Analysis
-
Section 28: R Deep Learning
-
Section 29: Advanced Statistical Techniques
-
Section 30: R Object Systems Deep Dive
-
Section 31: R Environments and Metaprogramming
-
Section 32: R for Finance
-
Section 33: R for Clinical and Health Data
-
Section 34: More Shiny Advanced Practice
-
Section 35: R Data Cleaning Deep Dive
-
Section 36: R Reporting Automation
-
Section 37: More Practical Projects Round 2
-
Section 38: R Ecosystem and Career
-
Section 39: More Visualization Practice
-
Section 40: R for Experimentation
-
Section 41: R for Genomics and Bioinformatics Deep Dive
-
Section 42: R for Marketing Analytics
-
Section 43: R Data Import/Export Deep Dive
-
Section 44: R String Processing Deep Dive
-
Section 45: R for Actuarial and Insurance Analytics
-
Section 46: R Testing and Quality Assurance Deep Dive
-
Section 47: R Version Control and Collaboration
-
Section 48: R Advanced Functional Programming
-
Section 49: R for Supply Chain and Operations
-
Section 50: More Practice Exercises Round 3
-
Section 51: R Dashboards and BI Integration
-
Section 52: R Data Governance and Ethics
-
Section 53: More Modeling Practice
-
Section 54: R Final Capstone Projects
-
Section 55: R for Sports Analytics
-
Section 56: More Interview Practice Round 2
-
Section 57: R Networking and APIs
-
Section 58: R for Environmental Science
-
Section 59: R Notebook and Documentation Practices
-
Section 60: More Data Wrangling Mastery
-
Section 61: R for A/B Testing at Scale
-
Section 62: R Package Ecosystem Deep Dive
89: Authentication in Shiny Apps
I've seen this mistake more times than I can count. A developer wants to protect a dashboard, so they create a simple "logged in" flag. It looks like it works during their local testing, but the moment they deploy it to a server with more than one user, they've accidentally created a massive security hole.
# WARNING: This code is fundamentally broken
is_authenticated <- FALSE # Global variable
ui <- fluidPage(
uiOutput("main_ui")
)
server <- function(input, output, session) {
output$main_ui <- renderUI({
if (is_authenticated) {
h1("Welcome to the Secret Executive Dashboard")
} else {
div(
textInput("user", "Username"),
passwordInput("pw", "Password"),
actionButton("login", "Log In")
)
}
})
observeEvent(input$login, {
# Using super-assignment to update the global variable
if (input$user == "admin" & input$pw == "password123") {
is_authenticated <<- TRUE
}
})
}
shinyApp(ui, server)
The Global State Trap
At first glance, this looks logical. You have a variable, you check it, and you update it when the button is clicked. But look closely at where is_authenticated is defined. It's sitting outside the server function.
In Shiny, the server function is executed once for every single user who connects to the app. However, any variable defined outside that function is shared across the entire R process. By using the super-assignment operator (<<-), you aren't just logging in one user; you are flipping a switch for every person currently using the app. If User A logs in successfully, User B—who might have just opened the app—will suddenly see the "Secret Executive Dashboard" without ever entering a password. That's a catastrophic failure in any production environment.
Encapsulating State in the Server Session
To fix this, we need to move the authentication state inside the server function. This ensures that the variable is created in a fresh environment for every new session. I also recommend using a reactiveVal instead of a standard variable, because renderUI needs a reactive trigger to know when to redraw the screen.
ui <- fluidPage(
uiOutput("main_ui")
)
server <- function(input, output, session) {
# State is now local to this specific user session
authenticated <- reactiveVal(FALSE)
output$main_ui <- renderUI({
# renderUI will now automatically re-run whenever authenticated() changes
if (authenticated()) {
h1("Welcome to the Secret Executive Dashboard")
} else {
div(
textInput("user", "Username"),
passwordInput("pw", "Password"),
actionButton("login", "Log In")
)
}
})
observeEvent(input$login, {
if (input$user == "admin" & input$pw == "password123") {
authenticated(TRUE)
} else {
showNotification("Invalid credentials", type = "error")
}
})
}
shinyApp(ui, server)
Now, when User A logs in, authenticated(TRUE) only happens within their specific session memory. User B's session remains FALSE. It's a simple shift in where the variable lives, but it's the difference between a secure app and a liability.
Moving Beyond Basic Logic
While the logic above solves the "shared state" bug, you shouldn't manually write password checks for a serious app. Hard-coding credentials in your script is a huge no-no (they'll end up in your git history), and simple if statements don't handle session timeouts or encrypted passwords.
For real-world projects, I suggest looking at packages like shinymanager or shinyauthr. They handle the "boilerplate" of authentication—like database lookups, password hashing, and session cookies—so you can focus on the actual data visualization. If you're deploying to a corporate environment, you'll likely be using OAuth or Active Directory, which usually happens at the server level (like ShinyProxy or Posit Connect) rather than inside the R code itself.
📋 Practical Task
Build a Session-Aware Gatekeeper for Sensitive Data
Your goal is to create a Shiny app that protects a "Financial Report" tab. You must ensure that the authentication state is session-specific and that the user cannot access the report without the correct credentials.
- Create a
uiOutputthat switches between a login screen and the main content. - Implement a
reactiveValinside theserverfunction to track the login status. - The login should only succeed if the username is
"analyst"and the password is"secure2024". - If the login fails, use
showNotification()to alert the user. - Once logged in, display a table (you can use
head(mtcars)as a placeholder for the "Financial Report") and a "Logout" button that sets the authentication state back toFALSE.
There are no comments for now.