Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
Package: auth0
Type: Package
Title: Authentication in Shiny with Auth0
Version: 0.2.4
Version: 0.3.0
Authors@R: c(
person("Julio", "Trecenti", email = "julio.trecenti@gmail.com", role = "cre"),
person("Daniel", "Falbel", email = "dfalbel@gmail.com", role = "aut"),
person("José", "Jesus", email = "jjesusfilho@gmail.com", role = "ctb"),
person("Dean", "Attali", email = "daattali@gmail.com", role = "ctb"),
person("William", "Amorim", email = "TheWilliam89@gmail.com", role = "ctb"),
person("C", "Lente", email = "c@lente.dev", role = "ctb"))
Description: Uses Auth0 API (see <https://auth0.com> for more
information) to use a simple authentication system. It provides
Expand All @@ -16,7 +17,7 @@ BugReports: https://github.com/curso-r/auth0/issues
License: MIT + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.2
RoxygenNote: 7.3.3
Imports: httr,
shiny,
yaml,
Expand Down
7 changes: 5 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# auth0 0.2.4
# auth0 0.3.0

- fix issue #101, which was caused by incorrect parenthesis in `gsub()` function (Thanks to @teofiln for the PR #102)
- Fix issue #101, which was caused by incorrect parenthesis in `gsub()` function (Fixed by @teofiln)
- Add `request_extra_params` option to `_auth0.yml` file, to allow passing extra parameters to the authorization endpoint (Issue #100).
- Custom URL params will no longer be removed after successful authentication.
- Add `remove_callback_params` param to `shinyAppAuth0()` function to remove `code` and `state` callback parameters after successful authentication.

# auth0 0.2.3

Expand Down
5 changes: 3 additions & 2 deletions R/auth0.R
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,11 @@ auth0_info <- function(config) {
api <- auth0_api(conf$api_url, conf$request, conf$access)
audience <- conf$audience
rurl <- config$remote_url
extra_params <- config$request_extra_params
# backward compatibility
if (is.null(rurl)) rurl <- config$shiny_config$remote_url
list(scope = scope, state = state, app = app, api = api, audience=audience,
remote_url = rurl)
list(scope = scope, state = state, app = app, api = api, audience = audience,
remote_url = rurl, extra_params = extra_params)
}

#' Parse `_auth0.yml` file.
Expand Down
20 changes: 8 additions & 12 deletions R/logout.R
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,14 @@ logoutButton <- function(label = "Log out", ..., id = "._auth0logout_") {
#'
#' @export
logout_url <- function() {

config <- auth0_config()
# Use the base URL from the redirect_uri (without the current path)
base_url <- sub("(https?://[^/]+).*", "\\1", redirect_uri)
app_url_enc <- utils::URLencode(base_url, reserved = TRUE)

logout_url <- sprintf(
"%s/v2/logout?client_id=%s&returnTo=%s",
config$auth0_config$api_url,
config$auth0_config$credentials$key,
app_url_enc
)
app_url_enc <- utils::URLencode(redirect_uri, reserved = TRUE)
logout_url <- sprintf("%s/v2/logout?client_id=%s&returnTo=%s",
config$auth0_config$api_url,
config$auth0_config$credentials$key,
app_url_enc)
logout_url
}

Expand All @@ -74,14 +71,13 @@ logout_url <- function() {
#'
#' @export
logout <- function() {

if (!requireNamespace("shinyjs", quietly = TRUE)) {
stop("Package \"shinyjs\" required.", call. = FALSE)
}

shiny::insertUI(
selector = "head",
where = "beforeEnd",
immediate = TRUE,
selector = "head", where = "beforeEnd", immediate = TRUE,
ui = shinyjs::useShinyjs()
)
url <- logout_url()
Expand Down
93 changes: 43 additions & 50 deletions R/shiny.R
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#' # first, create the yml file using use_auth0() function
#'
#' if (interactive()) {
#'
#' # ui.R file
#' library(shiny)
#' library(auth0)
Expand All @@ -27,6 +28,7 @@
#' options(shiny.port = 8080)
#' shiny::runApp()
#' }
#'
#' }
#' @export
auth0_ui <- function(ui, info) {
Expand All @@ -36,53 +38,38 @@ auth0_ui <- function(ui, info) {
} else {
if (missing(info)) info <- auth0_info()
function(req) {
verify <- has_auth_code(
shiny::parseQueryString(req$QUERY_STRING),
info$state
)
verify <- has_auth_code(shiny::parseQueryString(req$QUERY_STRING), info$state)
if (!verify) {
if (grepl("error=unauthorized", req$QUERY_STRING)) {
redirect <- sprintf("location.replace(\"%s\");", logout_url())
shiny::tags$script(shiny::HTML(redirect))
} else {

params <- shiny::parseQueryString(req$QUERY_STRING)
params$code <- NULL
params$state <- NULL

# Reconstruct the query string
query <- paste(
query <- paste0("/?", paste(
mapply(paste, names(params), params, MoreArgs = list(sep = "=")),
collapse = "&"
)
query <- if (query != "") paste0("?", query) else ""

# Preserve the original path (req$PATH_INFO) in the redirect URI
if (grepl("127.0.0.1", req$HTTP_HOST)) {
redirect_uri <- paste0(
"http://",
gsub("127.0.0.1", "localhost", req$HTTP_HOST),
req$PATH_INFO,
query
)
collapse = "&"))
if (!is.null(info$remote_url) && info$remote_url != "" && !getOption("auth0_local")) {
redirect_uri <- paste0(info$remote_url, query)
} else {
redirect_uri <- paste0(
"http://",
req$HTTP_HOST,
req$PATH_INFO,
query
)
if (grepl("127.0.0.1", req$HTTP_HOST)) {
redirect_uri <- paste0("http://", gsub("127.0.0.1", "localhost", req$HTTP_HOST), query)
} else {
redirect_uri <- paste0("http://", req$HTTP_HOST, query)
}
}
redirect_uri <<- redirect_uri

# Generate the Auth0 authorization URL
query_extra <- if (is.null(info$audience)) list() else
list(audience = info$audience)
query_extra <- if(!is.null(info$audience) || !is.null(info$extra_params)) {
c(info$extra_params, list(audience = info$audience))
} else {
NULL
}
url <- httr::oauth2.0_authorize_url(
info$api,
info$app(redirect_uri),
scope = info$scope,
state = info$state,
query_extra = query_extra
info$api, info$app(redirect_uri), scope = info$scope, state = info$state,
query_extra=query_extra
)
redirect <- sprintf("location.replace(\"%s\");", url)
shiny::tags$script(shiny::HTML(redirect))
Expand All @@ -103,21 +90,20 @@ auth0_ui <- function(ui, info) {
#' @param server the shiny server function.
#' @param info object returned from [auth0_info]. If not informed,
#' will try to find the `_auth0.yml` and create it automatically.
#' @param remove_callback_params whether to remove the `code` and `state` query.
#'
#' @export
auth0_server <- function(server, info) {
auth0_server <- function(server, info, remove_callback_params = TRUE) {
disable <- getOption("auth0_disable")
if (!is.null(disable) && disable) {
server
} else {
if (missing(info)) info <- auth0_info()
function(input, output, session) {
shiny::isolate(auth0_server_verify(
session,
info$app,
info$api,
info$state
))
shiny::isolate(auth0_server_verify(session, info$app, info$api, info$state))
if (remove_callback_params) {
auth0_remove_callback_params(session)
}
shiny::observeEvent(input[["._auth0logout_"]], logout())
server(input, output, session)
}
Expand All @@ -132,6 +118,8 @@ auth0_server <- function(server, info) {
#' @param ui an ordinary UI object to create shiny apps.
#' @param server an ordinary server object to create shiny apps.
#' @param config_file path to YAML configuration file.
#' @param remove_callback_params whether to remove the `code` and `state` query
#' parameters from the URL after successful authentication. Defaults to `TRUE`.
#' @param ... Other arguments passed on to [shiny::shinyApp()].
#'
#' @details
Expand All @@ -147,7 +135,8 @@ auth0_server <- function(server, info) {
#' disable auth0 temporarily.
#'
#' @export
shinyAppAuth0 <- function(ui, server, config_file = NULL, ...) {
shinyAppAuth0 <- function(ui, server, config_file = NULL, remove_callback_params = TRUE, ...) {

disable <- getOption("auth0_disable")
if (!is.null(disable) && disable) {
shiny::shinyApp(ui, server, ...)
Expand All @@ -156,7 +145,11 @@ shinyAppAuth0 <- function(ui, server, config_file = NULL, ...) {
config_file <- auth0_find_config_file()
}
info <- auth0_info(config_file)
shiny::shinyApp(auth0_ui(ui, info), auth0_server(server, info), ...)
shiny::shinyApp(
auth0_ui(ui, info),
auth0_server(server, info, remove_callback_params),
...
)
}
}

Expand All @@ -171,10 +164,8 @@ shinyAppAuth0 <- function(ui, server, config_file = NULL, ...) {
#'
#' @export
shinyAuth0App <- function(ui, server, config_file = NULL) {
warning(
"`shinyAuth0App()` is soft-deprecated as of auth0 0.1.2.",
"Please use `shinyAppAuth0()` instead."
)
warning("`shinyAuth0App()` is soft-deprecated as of auth0 0.1.2.",
"Please use `shinyAppAuth0()` instead.")
shinyAppAuth0(ui, server, config_file)
}

Expand Down Expand Up @@ -221,12 +212,14 @@ shinyAuth0App <- function(ui, server, config_file = NULL) {
#' }
#' shinyAuth0App(ui, server, config_file)
#' }
#'
#' }
#'
#'
#' @export
auth0_logout_url <- function(config_file = NULL, redirect_js = TRUE) {
stop(
"`auth0_logout_url()` is deprecated. ",
"See `?logoutButton()` to add a logout button in auth0 apps."
)

stop("`auth0_logout_url()` is deprecated. ",
"See `?logoutButton()` to add a logout button in auth0 apps.")

}
42 changes: 40 additions & 2 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
auth0_local = interactive()
)
toset <- !(names(op.auth0) %in% names(op))
if(any(toset)) options(op.auth0[toset])
if (any(toset)) options(op.auth0[toset])
invisible()
}

Expand All @@ -24,7 +24,6 @@
#'
#' @export
auth0_find_config_file <- function() {

config_file <- getOption("auth0_config_file")

if (is.null(config_file) || !file.exists(config_file)) {
Expand All @@ -51,5 +50,44 @@ auth0_find_config_file <- function() {
config_file
}

auth0_remove_callback_params <- function(session) {
shiny::observeEvent(session[["clientData"]]$url_search,
{
params <- shiny::parseQueryString(session[["clientData"]]$url_search)

# Remove only auth callback params and keep any other query params untouched.
if (!is.null(params$code) || !is.null(params$state)) {
params$code <- NULL
params$state <- NULL

path <- session[["clientData"]]$url_pathname
hash <- session[["clientData"]]$url_hash

query <- ""
if (length(params) > 0) {
encoded <- mapply(
function(nm, val) {
paste0(
utils::URLencode(nm, reserved = TRUE),
"=",
utils::URLencode(as.character(val), reserved = TRUE)
)
},
names(params),
params,
SIMPLIFY = TRUE,
USE.NAMES = FALSE
)
query <- paste0("?", paste(encoded, collapse = "&"))
}

shiny::updateQueryString(paste0(path, query, hash), mode = "replace", session = session)
}
},
once = TRUE,
ignoreInit = FALSE
)
}

# Get rid of NOTE
globalVariables(c("redirect_uri"))
2 changes: 2 additions & 0 deletions man/auth0_logout_url.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion man/shinyAppAuth0.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading