Skip to contents

This reference lists package-wide options for network requests, logging, and validation. Set options near the top of app.R, before creating the provider and client. The defaults apply when an option is unset.

For example, allow a slow provider up to ten seconds per HTTP request:

options(shinyOAuth.timeout = 10)

Times are in seconds unless a setting explicitly says milliseconds. Options affect the R process; use oauth_client() and oauth_module_server() arguments for settings that belong to one client or module. See Usage for app setup.

check_oauth21() is an opt-in, read-only assessment pinned to OAuth 2.1 draft 16. Ruleset 1.1.0 reports requirement sources: OAuth core, OIDC, extensions, security guidance, and package or application policy. Recommendations do not change the mandatory configuration verdict. Existing OAuth 2.0 authentication methods and callback choices remain available. For example, Basic/body client authentication can pass while receiving advice to consider asymmetric methods. Distinct callback routes remain valid when issuer identification is unavailable, and localhost callbacks remain supported with advice to prefer a loopback IP.

Callback capacity advice uses local field defaults and an 8000-byte minimum envelope as package thresholds, not numeric OAuth 2.1 requirements. Test the complete encoded query or form body against package, proxy and browser limits: include parameter names, separators, fixed application parameters, percent encoding, state, issuer and JARM. An aggregate floor cannot guarantee that all decoded fields fit simultaneously. Back-channel redirect blocking is package policy motivated by credential confidentiality; the draft’s browser redirect rules are a separate requirement.

Logging

  • options(shinyOAuth.audit_hook = function(event){ ... }) – receive structured audit and error events
  • options(shinyOAuth.audit_include_http = FALSE) – exclude HTTP request details from audit events (default: TRUE)
  • options(shinyOAuth.audit_include_raw_session_token = TRUE) – include the raw shiny_session[["token"]] in native audit-hook payloads. By default, hooks receive only shiny_session[["session_token_digest"]]
  • options(shinyOAuth.audit_redact_http = FALSE) – disable automatic redaction of sensitive data in audit events (default: TRUE). Debug only: raw mode can expose cookies, authorization headers, codes, state values, and client IP addresses
  • options(shinyOAuth.telemetry_path_scrubber = function(path) NULL) – optionally return an approved route template for audit and OTel paths. Paths are omitted by default. Return NULL for unknown routes; remove identifying segments and make the function idempotent. Input is bounded to 2048 bytes and output to 512 bytes.
  • options(shinyOAuth.audit_digest_key = ...) – shared key of at least 32 bytes for HMAC-SHA256 digests used in audit/OTel attributes. Invalid configured keys cause an error; by default, ‘shinyOAuth’ generates a random per-process key when this is not configured
  • options(shinyOAuth.otel_tracing_enabled = FALSE) – disable ‘shinyOAuth’ OpenTelemetry span creation and async trace-context propagation. Default: TRUE
  • options(shinyOAuth.otel_logging_enabled = FALSE) – disable ‘shinyOAuth’ OpenTelemetry log emission. Default: TRUE
  • options(shinyOAuth.otel_include_authorization_details = TRUE) – include raw scope names, claim targets, and ACR values in telemetry. Default: FALSE (counts only). These fields may be sensitive and have high cardinality.

See the audit logging vignette for details about audit hooks, and the OpenTelemetry vignette for more details about logs and traces via OpenTelemetry.

Validation and URL policy

  • options(shinyOAuth.access_token_cnf = "opaque") – never decode access tokens to obtain sender-binding metadata. DPoP and mTLS still check cnf from token responses and introspection and present their configured sender credentials. The compatibility default "jwt" inspects JWT cnf without validating the access-token signature; select it only where that representation is agreed with the provider. This option is propagated to async workers. Requiring observed binding remains a separate client policy (dpop_require_observed_cnf or mtls_require_observed_cnf).

  • options(shinyOAuth.leeway = 30) – default clock skew leeway (seconds) for ID token exp/iat/nbf checks and state payload issued_at future check

  • options(shinyOAuth.max_id_token_lifetime = 86400) – maximum ID token lifetime in seconds (exp - iat). This is an additional package check beyond the OIDC expiry check. Default 86400 (24 hours). Set to Inf to disable the check

  • options(shinyOAuth.allowed_non_https_hosts = c("localhost", "127.0.0.1", "::1", "[::1]")) - allows these hosts to use http:// in non-OIDC URL checks; it does not relax OIDC discovery

  • options(shinyOAuth.allow_insecure_oidc_loopback = TRUE) – development-only opt-in for OIDC issuer and endpoint URLs on HTTP loopback origins; production OIDC metadata URLs must use HTTPS

  • options(shinyOAuth.allowed_hosts = c()) – when non‑empty, restricts accepted hosts to this whitelist

  • options(shinyOAuth.allow_hs = TRUE) – opt‑in HMAC validation for ID tokens (HS256/HS384/HS512). Requires a strictly server‑side client_secret

  • options(shinyOAuth.client_assertion_ttl = 120L) – lifetime in seconds for JWT client assertions used with client_secret_jwt or private_key_jwt token endpoint authentication. Finite values below 60 seconds are coerced to 60 seconds, finite values above 300 seconds are clamped to 300 seconds, and NA or non-finite values fall back to the 120-second default

  • options(shinyOAuth.state_fail_delay_ms = 0) – delay in milliseconds before state parsing or decryption failures. Defaults to 0 (no delay). A positive number sets a fixed delay; two numbers, such as c(10, 30), set bounds for a randomized delay. Positive delays sleep synchronously and block the Shiny worker, including initial state validation with async = TRUE. The delay adds timing noise but does not provide constant-time validation.

Note on allowed_hosts: patterns support globs (*, ?). Using a catch‑all like "*" matches any host and effectively disables endpoint host restrictions (scheme rules still apply). Avoid this unless you truly intend to accept any host; prefer pinning to your domain(s), e.g., c(".example.com").

Advanced parameter overrides

By default, ‘shinyOAuth’ blocks certain security-critical parameters from being passed via extra_auth_params, extra_token_params, and extra_token_headers. This helps prevent accidental misconfiguration that could break state binding, PKCE, or client authentication.

Set the callback format with oauth_client(response_mode = ...).

If you have a specific, advanced use case where you need to override one of these blocked parameters, you can unblock them using the following options:

  • options(shinyOAuth.unblock_auth_params = c("redirect_uri")) – allows replacing the specified authorization URL parameters. Default blocked: response_type, client_id, redirect_uri, state, request_uri, request, scope, code_challenge, code_challenge_method, nonce, claims
  • Transaction and credential fields can never be unblocked: state, nonce, client_id, code, all PKCE fields, refresh_token, client_secret, client_assertion, client_assertion_type, request, request_uri, response_type, and grant_type. Allowed overrides replace existing names case insensitively; they do not append a duplicate protocol parameter.
  • options(shinyOAuth.unblock_token_params = c(...)) – allows replacing the specified token exchange parameters. Default blocked: grant_type, code, redirect_uri, code_verifier, client_id, client_secret, client_assertion, client_assertion_type
  • options(shinyOAuth.unblock_token_headers = c("authorization")) – allows overriding the specified token exchange headers (case-insensitive). Default blocked: Authorization, Cookie

Async timeout (mirai)

  • options(shinyOAuth.async_timeout = 10000) – per-task timeout in milliseconds for mirai async tasks. When using mirai with dispatcher (the default), timed-out tasks are automatically cancelled and resolve as a mirai error. Use NULL (the default) for no timeout, or a whole number from 0 to 2147483647. Ignored when falling back to the ‘future’ backend

Async condition replay

  • options(shinyOAuth.replay_async_conditions = FALSE) – when FALSE, warnings and messages captured from async workers are silently discarded instead of being re-emitted on the main R process. Default is TRUE (replay all captured conditions). Useful if worker diagnostics are too noisy or handled separately via audit_hook

Token lifetime fallback

  • options(shinyOAuth.default_expires_in = 3600) – fallback token lifetime (in seconds) when the provider omits expires_in from the token response

HTTP settings (timeout, retries, user agent)

  • options(shinyOAuth.tls_min_version = "1.2") - optionally require TLS 1.2 or later on package-owned HTTPS requests. "1.3" requires TLS 1.3 or later; NULL (default) retains the linked curl/TLS backend’s defaults. Applies before discovery and to token, PAR, JWKS, UserInfo and resource requests, including async workers. A stronger supplied minimum and a compatible supplied maximum survive; a conflicting maximum or disabled certificate/hostname verification raises an error when a minimum is selected. Custom CA settings remain usable. The setting is bound to pending login transactions, so change it before initiating login. It does not configure browser/proxy TLS or disallow HTTP development endpoints. Older wolfSSL backends require curl 8.10.0 or later to apply minimum-version semantics. Actual negotiated connections remain runtime evidence; an absent option alone says nothing about their TLS version.

  • options(shinyOAuth.timeout = 5) – default HTTP timeout (seconds) applied to all outbound requests (discovery, JWKS, token exchange, userinfo). Increase if your provider/network is slow. Values beyond curl’s supported timeout range are capped

  • options(shinyOAuth.retry_max_tries = 3L) – maximum attempts for retryable requests after network errors or HTTP 408, 429, or 5xx responses. Authorization-code exchange and refresh are not automatically retried, apart from a single DPoP nonce challenge retry

  • options(shinyOAuth.dpop_nonce_max_bytes = 4096L) – maximum DPoP nonce size in bytes. RFC 9449 sets no length limit; this local resource limit is configurable from 1 to 65536 bytes and is propagated to async workers. A response exceeding it raises a specific error without exposing the nonce. Raise it if your provider legitimately issues larger nonces

  • options(shinyOAuth.retry_backoff_base = 0.5) – base backoff in seconds used for exponential backoff with jitter

  • options(shinyOAuth.retry_backoff_cap = 5) – per‑attempt cap on backoff seconds (before jitter)

  • options(shinyOAuth.retry_after_cap = 60) – maximum synchronous sleep in seconds for a server-provided Retry-After value; this is separate from the client-side backoff cap

  • options(shinyOAuth.retry_status = c(408L, 429L, 500:599)) – HTTP statuses considered transient and retried

  • options(shinyOAuth.user_agent = "shinyOAuth/<version> R/<version> httr2/<version>") – override the default User‑Agent header applied to all outbound requests. By default this string is built dynamically from the installed package/runtime versions; set a custom string here if your organization requires a specific format

  • options(shinyOAuth.allow_redirect = FALSE) – when FALSE (default), all sensitive HTTP requests (token exchange, refresh, introspection, revocation, userinfo, OIDC discovery, JWKS) refuse to follow redirects and reject 3xx responses. This prevents authorization codes, tokens, and PKCE verifiers from leaking to redirect targets. Set to TRUE only when you deliberately accept that redirect-following risk for a specific deployment; this opt-in is honored in all sessions

  • options(shinyOAuth.max_body_bytes = 1048576) – maximum response body size (bytes, default 1 MiB) accepted from OAuth endpoints and resource requests. Increase this if an API legitimately returns larger payloads. The limit also applies after gzip decompression; other content encodings are rejected. Values above R’s supported binary-read size are capped

State store

  • options(shinyOAuth.allow_non_atomic_state_store = TRUE) – allow a shared state store without atomic [["take"]]() to use separate [["get"]]() and [["remove"]]() calls. Default FALSE: such a store causes an error. With TRUE, the package warns once and proceeds, but concurrent requests may reuse a login entry. Use an atomic shared store for production; see custom_cache().

Size caps

State envelope

  • options(shinyOAuth.state_max_token_chars = 8192) – maximum allowed length of the base64url-encoded state query parameter
  • options(shinyOAuth.state_max_wrapper_bytes = 8192) – maximum decoded byte size of the outer JSON wrapper (before parsing)
  • options(shinyOAuth.state_max_ct_b64_chars = 8192) – maximum allowed length of the base64url-encoded ciphertext inside the wrapper
  • options(shinyOAuth.state_max_ct_bytes = 8192) – maximum decoded byte size of the ciphertext before attempting AES-GCM decrypt

These prevent maliciously large state parameters from causing excessive CPU or memory usage during decoding and decryption.

Callback query

  • options(shinyOAuth.callback_max_code_bytes = 8192) – maximum decoded byte length of the code callback parameter across direct, GET/POST bridge, module and JARM paths. Explicit lower or higher limits remain effective; values are rejected rather than truncated
  • options(shinyOAuth.callback_max_state_bytes = 8192) – maximum byte length of the state query parameter (outer token string)
  • options(shinyOAuth.callback_max_error_bytes = 256) – maximum byte length of the error query parameter
  • options(shinyOAuth.callback_max_error_description_bytes = 4096) – maximum byte length of the error_description query parameter
  • options(shinyOAuth.callback_max_error_uri_bytes = 2048) – maximum byte length of the error_uri query parameter
  • options(shinyOAuth.callback_max_iss_bytes = 2048) – maximum byte length of the iss query parameter (RFC 9207 issuer identification)
  • options(shinyOAuth.callback_max_query_bytes = <derived>) – maximum total byte length of the raw query string. HTTP UI wrappers apply this budget to every request, including ordinary application queries and hosted Request Object requests, before routing or parsing.
  • options(shinyOAuth.callback_max_browser_token_bytes = 256) – maximum byte length of the browser_token argument accepted by handle_callback()
  • options(shinyOAuth.callback_max_form_post_body_bytes = <derived>) – maximum byte length of the raw form_post callback body before parsing
  • options(shinyOAuth.callback_max_form_post_handle_bytes = 128) – maximum byte length of the transient shinyOAuth_form_post handle query parameter
  • options(shinyOAuth.callback_max_form_post_id_bytes = 256) – maximum byte length of the transient shinyOAuth_form_post_id module-id query parameter

These limits reject oversized callback URLs and POST bodies before they cause excessive processing or logging. Keep the defaults unless a legitimate provider response needs more space.

Generated login state must fit both shinyOAuth.callback_max_state_bytes and the state envelope limits above. Their outer-token defaults both allow 8192 bytes (base64url state is ASCII). Lowering either limit can restrict ordinary logins with many scopes or other state metadata. prepare_call() checks both budgets before storing pending login state, publishing a Request Object, or sending PAR. Increasing only one limit does not override the other.

Local debugging

  • options(shinyOAuth.skip_browser_token = TRUE) – skip browser cookie binding in tests or interactive sessions

  • options(shinyOAuth.skip_id_sig = TRUE) – skip ID token signature verification in tests or interactive sessions

  • options(shinyOAuth.allow_unsigned_userinfo_jwt = TRUE) – accept unsigned (alg=none) UserInfo JWTs in tests or interactive sessions; outside those contexts ‘shinyOAuth’ errors instead of honoring it

  • options(shinyOAuth.debug = TRUE) – re‑raise errors during token exchange

  • options(shinyOAuth.expose_error_body = TRUE) – include sanitized HTTP bodies, claim values, and free-form error details in audit/OTel output and module diagnostics during tests or interactive debugging. Details omit URL credentials and control characters and are capped at 512 UTF-8 bytes per field; they may still contain sensitive information. Production processes keep these details disabled.

    HTTP and transport condition contexts use the same URL and diagnostic policy. Transport parents retain their error classes but omit original request/response objects, calls, backtraces, and nested parents. Their messages are withheld by default; the exposure option enables only sanitized messages. JWKS metadata failures also withhold underlying diagnostics by default.

Don’t enable these options in production. They disable key security checks or alter error behavior, and are intended for local testing/debugging only.