Main helper for creating a validated OAuthClient configuration before
oauth_module_server() starts login or callback handling.
Usage
oauth_client(
provider,
client_id,
client_secret = character(0),
redirect_uri,
scopes = character(0),
response_mode = NULL,
resource = character(0),
claims = NULL,
enforce_callback_issuer = NULL,
scope_validation = c("warn", "strict", "none"),
claims_validation = c("none", "warn", "strict"),
required_acr_values = character(0),
userinfo_jwt_required_time_claims = character(0),
introspect = FALSE,
introspect_elements = character(0),
state_store = cachem::cache_mem(max_age = 300),
state_payload_max_age = 300,
state_entropy = 64,
state_key = random_urlsafe(128),
client_assertion_private_key = NULL,
client_assertion_private_key_kid = NULL,
client_assertion_alg = NULL,
client_assertion_audience = NULL,
mtls_client_cert_file = NULL,
mtls_client_key_file = NULL,
mtls_client_key_password = NULL,
mtls_client_ca_file = NULL,
mtls_certificate_bound_access_tokens = FALSE,
dpop_private_key = NULL,
dpop_private_key_kid = NULL,
dpop_signing_alg = NULL,
dpop_require_access_token = NULL,
dpop_require_observed_cnf = FALSE,
request_object_mode = c("parameters", "request", "request_uri"),
request_object_signing_alg = NULL,
request_object_audience = NULL,
request_object_encryption_alg = NULL,
request_object_encryption_enc = NULL,
request_object_encryption_kid = NULL,
request_object_ttl = 45,
request_object_nbf_skew = NULL,
jarm_signed_response_alg = NULL,
jarm_encrypted_response_alg = NULL,
jarm_encrypted_response_enc = NULL,
jarm_decryption_private_key = NULL,
jarm_decryption_private_key_kid = NULL,
jarm_max_lifetime = 600,
...
)Arguments
- provider
OAuthProvider object
- client_id
OAuth client ID
- client_secret
OAuth client secret.
Validation rules:
Required (non-empty) when the provider authenticates the client with HTTP Basic auth at the token endpoint (
token_auth_style = "header", also known asclient_secret_basic).Optional when the provider uses form-body client authentication at the token endpoint (
token_auth_style = "body", also known asclient_secret_post) anduse_pkce = TRUE. In that configuration, the secret is omitted only when it is empty.Ignored for token-endpoint authentication when the provider uses
token_auth_style = "public"(or the alias"none"). Public auth sendsclient_idonly and never sendsclient_secret, even if one is configured explicitly.
Note: If your provider issues HS256 ID tokens and
id_token_validationis enabled, a non-emptyclient_secretis required for signature validation.- redirect_uri
Redirect URI registered with provider
- scopes
Vector of scopes to request. For OIDC providers (those with an
issuer), shinyOAuth automatically prependsopenidwhen it is missing; that effective scope set is what gets sent in the authorization request and used for later state and token-scope validation.- response_mode
Authorization response mode for authorization-code callbacks. Supported values are
"query","form_post","jwt","query.jwt", and"form_post.jwt". The effective default is always"query": omitting this argument keeps the normal query-parameter callback flow and shinyOAuth does not send aresponse_modeparameter. Pass"query"only if you need to explicitly request the query response mode from the provider. Set"form_post"only when the provider requires or explicitly recommends POSTing the authorization response to the redirect URI. Shiny apps using"form_post"must wrap their UI withoauth_form_post_ui(). Prefer this argument over settingextra_auth_params$response_modeon the provider. When the provider advertisesresponse_modes_supported, the resolved mode must be included in that set."jwt"requests the JARM-defined default callback transport for the response type; for the authorization-code flow that still means a query callback, but shinyOAuth preserves and sends"jwt"when you configure it explicitly."fragment.jwt"is not currently supported because shinyOAuth does not implement fragment callback transport.JARM callbacks are currently module-only. For
"jwt","query.jwt", and"form_post.jwt", useoauth_module_server()and, for"form_post.jwt", wrap the app UI withoauth_form_post_ui(). The exportedhandle_callback()helper still accepts only the classic directcode+ sealedstatecallback shape and does not expose a public JARM validation/resume API.- resource
Optional RFC 8707 resource indicator(s). Supply a character vector of absolute URIs to request audience-restricted tokens for one or more protected resources. Each value is sent as a repeated
resourceparameter on the authorization request, initial token exchange, and token refresh requests. Default ischaracter(0).- claims
OIDC claims request parameter (OIDC Core section 5.5). Allows requesting specific claims from the UserInfo Endpoint and/or in the ID Token. Can be:
NULL(default): no claims parameter is sentA list: automatically JSON-encoded (via
jsonlite::toJSON()withauto_unbox = TRUE) and URL-encoded into the authorization request. The list should have top-level membersuserinfoand/orid_token, each containing named lists of claims. UseNULLto request a claim without parameters (per spec). Example:list(userinfo = list(email = NULL, given_name = list(essential = TRUE)), id_token = list(auth_time = list(essential = TRUE)))Note on single-element arrays: because
auto_unbox = TRUEis used, single-element R vectors are serialized as JSON scalars, not arrays. The OIDC spec definesvaluesas an array. To force array encoding for a single-element vector, wrap it inI(), e.g.,acr = list(values = I("urn:mace:incommon:iap:silver"))produces{"values":["urn:mace:incommon:iap:silver"]}. Multi-element vectors are always encoded as arrays. shinyOAuth warns when it sees a single-elementvaluesentry that is not wrapped inI(), because that common input pattern serializes incorrectly for OIDC.A character string: pre-encoded JSON string (advanced use). Must be valid JSON. Use this when you need full control over JSON encoding. Note: The
claimsparameter is OPTIONAL per OIDC Core section 5.5. Not all providers support it; consult your provider's documentation.
- enforce_callback_issuer
Logical or
NULL. WhenTRUE, enforce that authorization responses handled through this client include an RFC 9207issparameter and reject callbacks unless it exactly matchesprovider@issuer. This is recommended when one callback URL can receive responses from more than one authorization server. Requires the provider to have a configuredissuer.When
NULL(theoauth_client()helper default), shinyOAuth auto-enables this check for providers that advertiseauthorization_response_iss_parameter_supported = TRUEand have a configuredissuer, such as OIDC discovery providers that expose RFC 9207 support. SetFALSEto opt out explicitly.- scope_validation
Controls how scope discrepancies are handled when the authorization server grants fewer scopes than requested. RFC 6749 Section 3.3 permits servers to issue tokens with reduced scope, and Section 5.1 allows token responses to omit
scopewhen it is unchanged from the requested scope."warn"(default): Emits a warning but continues authentication if scopes are missing."strict": Throws an error if any requested scope is missing from the granted scopes. Omittedscopeis treated as unchanged, not as an error."none": Skips scope validation entirely.
- claims_validation
Controls validation of requested claims supplied via the
claimsparameter (OIDC Core section 5.5). Whenclaimsincludes entries withessential = TRUEforid_tokenoruserinfo, or explicitvalue/valuesconstraints for individual claims, this setting determines what happens if the returned ID token or userinfo response does not satisfy those requests."none": Skips claims validation entirely. This remains the effective default when the suppliedclaimsrequest has no enforceableessential,value, orvaluesconstraints, and when you explicitly setclaims_validation = "none"."warn": Emits a warning but continues authentication if requested essential claims are missing or requested claim values are not satisfied."strict": Throws an error if any requested essential claims are missing or requested claimvalue/valuesconstraints are not satisfied by the response.
If
claims_validationis omitted and the suppliedclaimsrequest does include enforceableessential,value, orvaluesconstraints,oauth_client()promotes the effective default to"warn"so those mismatches are surfaced by default.Enforceable requests under
claims$id_tokenrequire a validated ID token. Configure the provider withid_token_validation = TRUEoruse_nonce = TRUEso shinyOAuth validates the ID token before checking those claims.- required_acr_values
Optional character vector of acceptable Authentication Context Class Reference values (OIDC Core sections 2 and 3.1.2.1). When non-empty, the ID token returned by the provider must contain an
acrclaim whose value is one of the specified entries; otherwise the login fails with ashinyOAuth_id_token_error.Additionally, when non-empty, the authorization request automatically includes an
acr_valuesquery parameter (space-separated) as a voluntary hint to the provider (OIDC Core section 3.1.2.1). Note that the provider is not required to honour this hint; the client-side validation is the authoritative enforcement.Requires an OIDC-capable provider with
id_token_validation = TRUEand anissuerconfigured. Default ischaracter(0)(no enforcement).- userinfo_jwt_required_time_claims
Optional character vector of temporal JWT claims that must be present when the UserInfo response is a signed JWT (
application/jwt). Allowed values are"exp","iat", and"nbf".Default is
character(0), which means these claims are validated only when present. Set, for example,userinfo_jwt_required_time_claims = "exp"to require an expiry on signed UserInfo JWTs, or pass multiple values to require additional temporal claims. For security-sensitive deployments that accept signed UserInfo JWTs, prefer requiring at least"exp".- introspect
If TRUE, the login flow will call the provider's token introspection endpoint (RFC 7662) to validate the access token. The login is not considered complete unless introspection succeeds and returns
active = TRUE; otherwise the login fails andauthenticatedremains FALSE. Whenoauth_module_server()later performs proactive refresh, it also forwards this setting so refreshed access tokens are introspected through the same client policy. Default is FALSE. Requires the provider to have anintrospection_urlconfigured.- introspect_elements
Optional character vector of additional requirements to enforce on the introspection response when
introspect = TRUE. Supported values:"sub": require the introspectedsubto match the session subject (from a validated ID tokensubwhen available, else from userinfosub)."client_id": require the introspectedclient_idto match your OAuth client id."scope": validate introspectedscopeagainst requested scopes (respects the client'sscope_validationmode)."token_type": require introspection to returntoken_type. This is useful for sender-constrained deployments such as DPoP, where introspection can authoritatively reporttoken_type = "DPoP". Default ischaracter(0). (Note that not all providers may return each of these fields in introspection responses.)
- state_store
State storage backend. Defaults to
cachem::cache_mem(max_age = 300). Alternative backends should usecustom_cache()with an atomic$take()method for replay-safe single-use state consumption. The backend must implement cachem-like methods$get(key, missing),$set(key, value), and$remove(key);$info()is optional.Stored values must round-trip
browser_tokenas a non-empty string.pkce_code_verifierandnonceare required only when the provider enables PKCE or nonce validation; otherwise backends may keep those fields asNULLor omit them.cachem::cache_mem()is a good default for a single Shiny process. For multi-process deployments, usecustom_cache()with an atomic$take()backed by a shared store (for example RedisGETDELor SQLDELETE ... RETURNING). Plaincachem::cache_disk()is not safe as a shared state store because its$get()+$remove()operations are not atomic.The client automatically generates, persists (in
state_store), and validates the OAuthstateparameter (and OIDCnoncewhen applicable) during the authorization code flow.- state_payload_max_age
Positive number of seconds. Maximum allowed age for the decrypted state payload's
issued_attimestamp during callback validation.This is the freshness window for the sealed
statepayload itself. It is separate from thestate_storeTTL, which controls how long the one-time server-side state entry can exist.Default is 300 seconds.
- state_entropy
Integer. The length (in characters) of the randomly generated state parameter. Higher values provide more entropy and better security against CSRF attacks. Must be between 22 and 128 (to align with
validate_state()'s default minimum which targets ~128 bits for base64url-like strings). Default is 64.- state_key
Optional per-client secret used as the state sealing key for AES-GCM AEAD (authenticated encryption) of the state payload that travels via the
statequery parameter. This provides confidentiality and integrity (via authentication tag) for the embedded data used during callback verification. If you omit this argument, a random value is generated viarandom_urlsafe(128). This key is distinct from the OAuthclient_secretand may be used with public clients.Type: character string (>= 32 bytes when encoded) or raw vector (>= 32 bytes). Raw keys enable direct use of high-entropy secrets from external stores. Both forms are normalized internally by cryptographic helpers.
Multi-process deployments: if your app runs with multiple R workers or behind a non-sticky load balancer, configure a shared
state_storeand the samestate_keyacross all workers. Otherwise callbacks that land on a different worker will fail state validation.- client_assertion_private_key
Optional private key for
private_key_jwtclient authentication at the token endpoint. Can be anopenssl::keyor a PEM string containing a private key. Required when the provider'stoken_auth_style = 'private_key_jwt'. Ignored for other auth styles. Current outbound private-key JWT signing supports RSA and EC private keys. For RSA keys, outbound signing is currently limited toRS256;RS384,RS512, and RSA-PSS (PS256,PS384,PS512) are not supported. Ed25519/Ed448 keys are also not currently supported.- client_assertion_private_key_kid
Optional key identifier (kid) to include in the JWT header for
private_key_jwtassertions. Useful when the authorization server uses kid to select the correct verification key.- client_assertion_alg
Optional JWT signing algorithm to use for client assertions. When omitted, defaults to
HS256forclient_secret_jwt. Forprivate_key_jwt, a compatible default is selected based on the private key type/curve (e.g.,RS256for RSA orES256/ES384/ES512for EC P-256/384/521). If an explicit value is provided but incompatible with the key, validation fails early with a configuration error. When the provider advertisestoken_endpoint_auth_signing_alg_values_supported, both explicit values and inferred defaults must be included in that set. Supported values areHS256,HS384,HS512for client_secret_jwt and asymmetric algorithms supported for outbound signing (RS256,ES256,ES384,ES512) for private keys.RS384,RS512,PS256,PS384,PS512, andEdDSAare not currently supported for outbound client assertions.- client_assertion_audience
Optional override for the
audclaim used when building JWT client assertions (client_secret_jwt/private_key_jwt). By default, shinyOAuth uses the exact token endpoint request URL. Some identity providers require a different audience value; set this to the exact value your IdP expects.- mtls_client_cert_file
Optional path to the PEM-encoded client certificate (or certificate chain) used for RFC 8705 mutual TLS client authentication and certificate-bound protected-resource requests. Required when
provider@token_auth_styleis"tls_client_auth"or"self_signed_tls_client_auth".- mtls_client_key_file
Optional path to the PEM-encoded private key used with
mtls_client_cert_file. Must be supplied together withmtls_client_cert_file, and is required for RFC 8705 mTLS client authentication.- mtls_client_key_password
Optional password used to decrypt an encrypted PEM private key referenced by
mtls_client_key_file.- mtls_client_ca_file
Optional path to a PEM CA bundle used to validate the remote HTTPS server certificate when making mTLS requests. This is mainly useful for local or test environments that use self-signed server certificates.
- mtls_certificate_bound_access_tokens
Logical. Whether this client intends to request RFC 8705 certificate-bound access tokens when the provider advertises that capability. Default is
FALSE.Set this to
TRUEfor clients that should prefer discoveredmtls_endpoint_aliaseson authorization-server requests even whentoken_auth_styleitself is not an mTLS auth style, and that should fail closed if the returned access token omitscnf.x5t#S256.Requires
mtls_client_cert_fileandmtls_client_key_file, and the provider must be configured withmtls_client_certificate_bound_access_tokens = TRUE.- dpop_private_key
Optional private key used to generate DPoP proofs (RFC 9449). Can be an
openssl::keyor a PEM string containing an asymmetric private key. When provided, shinyOAuth can attachDPoPproofs to token endpoint requests and use DPoP-bound access tokens in downstream request helpers. Inoauth_client(), configuring this key also makesdpop_require_access_tokendefault toTRUE, so access-token responses rejecttoken_type = "Bearer"unless you explicitly setdpop_require_access_token = FALSE. Current outbound DPoP signing supports RSA and EC private keys. For RSA keys, outbound signing is currently limited toRS256;RS384,RS512, and RSA-PSS (PS256,PS384,PS512) are not supported. Ed25519/Ed448 keys are also not currently supported. This is an advanced setting; most clients do not need DPoP unless their provider or resource server asks for it.- dpop_private_key_kid
Optional key identifier (
kid) to include in the JOSE header of DPoP proofs. Useful when the authorization or resource server expects a stable key identifier alongside the embedded public JWK.- dpop_signing_alg
Optional JWT signing algorithm to use for DPoP proofs. When omitted, a compatible asymmetric default is selected based on the private key type/curve (for example
RS256,ES256,ES384, orES512).RS384,RS512,PS256,PS384,PS512, andEdDSAare not currently supported for outbound DPoP proofs. If an explicit value is provided but incompatible with the key, validation fails early with a configuration error. When the provider advertisesdpop_signing_alg_values_supported, both explicit values and inferred defaults must be included in that set.- dpop_require_access_token
Logical or
NULL. WhenTRUEanddpop_private_keyis configured, shinyOAuth requires the authorization server to returntoken_type = "DPoP"for access tokens and fails fast otherwise. When shinyOAuth can observe token binding data from a JWT access token or an introspection response, this strict mode also requirescnf$jktto be present and match the configureddpop_private_key. Opaque access tokens that expose nocnfdata still pass this check unless introspection later reveals the binding. Inoauth_client(), the defaultNULLresolves toTRUEwhendpop_private_keyis configured and toFALSEotherwise. SetFALSEexplicitly only when you intentionally want to allow Bearer access tokens, such as deployments where DPoP is used only to bind refresh tokens.- dpop_require_observed_cnf
Logical. When
TRUE, shinyOAuth rejectstoken_type = "DPoP"access tokens unless it can observecnf$jktlocally, either from the access token itself or from a token introspection response. Use this when high-assurance DPoP deployments must fail closed on opaque access tokens that provide no observable binding. Default isFALSE.- request_object_mode
Controls how the authorization request is transported to the provider.
"parameters"(default): send OAuth parameters directly on the browser redirect URL."request": send a signed JWT-secured authorization request (JAR; RFC 9101) via therequestparameter."request_uri": publish a signed Request Object by reference and send its URL via therequest_uriparameter.
Most users can keep the default. Request mode is an advanced option that requires signing material on the client. shinyOAuth prefers
client_assertion_private_keywhen present; otherwise it falls back to HMAC signing withclient_secret. When Request Object encryption is configured, shinyOAuth signs first and then wraps the signed Request Object in a JWE. If a caller-managedrequest_uriuses HTTP and the configured host policy explicitly allows it, shinyOAuth still publishes it but warns once per R session because RFC 9101 Section 5.2 expects client-providedrequest_urivalues to use HTTPS. If the provider advertisesrequest_uri_registration_required = TRUE, caller-managedrequest_uripublication still depends on the provider having that URI or a matching wildcard prefix registered for the client; shinyOAuth cannot verify that server-side registration automatically.- request_object_signing_alg
Optional JWS algorithm override for signed authorization requests when
request_object_modeuses a Request Object ("request"or"request_uri"). When omitted, shinyOAuth choosesHS256for HMAC-based signing or a compatible asymmetric default based onclient_assertion_private_key(for exampleRS256,ES256,ES384, orES512).RS384,RS512,PS256,PS384,PS512, andEdDSAare not currently supported for outbound signed authorization requests.- request_object_audience
Optional override for the
audclaim used in signed authorization requests. By default, shinyOAuth uses the provider issuer when available. Whenrequest_object_mode = "request"or"request_uri", the provider must have a configured issuer or you must supply an explicit override so the signed Request Object remains audience-bound to the intended authorization server.- request_object_encryption_alg
Optional JWE key-management algorithm override for encrypted Request Objects. Current outbound support is limited to
RSA-OAEP. When set, you must also setrequest_object_encryption_enc.- request_object_encryption_enc
Optional JWE content-encryption algorithm override for encrypted Request Objects. Current outbound support is limited to the AES-CBC-HMAC family (
A128CBC-HS256,A192CBC-HS384,A256CBC-HS512). When set, you must also setrequest_object_encryption_alg.- request_object_encryption_kid
Optional key identifier (
kid) used to select one provider encryption key and emit the outer JWEkidheader. This is mainly useful when the provider publishes more than one Request Object encryption key.- request_object_ttl
Positive number of seconds to keep signed authorization request objects (
requestJWTs) valid. Whenrequest_object_mode = "request_uri", shinyOAuth also uses this value as the default publication window for the referenced Request Object URI. Default is45.- request_object_nbf_skew
Optional non-negative number of seconds. When provided, shinyOAuth adds an
nbfclaim set toiat - request_object_nbf_skewso deployments can tolerate small clock skew while still emitting bounded request-object validity windows. LeaveNULL(the default) to omitnbf. Request-objectnbfis reserved by shinyOAuth and cannot be supplied through extra authorization parameters.- jarm_signed_response_alg
Optional expected JWS algorithm for signed JWT Secured Authorization Responses (JARM). When omitted and the effective response mode is JARM, shinyOAuth defaults to
RS256. This value is not sent dynamically on the authorization request; it must match the client metadata and provider behavior configured out-of-band for that client. Current inbound support acceptsHS256,HS384,HS512,RS256,RS384,RS512,ES256,ES384,ES512, andEdDSA. RSA-PSS (PS256,PS384,PS512) and unsecurednoneare not accepted for inbound JARM.- jarm_encrypted_response_alg
Optional expected JWE key-management algorithm for encrypted JARM responses. Current inbound support is limited to
RSA-OAEP. Likejarm_signed_response_alg, this reflects out-of-band client metadata and expected provider behavior rather than an authorization request parameter emitted by shinyOAuth.- jarm_encrypted_response_enc
Optional expected JWE content-encryption algorithm for encrypted JARM responses. Current inbound support is limited to the AES-CBC-HMAC family (
A128CBC-HS256,A192CBC-HS384,A256CBC-HS512). When omitted whilejarm_encrypted_response_algis set, shinyOAuth defaults toA128CBC-HS256. This must also match the provider-side JARM client metadata when encrypted responses are enabled.- jarm_decryption_private_key
Optional private key used to decrypt encrypted JARM responses. Can be an
openssl::keyor a PEM string containing a private key. Required when encrypted JARM is enabled.- jarm_decryption_private_key_kid
Optional key identifier (
kid) associated withjarm_decryption_private_key.- jarm_max_lifetime
Positive number of seconds. Maximum accepted lifetime for a JARM response JWT. Default is 600 seconds, matching JARM's recommended 10-minute upper bound for authorization response JWTs. When a JARM payload includes
iat, shinyOAuth enforcesexp - iat <= jarm_max_lifetime; otherwise it falls back to the remainingexpwindow at validation time. Applies only whenresponse_modeuses JARM.- ...
Deprecated renamed arguments accepted temporarily for backward compatibility.
Value
OAuthClient object
Examples
if (
# Example requires configured GitHub OAuth 2.0 app
# (go to https://github.com/settings/developers to create one):
nzchar(Sys.getenv("GITHUB_OAUTH_CLIENT_ID")) &&
nzchar(Sys.getenv("GITHUB_OAUTH_CLIENT_SECRET")) &&
interactive()
) {
library(shiny)
library(shinyOAuth)
# Define client
client <- oauth_client(
provider = oauth_provider_github(),
client_id = Sys.getenv("GITHUB_OAUTH_CLIENT_ID"),
client_secret = Sys.getenv("GITHUB_OAUTH_CLIENT_SECRET"),
redirect_uri = "http://127.0.0.1:8100"
)
# Choose which app you want to run
app_to_run <- NULL
while (!isTRUE(app_to_run %in% c(1:4))) {
app_to_run <- readline(
prompt = paste0(
"Which example app do you want to run?\n",
" 1: Auto-redirect login\n",
" 2: Manual login button\n",
" 3: Fetch additional resource with access token\n",
" 4: No app (all will be defined but none run)\n",
"Enter 1, 2, 3, or 4... "
)
)
}
if (app_to_run %in% c(1:3)) {
cli::cli_alert_info(paste0(
"Will run example app {app_to_run} on {.url http://127.0.0.1:8100}\n",
"Open this URL in a regular browser (viewers in RStudio/Positron/etc. ",
"cannot perform necessary redirects)"
))
}
# Example app with auto-redirect (1) -----------------------------------------
ui_1 <- fluidPage(
use_shinyOAuth(),
uiOutput("login")
)
server_1 <- function(input, output, session) {
# Auto-redirect (default):
auth <- oauth_module_server(
"auth",
client,
auto_redirect = TRUE
)
output$login <- renderUI({
if (auth$authenticated) {
user_info <- auth$token@userinfo
tagList(
tags$p("You are logged in!"),
tags$pre(paste(capture.output(str(user_info)), collapse = "\n"))
)
} else {
tags$p("You are not logged in.")
}
})
}
app_1 <- shinyApp(ui_1, server_1)
if (app_to_run == "1") {
runApp(
app_1,
port = 8100,
launch.browser = FALSE
)
}
# Example app with manual login button (2) -----------------------------------
ui_2 <- fluidPage(
use_shinyOAuth(),
actionButton("login_btn", "Login"),
uiOutput("login")
)
server_2 <- function(input, output, session) {
auth <- oauth_module_server(
"auth",
client,
auto_redirect = FALSE
)
observeEvent(input$login_btn, {
auth$request_login()
})
output$login <- renderUI({
if (auth$authenticated) {
user_info <- auth$token@userinfo
tagList(
tags$p("You are logged in!"),
tags$pre(paste(capture.output(str(user_info)), collapse = "\n"))
)
} else {
tags$p("You are not logged in.")
}
})
}
app_2 <- shinyApp(ui_2, server_2)
if (app_to_run == "2") {
runApp(
app_2,
port = 8100,
launch.browser = FALSE
)
}
# Example app requesting additional resource with access token (3) -----------
# Below app shows the authenticated username + their GitHub repositories,
# fetched via GitHub API using the access token obtained during login
ui_3 <- fluidPage(
use_shinyOAuth(),
uiOutput("ui")
)
server_3 <- function(input, output, session) {
auth <- oauth_module_server(
"auth",
client,
auto_redirect = TRUE
)
repositories <- reactiveVal(NULL)
observe({
req(auth$authenticated)
# Example additional API request using the access token
# (e.g., fetch user repositories from GitHub)
resp <- perform_resource_req(
auth$token,
"https://api.github.com/user/repos"
)
if (httr2::resp_is_error(resp)) {
repositories(NULL)
} else {
repos_data <- httr2::resp_body_json(resp, simplifyVector = TRUE)
repositories(repos_data)
}
})
# Render username + their repositories
output$ui <- renderUI({
if (isTRUE(auth$authenticated)) {
user_info <- auth$token@userinfo
repos <- repositories()
return(tagList(
tags$p(paste("You are logged in as:", user_info$login)),
tags$h4("Your repositories:"),
if (!is.null(repos)) {
tags$ul(
Map(
function(url, name) {
tags$li(tags$a(href = url, target = "_blank", name))
},
repos$html_url,
repos$full_name
)
)
} else {
tags$p("Loading repositories...")
}
))
}
return(tags$p("You are not logged in."))
})
}
app_3 <- shinyApp(ui_3, server_3)
if (app_to_run == "3") {
runApp(
app_3,
port = 8100,
launch.browser = FALSE
)
}
}