test_that("oauth2", { skip_on_cran() # Create the resource server rsapp <- local_app_process( oauth2_resource_app(), opts = server_opts(num_threads = 3) ) regi_url <- rsapp$url("/register") auth_url <- rsapp$url("/authorize") toke_url <- rsapp$url("/token") # Create the third party app server tpapp <- local_app_process( oauth2_third_party_app("3P app"), opts = server_opts(num_threads = 3) ) redi_url <- tpapp$url("/login/redirect") conf_url <- tpapp$url("/login/config") # Register the third party app at the resource server # In real life this is done by the admin of the third party app url <- paste0( regi_url, "?name=3P%20app", "&redirect_uri=", redi_url ) resp <- curl::curl_fetch_memory(url) expect_equal(resp$status_code, 200L) regdata <- jsonlite::fromJSON(rawToChar(resp$content)) # Now set this data on the third party app # In real life this is included in the config of the third party app # by its admin auth_data <- jsonlite::toJSON(list( auth_url = auth_url, token_url = toke_url, client_id = regdata$client_id, client_secret = regdata$client_secret ), auto_unbox = TRUE) handle <- curl::new_handle() curl::handle_setheaders( handle, "content-type" = "application/json" ) curl::handle_setopt( handle, customrequest = "POST", postfieldsize = nchar(auth_data), postfields = auth_data ) resp2 <- curl::curl_fetch_memory(conf_url, handle = handle) expect_equal(resp2$status_code, 200L) # Now everything is set up, a user can go to the login page of the # third party app: # browseURL(tpapp$url("/login")) # Scripting it is a bit tedious, because we need to parse the HTML and # submit a form. The `oauth2_login()` helper function does this. resp3 <- oauth2_login(tpapp$url("/login")) token <- jsonlite::fromJSON(rawToChar(resp3$token_response$content)) expect_equal(resp3$login_response$status_code, 200L) expect_equal(resp3$login_response$type, "text/html") expect_equal(resp3$token_response$status_code, 200L) expect_match(token$access_token, "^token-[0-9a-f]+$") }) test_that("oauth + httr", { skip_on_cran() # Not great, the OS should allocate a port, really... withr::local_envvar(c( HTTP_SERVER = "127.0.0.1", HTTP_SERVER_PORT = httpuv::randomPort() )) # Create the resource server rsappex <- oauth2_resource_app(access_duration = 0.1) log <- tempfile("webfakes-log-", fileext = ".log") on.exit(unlink(log, recursive = TRUE), add = TRUE) rsappex$use(logger = mw_log(stream = log), .first = TRUE) rsapp <- local_app_process( rsappex, opts = server_opts(num_threads = 3) ) regi_url <- rsapp$url("/register") auth_url <- rsapp$url("/authorize") toke_url <- rsapp$url("/token") # Register httr url <- paste0( regi_url, "?name=httr%20local%20app", "&redirect_uri=", httr::oauth_callback() ) reg_resp <- httr::GET(url) httr::stop_for_status(reg_resp) regdata <- httr::content(reg_resp) app <- httr::oauth_app( regdata$name[[1]], key = regdata$client_id[[1]], secret = regdata$client_secret[[1]], redirect_uri = httr::oauth_callback() ) endpoint <- httr::oauth_endpoint( authorize = auth_url, access = toke_url ) token <- suppressMessages(oauth2_httr_login( httr::oauth2.0_token(endpoint, app, cache = FALSE) )) # This will refresh the token automatically Sys.sleep(0.1) expect_message( cnt <- httr::content( httr::GET(rsapp$url("/data"), config = token), as = "parsed", type = "application/json" ), "Auto-refreshing stale OAuth" ) expect_equal(cnt, list(data = list("top secret!"))) loglines <- readLines(log) endpoints <- parse_url(map_chr(strsplit(loglines, " "), "[[", 2))$path expect_equal( endpoints, c("/register", "/authorize", "/authorize/decision", "/token", "/data", "/token", "/data") ) status <- map_chr(strsplit(loglines, " "), "[[", 3) expect_equal( as.numeric(status), c(200, 200, 302, 200, 401, 200, 200) ) })