Package 'tinyoauth'

Title: Minimal OAuth 2.0 Client
Description: A dependency-light OAuth 2.0 <https://www.rfc-editor.org/rfc/rfc6749> client supporting the client-credentials and authorization-code grants with token refresh. Built on 'curl' and 'jsonlite', with base R's socket server for the redirect listener, avoiding heavier HTTP stacks.
Authors: Troy Hernandez [aut, cre] (ORCID: <https://orcid.org/0009-0005-4248-604X>), cornball.ai [cph]
Maintainer: Troy Hernandez <[email protected]>
License: MIT + file LICENSE
Version: 0.1.0.1
Built: 2026-06-21 15:14:26 UTC
Source: https://github.com/cornball-ai/tinyoauth

Help Index


OAuth client for the Anthropic Claude (Claude Code) login flow

Description

A preconfigured [oauth_client] for Claude-subscription-backed access, carrying Anthropic's authorize and token endpoints plus the Claude Code scope string. The client id is Anthropic's public Claude Code identifier, not a secret.

Usage

anthropic_claude_client()

Value

A tinyoauth_client with an extra scope field.

Examples

anthropic_claude_client()

Build an authorization URL

Description

Build an authorization URL

Usage

oauth_authorize_url(client, scope = NULL, state = NULL)

Arguments

client

A [oauth_client] with an auth_url.

scope

Optional space-delimited scope string.

state

Optional opaque state for CSRF protection.

Value

The authorization URL to open in a browser.

Examples

oauth_authorize_url(
  oauth_client("id", token_url = "https://x/token",
               auth_url = "https://x/authorize"),
  scope = "user-read-email")

Authorization header value for a token

Description

Authorization header value for a token

Usage

oauth_bearer(token)

Arguments

token

A tinyoauth_token, a (legacy) httr Token2.0, or a raw access-token string.

Value

A string like "Bearer abc123" for use as an HTTP Authorization header.

Examples

## Not run: 
h <- curl::new_handle()
curl::handle_setheaders(h, Authorization = oauth_bearer(tok))

## End(Not run)

Default on-disk cache path for a client's token

Description

Default on-disk cache path for a client's token

Usage

oauth_cache_path(client)

Arguments

client

A [oauth_client].

Value

Path to the token cache file under tools::R_user_dir.


Define an OAuth 2.0 client

Description

Define an OAuth 2.0 client

Usage

oauth_client(id, secret = NULL, token_url, auth_url = NULL,
             redirect_uri = "http://127.0.0.1:1410/")

Arguments

id

Client (application) id.

secret

Client secret, or NULL for public clients.

token_url

The provider's token endpoint.

auth_url

The provider's authorization endpoint (needed for the authorization-code grant; omit for client-credentials only).

redirect_uri

Redirect URI registered with the provider. Use a loopback IP literal over http (127.0.0.1); many providers reject localhost.

Value

A tinyoauth_client object.

Examples

spotify <- oauth_client(
  id = "your_id", secret = "your_secret",
  token_url = "https://accounts.spotify.com/api/token",
  auth_url  = "https://accounts.spotify.com/authorize")

Exchange an authorization code for a token

Description

Exchange an authorization code for a token

Usage

oauth_exchange_code(client, code)

Arguments

client

A [oauth_client].

code

The authorization code from the redirect.

Value

A tinyoauth_token.


Is a token expired?

Description

Is a token expired?

Usage

oauth_expired(token, leeway = 60)

Arguments

token

A tinyoauth_token.

leeway

Seconds of slack before the hard expiry (default 60).

Value

TRUE if expired (or within leeway of it); FALSE when there is no expiry recorded.


Import an httr '.httr-oauth' cache into tinyoauth

Description

Reads a token cached by httr's oauth2.0_token() and returns a tinyoauth client and token built from it – the app credentials, endpoints, and (crucially) the refresh token. This lets a package migrating off httr reuse an existing authorization instead of forcing users to log in again.

Usage

oauth_import_httr(path = ".httr-oauth", which = 1L)

Arguments

path

Path to the httr cache (default ".httr-oauth").

which

Which cached token to import when the file holds several (1-based; default 1).

Details

The imported access token is marked expired, since httr's cached access token is usually stale: the durable credential is the refresh token. Pass the result to [oauth_refresh] or [oauth_token] to mint a fresh access token.

Value

A list with client (a [oauth_client]) and token (a tinyoauth_token).

Examples

## Not run: 
imported <- oauth_import_httr("~/project/.httr-oauth")
token <- oauth_refresh(imported$client, imported$token)

## End(Not run)

Decode a JWT payload

Description

Base64url-decodes the payload (middle) segment of a JSON Web Token and parses it as JSON. Does not verify the signature; use only on tokens you already trust (e.g. one the provider just issued you).

Usage

oauth_jwt_payload(x)

Arguments

x

A JWT string, or a tinyoauth_token (its access_token is used).

Value

The decoded payload as a named list, or NULL if x has no usable JWT.

Examples

# A toy token: header.payload.signature, payload = {"sub":"abc"}
payload <- jsonlite::base64_enc(charToRaw('{"sub":"abc"}'))
jwt <- paste("x", gsub("=", "", payload), "y", sep = ".")
oauth_jwt_payload(jwt)$sub

Refresh an access token

Description

Refresh an access token

Usage

oauth_refresh(client, token)

Arguments

client

A [oauth_client].

token

A tinyoauth_token carrying a refresh token.

Value

A refreshed tinyoauth_token. Providers that omit a new refresh token on refresh keep the existing one.

Examples

## Not run: 
tok <- oauth_refresh(spotify, tok)

## End(Not run)

Make an authenticated request

Description

Sends an HTTP request with the token as a Bearer header, retrying transient failures, and parses a JSON response. A convenience over building a curl handle by hand; for anything exotic, use [oauth_bearer] with curl directly.

Usage

oauth_request(token, url, method = "GET", query = NULL, body = NULL,
              headers = NULL, flatten = FALSE, retries = 3L)

Arguments

token

A tinyoauth_token, a (legacy) httr token, or a raw access-token string.

url

Endpoint URL.

method

HTTP method (default "GET").

query

Optional named list of query parameters.

body

Optional R object sent as a JSON body.

headers

Optional named character vector of extra headers.

flatten

Passed to jsonlite::fromJSON (default FALSE).

retries

Attempts on transport errors / HTTP 5xx (default 3).

Value

Parsed JSON, or invisibly NULL for an empty response body. Non-2xx responses raise an error carrying the status and body.

Examples

## Not run: 
oauth_request(tok, "https://api.spotify.com/v1/me")

## End(Not run)

Get a valid token, using the cache and refreshing as needed

Description

Returns a cached token if still valid; refreshes it if expired and a refresh token is available; otherwise runs the authorization-code flow. The result is written back to cache.

Usage

oauth_token(client, scope = NULL, cache = oauth_cache_path(client), ...)

Arguments

client

A [oauth_client].

scope

Optional space-delimited scope string (for first authorization).

cache

Cache file path, or NULL to disable caching. Defaults to [oauth_cache_path].

...

Passed to [oauth_token_authcode] (e.g. port, open_browser).

Value

A valid tinyoauth_token.

Examples

## Not run: 
tok <- oauth_token(spotify, scope = "user-read-email")

## End(Not run)

Get a valid Anthropic Claude token, using the cache and refreshing as needed

Description

The Claude analogue of [oauth_token]: returns a cached token if still valid, refreshes it if expired and a refresh token is available, otherwise runs the manual-paste login flow. The token is written back to cache.

Usage

oauth_token_anthropic(cache = oauth_cache_path(anthropic_claude_client()),
                      open_url = interactive(), login = TRUE)

Arguments

cache

Cache file path, or NULL to disable caching. Defaults to [oauth_cache_path] for the Claude client.

open_url

Open the authorization URL automatically (default: interactive sessions only).

login

Run the login flow when no usable cached/refreshable token exists (default TRUE). Pass FALSE to get the cached (and refreshed-if-needed) token or NULL, without ever prompting – useful inside a request path where an interactive login would be wrong.

Details

These are subscription credentials minted for Claude Code; using them is subject to Anthropic's terms for that product.

Value

A tinyoauth_token with access_token, refresh_token, and expires_at; or NULL when login is FALSE and no usable token is cached.

Examples

## Not run: 
tok <- oauth_token_anthropic()
curl::handle_setheaders(curl::new_handle(),
                        Authorization = oauth_bearer(tok),
                        "anthropic-beta" = "oauth-2025-04-20")

## End(Not run)

Run the authorization-code flow end to end

Description

Prints (and optionally opens) the authorization URL, then obtains the redirect either by catching it on a loopback listener (default) or, with manual = TRUE, by having you paste the redirected URL back. After verifying state, it exchanges the code.

Usage

oauth_token_authcode(client, scope = NULL, port = 1410L,
                     open_browser = interactive(), timeout = 120, manual = NA)

Arguments

client

A [oauth_client] with an auth_url.

scope

Optional space-delimited scope string.

port

Loopback port for the listener; must match the port in client$redirect_uri (default 1410).

open_browser

Open the URL automatically (default: interactive only).

timeout

Seconds to wait for the redirect.

manual

Skip the loopback listener and read the redirected address (or bare code) from the console instead. The default (NA) auto-detects: it switches to manual on a remote/headless session (SSH, RStudio Server, or unix with no display), where the browser runs elsewhere and the redirect can never reach a local listener (so the listener would just hang). Pass TRUE/FALSE to force it. In manual mode the browser shows a "can't reach 127.0.0.1" page after you approve – that is expected; copy its address bar and paste it.

Value

A tinyoauth_token (with a refresh token, when the provider issues one).

Examples

## Not run: 
tok <- oauth_token_authcode(spotify, scope = "user-read-email")
tok <- oauth_token_authcode(google, manual = TRUE)  # force manual paste

## End(Not run)

Fetch a token via the client-credentials grant

Description

App-only access (no user context).

Usage

oauth_token_client(client)

Arguments

client

A [oauth_client].

Value

A tinyoauth_token.

Examples

## Not run: 
tok <- oauth_token_client(spotify)

## End(Not run)

Get a valid OpenAI Codex token, using the cache and refreshing as needed

Description

The Codex analogue of [oauth_token]: returns a cached token if still valid, refreshes it if expired and a refresh token is available, otherwise runs the device-login flow. The token carries an extra account_id field (the ChatGPT account id) and is written back to cache.

Usage

oauth_token_openai_codex(cache = oauth_cache_path(openai_codex_client()),
                         open_url = interactive(), timeout = 600, login = TRUE)

Arguments

cache

Cache file path, or NULL to disable caching. Defaults to [oauth_cache_path] for the Codex client.

open_url

Open the verification URL automatically (default: interactive sessions only).

timeout

Seconds to wait for device authorization (default 600).

login

Run the device-login flow when no usable cached/refreshable token exists (default TRUE). Pass FALSE to get the cached (and refreshed-if-needed) token or NULL, without ever prompting – useful inside a request path where an interactive login would be wrong.

Value

A tinyoauth_token with access_token, refresh_token, expires_at, and account_id; or NULL when login is FALSE and no usable token is cached.

Examples

## Not run: 
tok <- oauth_token_openai_codex()
curl::handle_setheaders(curl::new_handle(),
                        Authorization = oauth_bearer(tok),
                        "chatgpt-account-id" = tok$account_id)

## End(Not run)

Extract the ChatGPT account id from a Codex token

Description

Reads the chatgpt_account_id claim that OpenAI nests under https://api.openai.com/auth in the access-token JWT.

Usage

openai_codex_account_id(token)

Arguments

token

A tinyoauth_token (or raw access-token string).

Value

The account id string, or NULL if absent.


OAuth client for the OpenAI Codex (ChatGPT) device-login flow

Description

A preconfigured [oauth_client] for ChatGPT-subscription-backed Codex access, carrying OpenAI's device-authorization endpoints alongside the standard token endpoint. The client id is OpenAI's public native-app identifier, not a secret.

Usage

openai_codex_client()

Value

A tinyoauth_client with extra device_usercode_url, device_token_url, and verification_uri fields.

Examples

openai_codex_client()