Skip to contents

Introspects an access or refresh token when the provider exposes an introspection endpoint (RFC 7662). Returns a small result object describing whether introspection is supported and, when known, whether the token is active.

Authentication to the introspection endpoint mirrors the provider's token_auth_style:

  • "header" (default): HTTP Basic with client_id/client_secret.

  • "body": form fields client_id and (when available) client_secret.

  • "public": form field client_id only; client_secret is never sent.

  • "client_secret_jwt" / "private_key_jwt": a signed JWT client assertion is generated (RFC 7523) and sent via client_assertion_type and client_assertion, with aud resolved via resolve_client_assertion_audience() (so client_assertion_audience overrides are honored).

Usage

introspect_token(
  oauth_client,
  oauth_token,
  which = c("access", "refresh"),
  async = FALSE,
  shiny_session = NULL
)

Arguments

oauth_client

OAuthClient object

oauth_token

OAuthToken object to introspect

which

Which token to introspect: "access" (default) or "refresh".

async

Logical, default FALSE. If TRUE and an async backend is configured, the operation is dispatched through shinyOAuth's async promise path and this function returns a promise-compatible async result that resolves to the result list. 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.

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

A list with fields:

  • supported: logical, TRUE when an introspection endpoint is configured.

  • active: logical or NA, where NA means the provider did not return a usable RFC 7662 active value.

  • raw: parsed introspection response list, or NULL when the endpoint is unsupported or the response could not be parsed.

  • status: machine-readable status such as "ok", "introspection_unsupported", "missing_token", "invalid_json", "missing_active", "invalid_active", or "http_<code>".

Details

Best-effort semantics:

  • If the provider does not expose an introspection endpoint, the function returns supported = FALSE, active = NA, and status = "introspection_unsupported".

  • If the endpoint responds with an HTTP error (e.g., 404/500) or the body cannot be parsed or does not include a usable active field, the function does not throw. It returns supported = TRUE, active = NA, and a descriptive status (for example, "http_404", "invalid_json", "missing_active"). In this context, NA means "unknown" and will not break flows unless your code explicitly requires a definitive result (i.e., isTRUE(result$active)).

  • Providers vary in how they encode the RFC 7662 active field (logical, numeric, or character variants like "true"/"false", 1/0). These are normalized to logical TRUE/FALSE when possible; otherwise active is set to NA.

Side effects

Performs network I/O when the provider exposes an introspection endpoint and the selected token exists. Emits best-effort audit events and OpenTelemetry span attributes. When async = TRUE, the work may run in a background worker.

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)
}