diff --git a/NEWS.md b/NEWS.md index 5002f252..009ed9c5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,11 @@ # httr 0.6.1.9000 +- `oauth1.0_token` and `oauth2.0_token` now permit the `oauth_listener` to listen on + a custom IP address and port (the previously hardwired ip:port of `127.0.0.1:1410` + is now just the default). This permits authentication to work under other settings, + such as inside docker containers (which require localhost uses `0.0.0.0` instead). + Thanks @cboettig (#211). + # httr 0.6.1 * Correctly parse headers with multiple `:`, thanks to @mmorgan (#180). diff --git a/R/oauth-init.R b/R/oauth-init.R index 204e9b19..af4d3d8e 100644 --- a/R/oauth-init.R +++ b/R/oauth-init.R @@ -7,10 +7,12 @@ #' \code{\link{oauth_app}} #' @param permission optional, a string of permissions to ask for. #' @param is_interactive Is the current environment interactive? +#' @inheritParams oauth_listener #' @export #' @keywords internal init_oauth1.0 <- function(endpoint, app, permission = NULL, - is_interactive = interactive()) { + is_interactive = interactive(), + host = "127.0.0.1", port = 1410) { oauth_sig <- function(url, method, token = NULL, token_secret = NULL, ...) { oauth_header(oauth_signature(url, method, app, token, token_secret, ..., @@ -28,7 +30,7 @@ init_oauth1.0 <- function(endpoint, app, permission = NULL, authorize_url <- modify_url(endpoint$authorize, query = list( oauth_token = token, permission = "read")) - verifier <- oauth_listener(authorize_url, is_interactive)$oauth_verifier + verifier <- oauth_listener(authorize_url, is_interactive, host, port)$oauth_verifier # 3. Request access token response <- POST(endpoint$access, @@ -50,11 +52,13 @@ init_oauth1.0 <- function(endpoint, app, permission = NULL, #' Otherwise, provide a URL to the user and prompt for a validation #' code. Defaults to the of the \code{"httr_oob_default"} default, #' or \code{TRUE} if \code{httpuv} is not installed. +#' @inheritParams oauth_listener #' @export #' @keywords internal init_oauth2.0 <- function(endpoint, app, scope = NULL, type = NULL, use_oob = getOption("httr_oob_default"), - is_interactive = interactive()) { + is_interactive = interactive(), + host = "127.0.0.1", port = 1410) { if (!use_oob && !is_installed("httpuv")) { message("httpuv not installed, defaulting to out-of-band authentication") use_oob <- TRUE @@ -80,7 +84,7 @@ init_oauth2.0 <- function(endpoint, app, scope = NULL, type = NULL, if (isTRUE(use_oob)) { code <- oauth_exchanger(authorize_url)$code } else { - code <- oauth_listener(authorize_url, is_interactive)$code + code <- oauth_listener(authorize_url, is_interactive, host, port)$code } # Use authorisation code to get (temporary) access token diff --git a/R/oauth-listener.r b/R/oauth-listener.r index f63bb76e..7370c3bb 100644 --- a/R/oauth-listener.r +++ b/R/oauth-listener.r @@ -10,9 +10,11 @@ #' #' @param request_url the url to send the browser to #' @param is_interactive Is an interactive environment available? +#' @param host ip address for the listener +#' @param port for the listener #' @export #' @keywords internal -oauth_listener <- function(request_url, is_interactive = interactive()) { +oauth_listener <- function(request_url, is_interactive = interactive(), host = "127.0.0.1", port = 1410) { if (!is_installed("httpuv")) { stop("httpuv package required to capture OAuth credentials.") } @@ -45,7 +47,7 @@ oauth_listener <- function(request_url, is_interactive = interactive()) { ) } - server <- httpuv::startServer("127.0.0.1", 1410, list(call = listen)) + server <- httpuv::startServer(host, port, list(call = listen)) on.exit(httpuv::stopServer(server)) message("Waiting for authentication in browser...") diff --git a/R/oauth-token.r b/R/oauth-token.r index ace86dab..3bea5ddd 100644 --- a/R/oauth-token.r +++ b/R/oauth-token.r @@ -133,7 +133,8 @@ Token <- R6::R6Class("Token", list( #' @export oauth1.0_token <- function(endpoint, app, permission = NULL, as_header = TRUE, - cache = getOption("httr_oauth_cache")) { + cache = getOption("httr_oauth_cache"), + host = "127.0.0.1", port = 1410) { params <- list(permission = permission, as_header = as_header) Token1.0$new(app = app, endpoint = endpoint, params = params, @@ -145,7 +146,7 @@ oauth1.0_token <- function(endpoint, app, permission = NULL, Token1.0 <- R6::R6Class("Token1.0", inherit = Token, list( init_credentials = function(force = FALSE) { self$credentials <- init_oauth1.0(self$endpoint, self$app, - permission = self$params$permission) + permission = self$params$permission, host = host, port = port) }, can_refresh = function() { FALSE @@ -186,7 +187,8 @@ Token1.0 <- R6::R6Class("Token1.0", inherit = Token, list( oauth2.0_token <- function(endpoint, app, scope = NULL, type = NULL, use_oob = getOption("httr_oob_default"), as_header = TRUE, - cache = getOption("httr_oauth_cache")) { + cache = getOption("httr_oauth_cache"), + host = "127.0.0.1", port = 1410) { params <- list(scope = scope, type = type, use_oob = use_oob, as_header = as_header) Token2.0$new(app = app, endpoint = endpoint, params = params, @@ -199,7 +201,7 @@ Token2.0 <- R6::R6Class("Token2.0", inherit = Token, list( init_credentials = function() { self$credentials <- init_oauth2.0(self$endpoint, self$app, scope = self$params$scope, type = self$params$type, - use_oob = self$params$use_oob) + use_oob = self$params$use_oob, host = host, port = port) }, can_refresh = function() { !is.null(self$credentials$refresh_token)