I'm looking to write some simple ETL scripts to query an API in R. They only authenticate successfully after I have run update.packages('openssl') and I'm not exactly sure what this means, beyond something being misconfigured.
Edit with runnable sample:
The following test GET request...
library(httr)
library(openssl)
library(tidyverse)
library(DBI)
#### SET QUERY/FORM VARIABLES ####
#### SET URL ENDPOINTS ####
api_base <- 'https://reqres.in'
sub_endpt <- '/api/unknown/2'
sub_url <- paste0(api_base, sub_endpt)
page_req <- GET(sub_url
, encode = 'json'
, verbose(info=TRUE)
...generates the following error:
* Trying 172.67.222.36...
* TCP_NODELAY set
* Connected to reqres.in (172.67.222.36) port 443 (#0)
* schannel: SSL/TLS connection with reqres.in port 443 (step 1/3)
* schannel: disabled server certificate revocation checks
* schannel: sending initial handshake data: sending 157 bytes...
* schannel: sent initial handshake data: sent 157 bytes
* schannel: SSL/TLS connection with reqres.in port 443 (step 2/3)
* schannel: failed to receive handshake, need more data
* schannel: SSL/TLS connection with reqres.in port 443 (step 2/3)
* schannel: encrypted data got 139
* schannel: encrypted data buffer: offset 139 length 4096
* schannel: next InitializeSecurityContext failed: SEC_E_INVALID_TOKEN (0x80090308) - The token supplied to the function is invalid
* Closing connection 0
* schannel: shutting down SSL/TLS connection with reqres.in port 443
* schannel: clear security context handle
Error in curl::curl_fetch_memory(url, handle = handle) :
schannel: next InitializeSecurityContext failed: SEC_E_INVALID_TOKEN (0x80090308) - The token supplied to the function is invalid
This same script works after running update.packages('openssl')
, but only if update.packages('openssl')
is run each time.
library(httr)
library(openssl)
library(tidyverse)
library(DBI)
update.packages('openssl')
#### SET QUERY/FORM VARIABLES ####
#### SET URL ENDPOINTS ####
api_base <- 'https://reqres.in'
sub_endpt <- '/api/unknown/2'
sub_url <- paste0(api_base, sub_endpt)
page_req <- GET(sub_url
, encode = 'json'
, verbose(info=TRUE)
)
After running the above, I instead receive:
Hostname in DNS cache was stale, zapped
* Trying 104.21.59.93...
* TCP_NODELAY set
* Connected to reqres.in (104.21.59.93) port 443 (#1)
* schannel: SSL/TLS connection with reqres.in port 443 (step 1/3)
* schannel: disabled server certificate revocation checks
* schannel: sending initial handshake data: sending 157 bytes...
* schannel: sent initial handshake data: sent 157 bytes
* schannel: SSL/TLS connection with reqres.in port 443 (step 2/3)
* schannel: failed to receive handshake, need more data
* schannel: SSL/TLS connection with reqres.in port 443 (step 2/3)
* schannel: encrypted data got 2563
* schannel: encrypted data buffer: offset 2563 length 4096
* schannel: sending next handshake data: sending 126 bytes...
* schannel: SSL/TLS connection with reqres.in port 443 (step 2/3)
* schannel: encrypted data got 258
* schannel: encrypted data buffer: offset 258 length 4096
* schannel: SSL/TLS handshake complete
* schannel: SSL/TLS connection with reqres.in port 443 (step 3/3)
* schannel: stored credential handle in session cache
-> GET /api/unknown/2 HTTP/1.1
-> Host: reqres.in
-> User-Agent: libcurl/7.59.0 r-curl/3.3 httr/1.4.1
-> Accept-Encoding: gzip, deflate
-> Accept: application/json, text/xml, application/xml, */*
->
* schannel: client wants to read 16384 bytes
* schannel: encdata_buffer resized 17408
* schannel: encrypted data buffer: offset 0 length 17408
* schannel: encrypted data got 1168
* schannel: encrypted data buffer: offset 1168 length 17408
* schannel: decrypted data length: 1105
* schannel: decrypted data added: 1105
* schannel: decrypted data cached: offset 1105 length 16384
* schannel: encrypted data length: 34
* schannel: encrypted data cached: offset 34 length 17408
* schannel: decrypted data length: 5
* schannel: decrypted data added: 5
* schannel: decrypted data cached: offset 1110 length 16384
* schannel: encrypted data buffer: offset 0 length 17408
* schannel: decrypted data buffer: offset 1110 length 16384
* schannel: schannel_recv cleanup
* schannel: decrypted data returned 1110
* schannel: decrypted data buffer: offset 0 length 16384
<- HTTP/1.1 200 OK
<- Date: Sat, 29 Jan 2022 16:11:59 GMT
<- Content-Type: application/json; charset=utf-8
<- Transfer-Encoding: chunked
<- Connection: keep-alive
<- x-powered-by: Express
<- access-control-allow-origin: *
<- etag: W/"e8-ov4wWh4/OY1IMQMqWgskYtOFnVs"
<- via: 1.1 vegur
<- Cache-Control: max-age=14400
<- CF-Cache-Status: REVALIDATED
<- Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
<- Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=fyNvgiYFkSfx2bLgj4G0uybx5hN7f9uUIiFjrgijkYbZD7FkoBWhZfFl%2BniMEaaf%2B8Ur5nMmH1Pe3mCgnwudLptXgIaYDRi8WZvItt%2Fz69En%2B%2BwTEhWhRuBbMDk%3D"}],"group":"cf-nel","max_age":604800}
<- NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
<- Vary: Accept-Encoding
<- Server: cloudflare
<- CF-RAY: 6d53bd4fe9628c90-EWR
<- Content-Encoding: gzip
<- alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
<-
* Connection #1 to host reqres.in left intact
I've confirmed this fails with the same error if I restart my R session and run the script without update.packages('openssl')
.
I've also confirmed that this also succeeds when I run update.packages('openssl')
before any of my library imports.
Original Post
I'm using the following libraries:
library(httr)
library(curl)
library(openssl)
library(tidyverse)
library(DBI)
After these imports, my sessionInfo() is:
R version 4.0.2 (2020-06-22)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 17763)
Matrix products: default
locale:
[1] LC_COLLATE=English_United States.1252 LC_CTYPE=English_United States.1252 LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] DBI_1.1.0 forcats_0.5.0 stringr_1.4.0 dplyr_1.0.0 purrr_0.3.4 readr_1.3.1
[7] tidyr_1.1.0 tibble_3.0.2 ggplot2_3.3.2 tidyverse_1.3.0 openssl_1.4.2 curl_3.3
[13] httr_1.4.1 RevoUtils_11.0.2 RevoUtilsMath_11.0.0
loaded via a namespace (and not attached):
[1] Rcpp_1.0.5 cellranger_1.1.0 pillar_1.4.6 compiler_4.0.2 dbplyr_1.4.4 tools_4.0.2 lubridate_1.7.9
[8] jsonlite_1.7.0 lifecycle_0.2.0 gtable_0.3.0 pkgconfig_2.0.3 rlang_0.4.6 reprex_0.3.0 cli_2.0.2
[15] rstudioapi_0.11 haven_2.3.1 withr_2.2.0 xml2_1.3.2 fs_1.4.2 hms_0.5.3 generics_0.0.2
[22] vctrs_0.3.1 askpass_1.1 grid_4.0.2 tidyselect_1.1.0 glue_1.4.1 R6_2.3.0 fansi_0.4.1
[29] readxl_1.3.1 modelr_0.1.8 blob_1.2.1 magrittr_1.5 backports_1.1.7 scales_1.1.1 ellipsis_0.3.1
[36] rvest_0.3.5 assertthat_0.2.1 colorspace_1.4-1 stringi_1.4.6 munsell_0.5.0 broom_0.7.0 crayon_1.3.4
When I import those libraries and then run my script, I get the following:
schannel: SSL/TLS connection with www.formstack.com port 443 (step 1/3)
* schannel: disabled server certificate revocation checks
* schannel: sending initial handshake data: sending 165 bytes...
* schannel: sent initial handshake data: sent 165 bytes
* schannel: SSL/TLS connection with www.formstack.com port 443 (step 2/3)
* schannel: failed to receive handshake, need more data
* schannel: SSL/TLS connection with www.formstack.com port 443 (step 2/3)
* schannel: encrypted data got 139
* schannel: encrypted data buffer: offset 139 length 4096
* schannel: next InitializeSecurityContext failed: SEC_E_INVALID_TOKEN (0x80090308) - The token supplied to the function is invalid
* Closing connection 0
* schannel: shutting down SSL/TLS connection with www.formstack.com port 443
* schannel: clear security context handle
Error in curl::curl_fetch_memory(url, handle = handle) :
schannel: next InitializeSecurityContext failed: SEC_E_INVALID_TOKEN (0x80090308) - The token supplied to the function is invalid
My script succeeds when I instead run:
library(httr)
library(curl)
library(openssl)
library(tidyverse)
library(DBI)
update.packages('openssl')
I suspected that this might have something to do with a conflict between curl and httr, because of this upon import:
> library(curl)
Attaching package: ‘curl’
The following object is masked from ‘package:httr’:
handle_reset
But the script also succeeds when I run the update first and swap the order of httr and curl imports, such as:
update.packages('openssl')
library(curl)
library(httr)
library(openssl)
library(tidyverse)
library(DBI)
I hope that's enough to help troubleshoot what's wrong in my environment here and appreciate any and all lessons about library maintenance / dependencies.