Changelog
Source:NEWS.md
shinyOAuth (development version)
Prevent ‘mirai’ warning spam about ‘stats’ maybe not being available in workers.
Reduce serialization overhead towards async workers by using certain functions from the package namespace directly.
shinyOAuth 0.3.0
Async backend: the default async backend is now ‘mirai’ (>= 2.0.0) for simpler and more efficient asynchronous execution. Use
mirai::daemons()to configure async workers. A ‘future’ backend configured withfuture::plan()is still supported, but ‘mirai’ takes precedence if both are configured.Test suite: fixed inconsistent results of several tests; tests not suitable for CRAN now skip on CRAN. Silenced test output messages to avoid confusion.
shinyOAuth 0.2.0
CRAN release: 2026-01-13
New/improved
Security
Token revocation: tokens can now be revoked when Shiny session ends. Enable via
revoke_on_session_end = TRUEinoauth_module_server(). The provider must expose arevocation_url(auto-discovered for OIDC, or set manually viaoauth_provider()). New exported functionrevoke_token().Token introspection on login: validate tokens via the provider’s introspection endpoint during login. Configure via
introspectandintrospect_elementsproperties onOAuthClient. The provider must expose anintrospection_url(auto-discovered for OIDC, or set manually viaoauth_provider()).DoS protection: callback query parameters and state payload/browser token sizes are validated before expensive operations (e.g., hashing for audit logs). Maximum size may be configured via
options(); see section ‘Size caps’ invignette("usage", package = "shinyOAuth").DoS protection: rate-limited JWKS refresh: forced JWKS cache refreshes (triggered by unknown
kid) are now rate-limited to prevent abuse.JWKS pinning: pinning is now enforced during signature verification: previously,
jwks_pinswithjwks_pin_mode = "any"only verified that at least one key in the JWKS matched a pin, but signature verification could still use any matching key (pinned or not). Now, signature verification is restricted to only use keys whose thumbprints appear in the pin list, ensuring true key pinning rather than presence-only checks.use_shinyOAuth()now injects<meta name="referrer" content="no-referrer">by default to reduce leaking ?code=…&state=… via the Referer header on the callback page. Can be disabled withuse_shinyOAuth(inject_referrer_meta = FALSE).Sensitive outbound HTTP requests (token exchange/refresh, introspection, revocation, userinfo, OIDC discovery, JWKS) now by default disable redirect following and reject 3xx responses to prevent bypassing host/HTTPS policies. Configurable via
options(shinyOAuth.allow_redirect = TRUE).client_bearer_req()also gainsfollow_redirect, which defaults toFALSE, to similarly control redirect behavior for requests using bearer tokens.State is now also consumed in login failure paths (when the provider returns an error but also a state).
Callback URL parameters are now also cleared in login failure paths.
OAuthProvidernow requires absolute URLs (scheme + hostname) for all endpoint URLs.Provider fingerprint now includes
userinfo_urlandintrospection_url, reducing risk of misconfiguration when multiple providers share endpoints.state_payload_max_ageproperty onOAuthClientfor independent freshness validation of the state payload’sissued_attimestamp.Default client assertion JWT TTL reduced from 5 minutes to 120 seconds, reducing the window for replay attacks while allowing for clock skew.
Auditing
New audit events:
session_ended(logged on Shiny session close),authenticated_changed(logged when authentication status changes),token_introspection(whenintrospect_token()is used),token_revocation(whenrevoke_token()is used),error_state_consumedanderror_state_consumption_failed(called when provider returns an error during callback handling and the state is attempted to be consumed).All audit events now include
$process_id,$is_async, and$main_process_id(if called from an async worker); these fields help identify which process generated the event and whether it was from an async worker. Async workers now also properly propagate audit hooks from the main process (see ‘Fixed’).Audit event
login_successnow includessub_sourceto indicate whether the subject digest came fromuserinfo,id_token(verified), orid_token_unverified.Audit digest keying: audit/event digests (e.g.,
sub_digest,browser_token_digest) now default to HMAC-SHA256 with an auto-generated per-process key to reduce reidentification/correlation risk if logs leak. Configure a key withoptions(shinyOAuth.audit_digest_key = "..."), or disable keying (legacy deterministic SHA-256) withoptions(shinyOAuth.audit_digest_key = FALSE).HTTP log sanitization: sensitive data in HTTP contexts (headers, cookies) is now sanitized by default in audit logs. Can be disabled with
options(shinyOAuth.audit_redact_http = FALSE). Useoptions(shinyOAuth.audit_include_http = FALSE)to not include any HTTP data in logs.
UX
Configurable scope validation:
validate_scopesproperty onOAuthClientcontrols whether returned scopes are validated against requested scopes ("strict","warn", or"none"). Scopes are now normalized (alphabetically sorted) before comparison.OAuthProvider: extra parameters are now blocked from overriding reserved keys essential for the OAuth 2.0/OIDC flow. Reserved keys may be explicitly overridden viaoptions(shinyOAuth.unblock_auth_params = c(...), shinyOAuth.unblock_token_params = c(...), shinyOAuth.unblock_token_headers = c(...)). It is also validated early that all parameters are named, catching configuration errors sooner.Added warning about negative
expires_invalues in token responses.Added warning when
OAuthClientis instantiated inside a Shiny session; may cause sealed state payload decryption to fail when random secret is generated upon client creation.Added hints in error messages when sealed state payload decryption fails.
Ensured a clearer error message when token response is in unexpected format.
Ensured a clearer error when retrieved state store entry is in unexpected format.
Ensured a clearer error message when retrieved userinfo cannot be parsed as JSON.
Immediate error when
OAuthProviderusesHS*algorithm butoptions(shinyOAuth.allow_hs = TRUE)is not enabled; also immediate error whenOAuthProviderusesHS*algorithm and ID token verification can happen butclient_secretis absent or too weak.build_auth_url()now uses package-typed errors (err_invalid_state()) instead of genericstopifnot()assertions, ensuring consistent error handling and audit logging.
Other
ID token signature/claims validation now occurs before fetching userinfo. This ensures cryptographic validation passes before making external calls to the userinfo endpoint.
When fetching JWKS, if
key_opsis present on keys, only keys withkey_opsincluding"verify"are considered.oauth_provider()now defaultsallowed_token_typestoc("Bearer")for all providers. This prevents accidentally misusing non-Bearer tokens (e.g., DPoP, MAC) as Bearer tokens. Setallowed_token_types = character()to opt out. Token type is also now validated before calling the userinfo endpoint.client_assertion_audienceproperty onOAuthClientallows overriding the JWT audience claim for client assertion authentication.
Fixed
Package now correctly requires
httr2>= 1.1.0.authenticatednow flips toFALSEpromptly when a token expires orreauth_after_secondselapses, even without other reactive changes. Previously, the value could remainTRUEpast expiry until an unrelated reactive update triggered re-evaluation.HTTP error responses (4xx/5xx) are now correctly returned to the caller immediately instead of being misclassified as transport errors and retried.
Async worker options propagation: all R options are now automatically propagated to async workers when using
async = TRUE. Previously, options set in the main process (includingaudit_hook,trace_hook, HTTP settings, and any custom options) were not available infuture::multisessionworkers.oauth_provider_microsoft(): fixed incorrect default which blocked multi-tenant configuration.oauth_provider_oidc_discover(): stricter host matching;?and*wildcards now correctly handled.Fixed potential auto-redirect loop after authentication error has surfaced.
Fixed potential race condition between proactive refresh and expiry watcher: the expiry watcher now defers clearing the token and triggering reauthentication while a refresh is in progress.
Token expiry handling during token refresh now aligns with how it is handled during login.
State payload
issued_atvalidation now applies clock drift leeway (fromOAuthProvider@leeway/shinyOAuth.leewayoption), consistent with ID tokeniatcheck.
shinyOAuth 0.1.4
CRAN release: 2025-11-24
Added a console warning about needing to access Shiny apps with
oauth_module_server()in a regular browser; also updated examples and vignettes to further clarify this.oauth_module_server(): improved formatting style of warning messages (now consistent with error messages).
shinyOAuth 0.1.3
CRAN release: 2025-11-10
Rewrote
vignette("authentication-flow")to improve clarity.Skip timing-sensitive tests on CRAN.