S7 class describing an OAuth 2.0 or OpenID Connect provider. It stores the provider's endpoints and the rules shinyOAuth should follow during login, callback handling, token exchange, and optional OIDC checks.
This is a low-level constructor intended for advanced use. Most users should
prefer the helper constructors oauth_provider() for generic OAuth 2.0
providers or oauth_provider_oidc() / oauth_provider_oidc_discover() for
OpenID Connect providers. Those helpers enable secure defaults based on the
presence of an issuer and available endpoints.
Usage
OAuthProvider(
name = character(0),
auth_url = character(0),
token_url = character(0),
issuer = NA_character_,
issuer_match = "url",
token_auth_style = "header",
use_pkce = TRUE,
pkce_method = "S256",
use_nonce = FALSE,
userinfo_url = NA_character_,
userinfo_required = FALSE,
userinfo_id_selector = function(userinfo) userinfo[["sub"]],
userinfo_id_token_match = FALSE,
userinfo_signed_jwt_required = FALSE,
id_token_required = FALSE,
id_token_validation = FALSE,
id_token_at_hash_required = FALSE,
introspection_url = NA_character_,
revocation_url = NA_character_,
extra_auth_params = list(),
extra_token_params = list(),
extra_token_headers = character(0),
jwks_uri = NA_character_,
jwks_cache = cachem::cache_mem(max_age = 3600),
jwks_pins = character(0),
jwks_pin_mode = "any",
jwks_host_issuer_match = FALSE,
jwks_host_allow_only = NA_character_,
allowed_algs = c("RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "EdDSA"),
allowed_token_types = "Bearer",
par_url = NA_character_,
par_required = FALSE,
signed_request_object_required = FALSE,
request_parameter_supported = NA,
request_uri_parameter_supported = NA,
request_uri_registration_required = NA,
request_object_signing_alg_values_supported = character(0),
request_object_encryption_alg_values_supported = character(0),
request_object_encryption_enc_values_supported = character(0),
request_object_encryption_jwk = NULL,
authorization_request_front_channel_mode = "compat",
authorization_response_iss_parameter_supported = FALSE,
response_modes_supported = character(0),
jarm_signing_alg_values_supported = character(0),
jarm_encryption_alg_values_supported = character(0),
jarm_encryption_enc_values_supported = character(0),
jarm_tolerate_duplicate_top_level_iss = FALSE,
token_endpoint_auth_signing_alg_values_supported = character(0),
dpop_signing_alg_values_supported = character(0),
mtls_endpoint_aliases = list(),
mtls_client_certificate_bound_access_tokens = FALSE,
leeway = getOption("shinyOAuth.leeway", 30)
)Arguments
- name
Provider name (e.g., "github", "google"). Cosmetic only; used in logging and audit events
- auth_url
Authorization endpoint URL
- token_url
Token endpoint URL
- issuer
Optional OIDC issuer URL. You need this when you want ID token validation. shinyOAuth uses it to verify the ID token
issclaim and to locate the provider's signing keys (JWKS), typically through the OIDC discovery document at/.well-known/openid-configuration.- issuer_match
Character scalar controlling how strictly the discovery document's
issueris validated againstissuerwhen it later performs runtime discovery to locate the JWKS URI."url"(default): require the issuer used for discovery to match exactly after removing one trailing slash, if present, from both the configured issuer and the discovery metadata value."host": compare only scheme + host."none": do not validate discovery issuer consistency.
In most cases, keep the default
"url". Use"host"only for providers that publish tenant-independent metadata with a templated issuer, such as some Microsoft aliases.- token_auth_style
How the client authenticates at the token endpoint. One of:
"header": HTTP Basic (client_secret_basic)
"body": Form body (client_secret_post)
"public": Public-client form body (
nonein discovery metadata); sendsclient_idbut neverclient_secret, even if one is configured. The alias"none"is also accepted."tls_client_auth": RFC 8705 mutual TLS client authentication using a client certificate chained to a trusted CA
"self_signed_tls_client_auth": RFC 8705 mutual TLS client authentication using a self-signed client certificate registered out of band with the provider
"client_secret_jwt": JWT client assertion signed with HMAC using client_secret (RFC 7523)
"private_key_jwt": JWT client assertion signed with an asymmetric key (RFC 7523)
- use_pkce
Whether to use PKCE. This adds a
code_challengeparameter to the authorization request and requires acode_verifierwhen exchanging the authorization code for tokens. This helps protect against authorization code interception attacks.- pkce_method
PKCE code challenge method ("S256" or "plain"). "S256" is recommended. Use "plain" only if you are working with a provider that does not support "S256".
- use_nonce
Whether to use OIDC nonce. This adds a
nonceparameter to the authorization request and validates thenonceclaim in the ID token. For OIDC providers, leaving this enabled is usually the right choice.- userinfo_url
User info endpoint URL (optional)
- userinfo_required
Whether to fetch userinfo after token exchange. User information will be stored in the
userinfofield of the returnedOAuthTokenobject. This requires a validuserinfo_urlto be set. If fetching userinfo fails, login fails.For the low-level constructor
oauth_provider(), when not explicitly supplied, this is inferred from the presence of a non-emptyuserinfo_url: if auserinfo_urlis provided,userinfo_requireddefaults toTRUE, otherwise it defaults toFALSE. This avoids unexpected validation errors whenuserinfo_urlis omitted (since it is optional).- userinfo_id_selector
A function that extracts the user ID from the userinfo response. Should take a single argument (the userinfo list) and return the user ID as a string.
This is used for helpers that need a provider-specific user identifier, such as audit fields and UserInfo-to-ID-token subject matching. If you configure a selector other than
function(x) x$sub, that selector also defines which UserInfo value is compared against the validated ID tokensub. Helper constructors likeoauth_provider()andoauth_provider_oidc()provide a default selector that extracts thesubfield.- userinfo_id_token_match
Whether to fail closed if UserInfo cannot be bound to a validated ID token subject. Whenever both UserInfo and a validated ID token are available, shinyOAuth compares the validated ID token
subto the value returned byuserinfo_id_selector(userinfo). Setting this field toTRUEadditionally requires a validated ID token baseline whenever UserInfo is fetched. This requiresuserinfo_required, a configureduserinfo_id_selector, plus eitherid_token_validationoruse_nonceto beTRUE.For
oauth_provider(), when not explicitly supplied, this is inferred asTRUEwhenuserinfo_requiredisTRUEand eitherid_token_validationoruse_nonceisTRUE; otherwise it defaults toFALSE.- userinfo_signed_jwt_required
Whether to require that the userinfo endpoint returns a signed JWT (
Content-Type: application/jwt) whose signature can be verified against the provider's JWKS. This is an advanced hardening option. WhenTRUE:If the userinfo response is not
application/jwt, authentication fails.If the JWT uses
alg=noneor an algorithm not in the asymmetric subset ofallowed_algs(RS*,ES*, orEdDSA), authentication fails.HS*algorithms are not accepted for UserInfo JWTs on this surface even if they appear inallowed_algs.If signature verification fails (JWKS fetch error, no compatible keys, or invalid signature), authentication fails.
This prevents unsigned or weakly signed userinfo payloads from being treated as trusted identity data. Requires
userinfo_required = TRUEand a validissuer(for JWKS). Defaults toFALSE.Note:
oauth_provider_oidc_discover()does not auto-enable this flag. Discovery'suserinfo_signing_alg_values_supportedindicates provider capability, not that every client actually receives signed JWTs. Passuserinfo_signed_jwt_required = TRUEexplicitly if you need this behavior.- id_token_required
Whether to require an ID token to be returned during token exchange. If no ID token is returned, the token exchange will fail. This only makes sense for OpenID Connect providers and may require the client's scope to include
openid.Note: At the S7 class level, this defaults to FALSE so that pure OAuth 2.0 providers can be configured without OIDC. Helper constructors like
oauth_provider()andoauth_provider_oidc()will enable this when an issuer is supplied or OIDC is explicitly requested.- id_token_validation
Whether to perform ID token validation after token exchange. This requires the provider to be a valid OpenID Connect provider with a configured
issuerand the token response to include an ID token (may require setting the client's scope to includeopenid).Note: At the S7 class level, this defaults to FALSE. Helper constructors like
oauth_provider()andoauth_provider_oidc()turn this on when an issuer is provided or when OIDC is used.- id_token_at_hash_required
Whether to require the
at_hash(Access Token hash) claim in the ID token. WhenTRUE, login fails if the ID token does not contain anat_hashclaim or if the claim does not match the access token. WhenFALSE(default),at_hashis validated only when present. Requiresid_token_validation = TRUE.- introspection_url
Token introspection endpoint URL (optional; RFC 7662)
- revocation_url
Token revocation endpoint URL (optional; RFC 7009)
- extra_auth_params
Extra parameters for authorization URL
- extra_token_params
Extra parameters for token exchange
- extra_token_headers
Extra headers for back-channel token-style requests (named character vector). shinyOAuth applies these headers to token exchange, refresh, introspection, revocation, and PAR requests. Use this only for headers you intentionally want on that full set of authorization-server calls.
- jwks_uri
Optional explicit URL of the provider's JWK Set document. Use this when a generic OAuth 2.0 or JARM deployment publishes signing keys outside OIDC discovery, or when you intentionally want to override runtime metadata-based JWKS resolution.
In most cases, a TTL between 15 minutes and 2 hours is reasonable. Shorter TTLs pick up new keys faster but do more network work; longer TTLs reduce traffic but may take longer to notice key rotation. If a new
kidappears, shinyOAuth will also do a one-time refresh automatically.- jwks_cache
Cache used for the provider's signing keys (JWKS). If not provided, shinyOAuth creates an in-memory cache for 1 hour with
cachem::cache_mem(max_age = 3600). You can also use another cachem-compatible backend, including a shared cache created withcustom_cache().- jwks_pins
Optional character vector of RFC 7638 JWK thumbprints (base64url) to pin against. If non-empty, fetched JWKS must contain keys whose thumbprints match these values depending on
jwks_pin_mode. This is an advanced hardening option that lets you pre-authorize expected keys.- jwks_pin_mode
Pinning policy when
jwks_pinsis provided. Either "any" (default; at least one key in JWKS must match) or "all" (every RSA/EC/OKP public key in JWKS must match one of the configured pins)- jwks_host_issuer_match
When TRUE, enforce that the discovery
jwks_urihost matches the issuer host exactly. Defaults to FALSE at the class level, but helper constructors for OIDC (e.g.,oauth_provider_oidc()andoauth_provider_oidc_discover()) enable this by default for safer config. The generic helperoauth_provider()will also automatically set this to TRUE when anissueris provided and eitherid_token_validationorid_token_requiredis TRUE (OIDC-like configuration). Set explicitly to FALSE to opt out. For providers that legitimately publish JWKS on a different host (for example Google), prefer settingjwks_host_allow_onlyto the exact hostname rather than disabling this check.- jwks_host_allow_only
Optional explicit hostname that the jwks_uri must match. When provided, jwks_uri host must equal this value (exact match). You can pass either just the host (e.g., "www.googleapis.com") or a full URL; only the host component will be used. If you need to include a port or an IPv6 literal, pass a full URL (e.g.,
https://[::1]:8443) - the port is ignored and only the hostname part is used for matching. Takes precedence overjwks_host_issuer_match.- allowed_algs
Optional vector of allowed JWT algorithms for ID tokens. Use to restrict acceptable
algvalues on a per-provider basis. Supported asymmetric algorithms includeRS256,RS384,RS512,ES256,ES384,ES512, andEdDSAfor OKP-backed signatures. When ID tokenat_hashvalidation is in play, Ed25519 is supported. Ed448at_hashcannot be validated with the current crypto bindings, so shinyOAuth skips that optional check unlessid_token_at_hash_required = TRUE, in which case Ed448 ID tokens fail fast. Symmetric HMAC algorithmsHS256,HS384,HS512are also supported but require that you supply aclient_secretand explicitly enable HMAC verification via the optionoptions(shinyOAuth.allow_hs = TRUE). Defaults toc("RS256","RS384","RS512","ES256","ES384","ES512","EdDSA"), which intentionally excludes HS*. Only includeHS*if you are certain theclient_secretis stored strictly server-side and is never shipped to, or derivable by, the browser or other untrusted environments.- allowed_token_types
Character vector of acceptable OAuth token types returned by the token endpoint (case-insensitive). Successful token responses must always include
token_type; whenallowed_token_typesis non-empty, its value must also be one of the allowed values or the flow fails fast with ashinyOAuth_token_error. Theoauth_provider()helper defaults toc("Bearer"). When the OAuthClient is configured withdpop_private_key, shinyOAuth also acceptstoken_type = "DPoP"and uses DPoP proofs on supported token and downstream requests. Other non-Bearer token types (for exampleMAC) still fail fast rather than being misused. Setallowed_token_types = character()explicitly only to disable the value allowlist while still requiringtoken_typeitself.- par_url
Optional Pushed Authorization Request (PAR) URL (RFC 9126). When set, shinyOAuth first sends the authorization request from server to provider and then redirects the browser with the returned
request_urihandle instead of the full request payload. Most users only need this when their provider specifically supports or requires PAR.- par_required
Logical. Whether the provider requires authorization requests to be sent via PAR. When
TRUE,par_urlmust also be configured.- signed_request_object_required
Logical. Whether the provider requires signed Request Objects for authorization requests. When
TRUE, clients should userequest_object_mode = "request"orrequest_object_mode = "request_uri".- request_parameter_supported
Logical or
NA. Whether discovery metadata explicitly advertises support for the authorization-requestrequestparameter.NAmeans the provider did not say. Discovery-derived providers apply the OpenID Connect default (FALSE) when this metadata is omitted.- request_uri_parameter_supported
Logical or
NA. Whether discovery metadata explicitly advertises support for the authorization-requestrequest_uriparameter for caller-managed request URIs.NAmeans the provider did not say. Discovery-derived providers apply the OpenID Connect default (TRUE) when this metadata is omitted. PAR-issuedrequest_urihandles remain valid even when this metadata isFALSE.- request_uri_registration_required
Logical or
NA. Whether discovery metadata says caller-managedrequest_urivalues must be pre-registered.NAmeans the provider did not say. Discovery-derived providers apply the OpenID Connect default (FALSE) when this metadata is omitted. shinyOAuth can publish caller-managedrequest_urivalues throughoauth_module_server(). When this isTRUE, make sure the provider has a matching public request URI or wildcard prefix registered for the client. shinyOAuth stores this metadata for caller awareness, but it cannot verify provider-side registration state automatically.- request_object_signing_alg_values_supported
Optional vector of JWS algorithms that the provider advertises for signed Request Objects (RFC 9101). This is mainly used for early validation when an OAuthClient sends
request_object_mode = "request"orrequest_object_mode = "request_uri".- request_object_encryption_alg_values_supported
Optional vector of JWE key-management algorithms that the provider advertises for encrypted Request Objects. This metadata is used for early validation when an OAuthClient enables Request Object encryption.
- request_object_encryption_enc_values_supported
Optional vector of JWE content-encryption algorithms that the provider advertises for encrypted Request Objects. This metadata is used for early validation when an OAuthClient enables Request Object encryption.
- request_object_encryption_jwk
Optional explicit recipient public key used to encrypt Request Objects when discovery-backed JWKS selection is not available or when you need to pin one specific encryption key. Accepts an OpenSSL public key, a PEM public-key string, a parsed JWK object, or a JWK JSON string.
Character scalar controlling which browser-visible outer parameters shinyOAuth keeps when the actual authorization request is carried by JAR or PAR. Use
"compat"(default) to keep the current OIDC-compatible shape with outerclient_id,response_type, andscopewhen an issuer is configured. Use"minimal"for plain OAuth browser redirects and for PAR deployments whose authorization endpoint accepts onlyclient_idplus the provider-issuedrequest_urihandle. OpenID Connect by-valuerequestand caller-managedrequest_uritransports reject"minimal"because OIDC still requires outerresponse_typeand an outerscopecontainingopenid.Logical. Whether the provider advertises RFC 9207 support for returning an
issparameter on the authorization response. WhenTRUE, theoauth_client()helper can auto-enable callback issuer enforcement when the caller leavesenforce_callback_issuerunset and the provider also has a configuredissuer.- response_modes_supported
Optional character vector of OAuth/OIDC
response_modevalues advertised by the provider. Discovery-backed providers use the discovery metadata value, defaulting toc("query", "fragment")when omitted per OIDC Discovery/RFC 8414. Generic providers may leave this empty when capabilities are not known. Provider metadata may include response modes that shinyOAuth does not implement; clients still fail fast if they request one of those unsupported modes.- jarm_signing_alg_values_supported
Optional vector of JWS algorithms that the provider advertises for signed JWT Secured Authorization Responses (JARM).
- jarm_encryption_alg_values_supported
Optional vector of JWE key-management algorithms that the provider advertises for encrypted JARM responses.
- jarm_encryption_enc_values_supported
Optional vector of JWE content-encryption algorithms that the provider advertises for encrypted JARM responses.
- jarm_tolerate_duplicate_top_level_iss
Logical. Whether shinyOAuth should tolerate repeated identical top-level
issmembers in signed JARM payloads for this provider. This is an interoperability escape hatch for providers that emit duplicate identical top-levelissclaims. WhenTRUE, shinyOAuth collapses repeated identical top-levelissmembers before duplicate-member rejection. Conflicting duplicates and nested duplicateissmembers still fail closed. Defaults toFALSE.- token_endpoint_auth_signing_alg_values_supported
Optional vector of JWS algorithms that the provider advertises for JWT-based client authentication (
client_secret_jwt/private_key_jwt) at the token endpoint. This metadata is used for early validation ofOAuthClient@client_assertion_algand inferred JWT client-assertion defaults.- dpop_signing_alg_values_supported
Optional vector of JWS algorithms that the provider advertises for DPoP proof JWTs (RFC 9449). This metadata is used for early validation of
OAuthClient@dpop_signing_algand inferred outbound DPoP signing defaults.- mtls_endpoint_aliases
Optional named list of RFC 8705 mTLS endpoint aliases. Names should follow the metadata keys such as
token_endpoint,userinfo_endpoint,introspection_endpoint,revocation_endpoint,par_endpoint, orpushed_authorization_request_endpoint, and values must be absolute URLs. This is an advanced setting used when a provider publishes separate mTLS-specific endpoints.- mtls_client_certificate_bound_access_tokens
Logical. Whether the authorization server advertises RFC 8705 capability to issue certificate-bound access tokens. This describes server capability; the client still has to opt into mTLS separately. When
TRUE, token responses may include acnfclaim with anx5t#S256thumbprint that downstream requests must match with the same certificate.- leeway
Clock skew leeway (seconds) applied to ID token
exp/iat/nbfchecks and state payloadissued_atfuture check. Default 30. Can be globally overridden via optionshinyOAuth.leeway.
Examples
# Configure generic OAuth 2.0 provider (no OIDC)
generic_provider <- oauth_provider(
name = "example",
auth_url = "https://example.com/oauth/authorize",
token_url = "https://example.com/oauth/token",
# Optional URL for fetching user info:
userinfo_url = "https://example.com/oauth/userinfo"
)
# Configure generic OIDC provider manually
# (This defaults to using nonce & ID token validation)
generic_oidc_provider <- oauth_provider_oidc(
name = "My OIDC",
base_url = "https://my-issuer.example.com"
)
#> Warning: [shinyOAuth] - Configure allowed hosts for production
#> ! No host allowlist configured via `options(shinyOAuth.allowed_hosts =
#> c(".example.com", "api.example.com"))`.
#> ℹ Restricting hosts hardens redirect and API endpoint validation.
#> ℹ See `?is_ok_host` for policy details and review the 'authentication-flow'
#> vignette
#> This warning is displayed once per session.
# Configure a OIDC provider via OIDC discovery
# (requires network access)
if (interactive()) {
# Using Auth0 sample issuer as an example
oidc_discovery_provider <- oauth_provider_oidc_discover(
issuer = "https://samples.auth0.com"
)
}
# GitHub preconfigured provider
github_provider <- oauth_provider_github()
# Google preconfigured provider
google_provider <- oauth_provider_google()
# Microsoft preconfigured provider
# See `?oauth_provider_microsoft` for example using a custom tenant ID
# Spotify preconfigured provider
spotify_provider <- oauth_provider_spotify()
# Slack via OIDC discovery
# (requires network access)
if (interactive()) {
slack_provider <- oauth_provider_slack()
}
# Keycloak
# (requires configured Keycloak realm; example below is therefore not run)
if (interactive()) {
oauth_provider_keycloak(base_url = "http://localhost:8080", realm = "myrealm")
}
# Auth0
# (requires configured Auth0 domain; example below is therefore not run)
if (interactive()) {
oauth_provider_auth0(domain = "your-tenant.auth0.com")
}
# Okta
# (requires configured Okta domain; example below is therefore not run)
if (interactive()) {
oauth_provider_okta(domain = "dev-123456.okta.com")
}