Shinyapp Google Login

ShinyApp Google Login

I solved this problem in a different manner using gar_shiny_ui

  1. we need to define the UI in the server

  2. Get user info and extract email from his/her google login

  3. Use this email to determine if the person is from your organisation

  4. If the person is from your organisation, show the main UI else show a UI which says 'You cannot access this tool'

    #Function to get google user data which will be used for checking if the user comes from your organisation
    user_info <- function(){
    f <- gar_api_generator("https://www.googleapis.com/oauth2/v1/userinfo",
    "GET",
    data_parse_function = function(x) x)
    f()}

    #UI code based on Output coming via server code
    ui<-uiOutput('myUI')

    #Server side code to do all the lifting
    server = function(input, output,session) {
    gar_shiny_auth(session)

    #Check if user has already logged in with google authentication
    gmail='john.doe@unkwown.com'
    tryCatch({
    x<- user_info()
    gmail=x$email
    print(gmail)})
    print(gmail)

    #Create a different UI based on where the user comes from (MyOrg or Not)
    output$myUI <- renderUI({

    if(grepl('@myorganisation.com',gmail)){
    ui = fluidPage(
    shinyjs::useShinyjs(),
    title='Your Product',
    theme = shinytheme("cerulean"),
    img(src = "mycompany_logo.png", height = 200, width = 400),

    sidebarLayout(
    sidebarPanel(write whatever you want)
    ,
    mainPanel( write whatever you want)
    )
    )}
    else {
    ui = fluidPage(mainPanel(
    h4("My Company Data Team Presents", allign="center"),
    h1("My Tool", allign="center"),
    p("Tool that makes analysing any and everything ",
    em("incredibly easy "),
    "with a simple click."),
    br(),
    p("- But unfortunately, your account does not have the rights to ",
    em("access "),
    "this tool."))) }
    })
    shinyApp(gar_shiny_ui(ui, login_ui = silent_auth), server)

R Shiny - use google authenticator to allow people with a certain type of email address to log in

So finally I found a solution that sort of works.

In addition to what I've written in the question,

  1. we need to define the UI in the server

  2. Get user info and extract email from his/her google login

  3. Use this email to determine if the person is from your organisation

  4. If the person is from your organisation, show the main UI else show a UI which says 'You cannot access this tool'

        #Function to get google user data which will be used for checking if the user comes from your organisation
    user_info <- function(){
    f <- gar_api_generator("https://www.googleapis.com/oauth2/v1/userinfo",
    "GET",
    data_parse_function = function(x) x
    )
    f()
    }

    #UI code based on Output coming via server code
    ui<-uiOutput('myUI')

    #Server side code to do all the lifting
    server = function(input, output,session) {
    gar_shiny_auth(session)

    #Check if user has already logged in with google authentication
    gmail='john.doe@unkwown.com'
    tryCatch({
    x<- user_info()
    gmail=x$email
    print(gmail)})
    print(gmail)

    #Create a different UI based on where the user comes from (MyOrg or Not)
    output$myUI <- renderUI({

    if(grepl('@myorganisation.com',gmail)){
    ui = fluidPage(
    shinyjs::useShinyjs(),
    title='Your Product',
    theme = shinytheme("cerulean"),
    img(src = "mycompany_logo.png", height = 200, width = 400),

    sidebarLayout(
    sidebarPanel(write whatever you want)
    ,
    mainPanel( write whatever you want)
    )
    )}
    else {
    ui = fluidPage(mainPanel(
    h4("My Company Data Team Presents", allign="center"),
    h1("My Tool", allign="center"),
    p("Tool that makes analysing any and everything ",
    em("incredibly easy "),
    "with a simple click."),
    br(),
    p("- But unfortunately, your account does not have the rights to ",
    em("access "),
    "this tool."))) }
    })
    shinyApp(gar_shiny_ui(ui, login_ui = silent_auth), server)

How do you implement Google authentication in a shiny R app?

My solution was to use the Google Sign-In API, write a very small amount of javascript, and use the js function Shiny.onInputChange to create reactive variables from the user data.

The Sign-In API provides a button, does not require a secret, and allows the client ID and scope to be specified in meta tags in the HTML HEAD, so it's very easy to use.

In app.R I simply add the Google API code, scope, client ID, and a login button like this.

ui <- tagList(
tags$head(
tags$meta(name="google-signin-scope",content="profile email"),
tags$meta(name="google-signin-client_id", content="YOURCLIENTID.apps.googleusercontent.com"),
HTML('<script src="https://apis.google.com/js/platform.js?onload=init"></script>'),
includeScript("signin.js"),
),
fluidPage(

titlePanel("Sample Google Sign-In"),

sidebarLayout(
sidebarPanel(
div(id="signin", class="g-signin2", "data-onsuccess"="onSignIn"),
actionButton("signout", "Sign Out", onclick="signOut();", class="btn-danger")

Note that Google's API will turn the signin div into a button and the data-onsuccess parameter names the function onSignIn to call upon successful authentication. Conveniently this is called whether the user is automatically logged in or actually going through the Google approval process.

There is also a signOut function which invalidates local cookies and also nullifies the profile data.

In a separate file signin.js I defined the callback function onSignIn that sends the user profile info to the shiny server from the client.

function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
Shiny.onInputChange("g.id", profile.getId());
Shiny.onInputChange("g.name", profile.getName());
Shiny.onInputChange("g.image", profile.getImageUrl());
Shiny.onInputChange("g.email", profile.getEmail());
}
function signOut() {
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut();
Shiny.onInputChange("g.id", null);
Shiny.onInputChange("g.name", null);
Shiny.onInputChange("g.image", null);
Shiny.onInputChange("g.email", null);
}

That's about it. Your UI and server just need to add code to access the user profile reactives. Here's an example in the UI:

 mainPanel(
with(tags, dl(dt("Name"), dd(textOutput("g.name")),
dt("Email"), dd(textOutput("g.email")),
dt("Image"), dd(uiOutput("g.image")) ))
)

And in the server:

server <- function(input, output) {
output$g.name = renderText({ input$g.name })
output$g.email = renderText({ input$g.email })
output$g.image = renderUI({ img(src=input$g.image) })

I put together a working example that you can run (with a very small bit of contortion - you must specify port 7445 and use localhost). Please read the README for more details.

Connect to googlesheets via shiny in R with googlesheets4

Just follow the instructions in this link:

# designate project-specific cache
options(gargle_oauth_cache = ".secrets")
# check the value of the option, if you like
gargle::gargle_oauth_cache()
# trigger auth on purpose to store a token in the specified cache
# a broswer will be opened
googlesheets4::sheets_auth()
# see your token file in the cache, if you like
list.files(".secrets/")
# sheets reauth with specified token and email address
sheets_auth(
cache = ".secrets",
email = "youremail"
)

Create one shiny app with two users that log in to different versions of the app

One possible way of doing this with shinymanager is as below. Another self build solution can be found here with more explanation on github.

The quote regarding self-build authentication in shiny in the comments is of course correct: using an approach outside of shiny is the better way.

# define some credentials
credentials <- data.frame(
user = c("shiny", "shinymanager"), # mandatory
password = c("azerty", "12345"), # mandatory
start = c("2019-04-15"), # optinal (all others)
expire = c(NA, NA),
admin = c(FALSE, TRUE),
comment = "Simple and secure authentification mechanism
for single ‘Shiny’ applications.",
stringsAsFactors = FALSE
)

library(shiny)
library(shinymanager)

ui <- fluidPage(
tags$h2("My secure application"),
uiOutput("myinput"),
tableOutput("data")
)

# Wrap your UI with secure_app
ui <- secure_app(ui)

server <- function(input, output, session) {

# call the server part
# check_credentials returns a function to authenticate users
res_auth <- secure_server(
check_credentials = check_credentials(credentials)
)

output$myinput <- renderUI({

if (reactiveValuesToList(res_auth)$user == "shiny") {
# if (TRUE) {
mychoices <- c("Cylinders" = "cyl",
"Transmission" = "am",
"Gears" = "gear")
} else {
mychoices <- c("Sepal Length" = "Sepal.Length",
"Sepal Width" = "Sepal.Width",
"Petal Length" = "Petal.Length",
"Petal Width" = "Petal.Width")
}

selectInput("variable",
"Variable:",
choices = mychoices)
})

output$data <- renderTable({

expr = if (reactiveValuesToList(res_auth)$user == "shiny") {
mtcars[, c("mpg", input$variable), drop = FALSE]
} else {
iris[, c("Species", input$variable), drop = FALSE]
}
})

}

shinyApp(ui, server)

Multi-user authentication for googlesheets on an app deployed to shinyapps.io

I enquired on github and the developer of the googlesheets4 package, responded that multi-user authentication in shiny is not yet implemented. The issue is being tracked here: https://github.com/r-lib/gargle/issues/14

Requiring login for only one section of Shiny app

You can just write the login-logic yourself. Here is a simple illustration how this can be done with renderUI.

library(shiny)

ui <- fluidPage(
tabsetPanel(
tabPanel("public area", "Eveyone can see this!"),
tabPanel("login area", uiOutput("login_area"))
)
)

server <- function(input, output, session){
logged_in = reactiveVal(FALSE)

output$logged_in <- renderUI({"you are logged in"})

output$not_logged_in <- renderUI({
tagList(
"you are not logged in",
actionButton("login", "Log me in!")
)
})

observeEvent(input$login, logged_in(TRUE))

output$login_area <- renderUI({
if (logged_in())
uiOutput("logged_in")
else
uiOutput("not_logged_in")
})
}

shinyApp(ui, server)


Related Topics



Leave a reply



Submit