Skip to contents

Refreshes an OAuth session by obtaining a new access token with the refresh token. When configured, shinyOAuth also re-fetches userinfo and validates any new ID token returned by the provider.

Per OIDC Core Section 12.2, providers may omit the ID token from refresh responses. When omitted, the original ID token from the initial login is preserved.

If the provider does return a new ID token during refresh, refresh_token() requires that an original ID token from the initial login is available so it can enforce subject continuity (OIDC 12.2: sub MUST match). If no original ID token is available, refresh fails with an error.

When id_token_validation = TRUE, any refresh-returned ID token is also fully validated (signature and claims) in addition to the OIDC 12.2 sub continuity check.

When userinfo_required = TRUE, userinfo is re-fetched using the fresh access token. Whenever shinyOAuth has both refreshed userinfo and a validated ID token baseline, it checks that their sub claims still match. If userinfo_id_token_match = TRUE, the absence of a trustworthy ID token baseline is treated as an error instead of silently accepting unbound userinfo data.

Usage

refresh_token(
  oauth_client,
  token,
  async = FALSE,
  introspect = FALSE,
  shiny_session = NULL
)

Arguments

oauth_client

OAuthClient object

token

OAuthToken object containing the refresh token

async

Logical, default FALSE. If TRUE and an async backend is configured, the refresh is dispatched through shinyOAuth's async promise path and this function returns a promise-compatible async result that resolves to an updated OAuthToken. mirai::mirai is preferred when daemons are configured via mirai::daemons(); otherwise the current future::future plan is used. Non-sequential future plans run off the main R session; future::sequential() stays in-process.

introspect

Logical, default FALSE. After a successful refresh, if the provider exposes an introspection endpoint, introspect the new access token for validation and audit/diagnostics. When enabled, refresh fails if introspection is unsupported, inactive, or missing required introspect_elements. The raw introspection result is not stored separately, but a successful introspection response may backfill token@cnf.

shiny_session

Optional pre-captured Shiny session context (from capture_shiny_session_context()) to include in audit events. Used when calling from async workers that lack access to the reactive domain.

Value

An updated OAuthToken object with refreshed credentials.

What changes:

  • access_token: Always updated to the fresh token

  • expires_at: Computed from expires_in when provided; otherwise a finite fallback expiry from resolve_missing_expires_in()

  • refresh_token: Updated if the provider rotates it; otherwise preserved

  • id_token: Updated only if the provider returns one (and it validates); otherwise the original from login is preserved

  • userinfo: Refreshed if userinfo_required = TRUE; otherwise preserved

  • cnf: Updated from the token response when present, and may be backfilled from refresh-time introspection when enabled

Validation failures cause errors: If the provider returns a new ID token that fails validation (wrong issuer, audience, expired, or subject mismatch with original), or if userinfo subject doesn't match the new ID token, the refresh fails with an error. In oauth_module_server(), this clears the session and sets authenticated = FALSE.

Examples

# Please note: `get_userinfo()`, `introspect_token()`, and `refresh_token()`
# are typically not called by users of this package directly, but are called
# internally by `oauth_module_server()`. These functions are exported
# nonetheless for advanced use cases. Most users will not need to
# call these functions directly

# Example requires a real token from a completed OAuth flow
# (code is therefore not run; would error with placeholder values below)
if (interactive()) {
  # 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"
  )

  # Have a valid OAuthToken object; fake example below
  # (typically provided by `oauth_module_server()` or `handle_callback()`)
  token <- handle_callback(client, "<code>", "<payload>", "<browser_token>")

  # Get userinfo
  user_info <- get_userinfo(client, token)

  # Introspect token (if supported by provider)
  introspection <- introspect_token(client, token)

  # Refresh token
  new_token <- refresh_token(client, token, introspect = TRUE)
}