Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

approval_prompt: 'auto' is not valid #177

Closed
rasnes opened this issue Apr 21, 2020 · 9 comments
Closed

approval_prompt: 'auto' is not valid #177

rasnes opened this issue Apr 21, 2020 · 9 comments
Assignees

Comments

@rasnes
Copy link

rasnes commented Apr 21, 2020

What goes wrong

I am using googleAuthR to access my Shiny dashboards hosted on Google Cloud Run. It has been working well, but today I got a new error I have not seen before, and I suspect the error is not in my setup.

Error 400: invalid_request
Invalid parameter value for approval_prompt: 'auto' is not valid

image

Steps to reproduce the problem

library(googleAuthR) # version 1.1.1
options(googleAuthR.webapp.client_id = <client_id>)
options(googleAuthR.scopes.selected = "email")
options(googleAuthR.webapp.client_secret = <secret>)
options(googleAuthR.redirect = <url>)

ui <- fluidPage(...)

server <- function(input, output, session){
  gar_shiny_auth(session)
  ...
}

shinyApp(gar_shiny_ui(ui), server)

Could it be that some changes to Google's API causes this?

@hugovk
Copy link

hugovk commented Apr 21, 2020

This is affecting Vimeo and also one of our sites (we use https://github.com/thephpleague/oauth2-client/).

Looks like a Google change and a fix is replacing approval_prompt=auto with prompt=, or leaving out both approval_prompt and prompt, or ``approval_prompt=force`.

https://developers.google.com/identity/protocols/oauth2/openid-connect#authenticationuriparameters

@MarkEdmondson1234
Copy link
Owner

MarkEdmondson1234 commented Apr 21, 2020 via email

@rasnes
Copy link
Author

rasnes commented Apr 22, 2020

Update: it seems to be working as usual again today. Some temporary change or something on Google's end?

@rasnes
Copy link
Author

rasnes commented Apr 22, 2020

Regarding Cloud Run setup. The main issue for me in setting it up (besides authentication :D) was that WebSockets are not supported. But disabling it in the protocols in Shiny server config, like instructed here works well in general, at least for "simpler" dashboards: rstudio/shiny#2455. The exception is that certain features and functions in Shiny seem to only work with WebSockets, like some parts of Dynamic UI I can't get to work properly on Cloud Run.

@hugovk
Copy link

hugovk commented Apr 22, 2020

Update: it seems to be working as usual again today. Some temporary change or something on Google's end?

Yes, looks like Google have sorted it. We've kept the fix in our library, because there's no mention of approval_prompt in the docs.

@MarkEdmondson1234
Copy link
Owner

It is possible with current code to alter the approval_prompt, which is derived from gar_shiny_auth_url

gar_shiny_auth_url <- function(req,
state = getOption("googleAuthR.securitycode"),
client.id = getOption("googleAuthR.webapp.client_id"),
client.secret = getOption("googleAuthR.webapp.client_secret"),
scope = getOption("googleAuthR.scopes.selected"),
access_type = c("online","offline"),
approval_prompt = c("auto","force")) {
access_type <- match.arg(access_type)
approval_prompt <- match.arg(approval_prompt)
url_redirect <- workout_redirect(req)
gar_shiny_getAuthUrl(url_redirect,
state = state,
client.id = client.id,
client.secret = client.secret,
scope = scope,
access_type = access_type,
approval_prompt = approval_prompt)
}

The default is approval_prompt = "auto" but change it to "force" by passing through your own login_ui function into gar_shiny_ui() which defaults to silent_auth:

gar_shiny_ui <- function(ui, login_ui = silent_auth){
check_package_loaded("shiny")
# make the ui available globally
assertthat::assert_that(is.list(ui),
is.function(login_ui))
.gar_shiny_env$ui <- ui
.gar_shiny_env$login_ui <- login_ui
# output the function
make_googleAuth_ui
}
#' Silent auth
#'
#' The default for logging in via \link{gar_shiny_ui}, this creates no login page and just takes you straight to authentication on Shiny app load.
#'
#' @param req What Shiny uses to check the URL parameters
#'
#'
#' @export
#' @family pre-load shiny authentication
silent_auth <- function(req){
shiny::tags$script(shiny::HTML(
sprintf("location.replace(\"%s\");", gar_shiny_auth_url(req)
)))
}

So it would look like:

my_silent_auth <- function(req){
    shiny::tags$script(shiny::HTML(
    sprintf("location.replace(\"%s\");", gar_shiny_auth_url(req, approval_prompt = "force")
            )))
}

ui <- fluidPage(...)

server <- function(input, output, session){
  gar_shiny_auth(session)
  ...
}

shinyApp(gar_shiny_ui(ui, login_ui = my_silent_auth), server)

The idea is you can alter the login page or behaviour as its a function that generated the login screen/URL.

Will keep this issue open to see if the default needs to change if it happens again, otherwise I should document the above a little better.

@rasnes
Copy link
Author

rasnes commented Apr 22, 2020

Okay, thank you very much!

@OuNao
Copy link

OuNao commented Apr 23, 2020

Hi,
approval_prompt is not part of GoogleAPI anymore.
https://developers.google.com/identity/protocols/oauth2/web-server#httprest

The correct parameter is "prompt"

I use googleAuth-jsUI in my project. I needed to change to be able to unforce show consent page:

googleAuth_jsUI<-function (id, login_class = "btn btn-primary", logout_class = "btn btn-danger", 
          login_text = "Log In", logout_text = "Log Out", prompt = c("consent", "select_account", "both", "none"), 
          scopes = getOption("googleAuthR.scopes.selected", "email")) 
{
  check_package_loaded("shiny")
  assert_that(is.string(login_class), is.string(logout_class), 
                          is.string(login_text), is.string(logout_text), 
              !is.null(scopes))
  prompt <- match.arg(prompt)
  if (prompt == "both") prompt<-"consent select_account"
  approval_prompt_line <- paste0(",\n 'prompt':'",prompt,"'")
  check_package_loaded("shiny")
  ns <- shiny::NS(id)
  shiny::tagList(
    shiny::tags$script(src = "https://apis.google.com/js/auth.js"), 
    shiny::tags$button(
      id = ns("login"), onclick = "auth();", 
      login_text, class = login_class), 
    shiny::tags$button(
      id = ns("logout"), 
      onclick = "out();", logout_text, class = logout_class), 
      load_js_template(
      "js/js-auth.js", 
      ns("login"), 
      ns("logout"), 
      getOption("googleAuthR.webapp.client_id"), 
      paste(scopes, collapse = " "), 
      approval_prompt_line, 
      ns("js_auth_access_token"), 
      ns("js_auth_token_type"), ns("js_auth_expires_in")))
}

Now I can select "select_account" prompt:

googleAuth_jsUI("loginButton", prompt = "select")
<script src="https://apis.google.com/js/auth.js"></script>
<button id="loginButton-login" onclick="auth();" class="btn btn-primary">Log In</button>
<button id="loginButton-logout" onclick="out();" class="btn btn-danger">Log Out</button>
<script type="text/javascript">var authorizeButton = document.getElementById('loginButton-login');var signoutButton = document.getElementById('loginButton-logout');signoutButton.style.display = 'none';function auth() {var config = {'client_id': 'myid.apps.googleusercontent.com','scope': 'https://www.googleapis.com/auth/drive.readonly' , 'prompt':'select_account'};gapi.auth.authorize(config, function() {token = gapi.auth.getToken();console.log('login complete');Shiny.onInputChange('loginButton-js_auth_access_token', token.access_token);Shiny.onInputChange('loginButton-js_auth_token_type', token.token_type);Shiny.onInputChange('loginButton-js_auth_expires_in', token.expires_in);authorizeButton.style.display = 'none';signoutButton.style.display = 'block';});}function out(){gapi.auth.signOut();location.reload();}</script>

Regards,

@MarkEdmondson1234
Copy link
Owner

Thanks very much @OuNao - I've updated the function on github (version 1.2.0) - can anyone test it to see if it works ok? A CRAN release is pending soon so this can be updated quickly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants