← All @molecule/* packages · App templates
@molecule/api-oauth-clientCore interface · oauth-client · API (Node) · v1.0.1 · Apache-2.0
OAuth 2.0 client core interface for molecule.dev — consume external OAuth APIs with authorization, token exchange, refresh, and revocation
npm install @molecule/api-oauth-client@molecule/api-oauth-client is the oauth-client core interface on the API (Node) side: the API your app calls, with no vendor inside.
Choose the implementation by bonding one of its 1 provider: @molecule/api-oauth-client-generic.
import { setProvider, getAuthorizationUrl, getToken } from '@molecule/api-oauth-client'
import { provider as genericOAuth } from '@molecule/api-oauth-client-generic'
setProvider(genericOAuth)
const config = {
id: 'github',
clientId: 'abc123',
clientSecret: 'secret',
authorizationUrl: 'https://github.com/login/oauth/authorize',
tokenUrl: 'https://github.com/login/oauth/access_token',
redirectUri: 'https://myapp.com/callback',
scopes: ['user', 'repo'],
}
const authUrl = getAuthorizationUrl(config, { state: 'csrf-token' })
const tokens = await getToken(config, 'authorization-code')Providers (1): @molecule/api-oauth-client-generic
Works with: @molecule/api-bond, @molecule/api-i18n
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Provider-agnostic OAuth 2.0 client interface for molecule.dev.
Defines the OAuthClientProvider interface for consuming external OAuth 2.0
APIs — building authorization URLs, exchanging codes for tokens, refreshing
tokens, making authenticated requests, and revoking access. Bond packages
(generic OAuth2, etc.) implement this interface. Application code uses the
convenience functions (getAuthorizationUrl, getToken, refreshToken,
request, revokeToken) which delegate to the bonded provider.
import { setProvider, getAuthorizationUrl, getToken } from '@molecule/api-oauth-client'
import { provider as genericOAuth } from '@molecule/api-oauth-client-generic'
setProvider(genericOAuth)
const config = {
id: 'github',
clientId: 'abc123',
clientSecret: 'secret',
authorizationUrl: 'https://github.com/login/oauth/authorize',
tokenUrl: 'https://github.com/login/oauth/access_token',
redirectUri: 'https://myapp.com/callback',
scopes: ['user', 'repo'],
}
const authUrl = getAuthorizationUrl(config, { state: 'csrf-token' })
const tokens = await getToken(config, 'authorization-code')
core
npm install @molecule/api-oauth-client @molecule/api-bond @molecule/api-i18n
AuthorizationUrlOptionsOptions for the authorization URL.
interface AuthorizationUrlOptions {
/** A CSRF-prevention state value. */
state?: string
/** PKCE code challenge. */
codeChallenge?: string
/** PKCE code challenge method (`'S256'` or `'plain'`). */
codeChallengeMethod?: 'S256' | 'plain'
/** Additional query parameters to include. */
additionalParams?: Record<string, string>
}
OAuthClientConfigConfiguration options for oauth-client providers.
interface OAuthClientConfig {
/** Default timeout for HTTP requests in milliseconds. */
timeout?: number
/** Custom user-agent header for requests. */
userAgent?: string
}
OAuthClientProviderOAuth client provider interface.
All OAuth client providers must implement this interface. Bond packages provide concrete implementations that handle the OAuth 2.0 flow for consuming external APIs.
interface OAuthClientProvider {
/**
* Builds the authorization URL that the user should be redirected to.
*
* @param config - The OAuth provider configuration.
* @param options - Optional authorization URL parameters.
* @returns The fully-qualified authorization URL.
*/
getAuthorizationUrl(config: OAuthConfig, options?: AuthorizationUrlOptions): string
/**
* Exchanges an authorization code for access/refresh tokens.
*
* @param config - The OAuth provider configuration.
* @param code - The authorization code received from the provider.
* @param options - Optional token exchange parameters.
* @returns The token set.
*/
getToken(config: OAuthConfig, code: string, options?: TokenExchangeOptions): Promise<OAuthTokens>
/**
* Refreshes an expired access token using a refresh token.
*
* @param config - The OAuth provider configuration.
* @param refreshToken - The refresh token.
* @returns A new token set.
*/
refreshToken(config: OAuthConfig, refreshToken: string): Promise<OAuthTokens>
/**
* Makes an authenticated HTTP request to a resource server.
*
* @param tokens - The current token set.
* @param url - The resource URL.
* @param options - Optional request parameters.
* @returns The parsed response body.
*/
request(tokens: OAuthTokens, url: string, options?: RequestOptions): Promise<unknown>
/**
* Revokes an access or refresh token.
*
* @param config - The OAuth provider configuration.
* @param token - The token to revoke.
* @returns Resolves when the token is revoked.
*/
revokeToken(config: OAuthConfig, token: string): Promise<void>
}
OAuthConfigConfiguration for an OAuth 2.0 provider (the external service).
interface OAuthConfig {
/** Unique identifier for this provider configuration. */
id: string
/** OAuth 2.0 client ID. */
clientId: string
/** OAuth 2.0 client secret. */
clientSecret: string
/** Authorization endpoint URL. */
authorizationUrl: string
/** Token endpoint URL. */
tokenUrl: string
/** Token revocation endpoint URL, if supported. */
revocationUrl?: string
/** Redirect URI registered with the provider. */
redirectUri: string
/** Requested scopes. */
scopes?: string[]
/** Scope delimiter (defaults to `' '`). */
scopeDelimiter?: string
}
OAuthTokensOAuth 2.0 access and refresh tokens.
interface OAuthTokens {
/** The access token. */
accessToken: string
/** The refresh token, if granted. */
refreshToken?: string
/** Token type (typically `'Bearer'`). */
tokenType: string
/** Access token lifetime in seconds, if provided. */
expiresIn?: number
/** Absolute expiration timestamp (ISO 8601). */
expiresAt?: string
/** Granted scopes (may differ from requested scopes). */
scope?: string
}
RequestOptionsOptions for making an authenticated request to a resource server.
interface RequestOptions {
/** HTTP method. Defaults to `'GET'`. */
method?: HttpMethod
/** Request headers. */
headers?: Record<string, string>
/** Request body (for POST/PUT/PATCH). */
body?: unknown
/** Content type. Defaults to `'application/json'`. */
contentType?: string
}
TokenExchangeOptionsOptions for the token exchange.
interface TokenExchangeOptions {
/** PKCE code verifier, required when a code challenge was used. */
codeVerifier?: string
/** Additional body parameters to include. */
additionalParams?: Record<string, string>
}
HttpMethodHTTP method for authenticated requests.
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
OAuthGrantTypeSupported OAuth 2.0 grant types.
type OAuthGrantType = 'authorization_code' | 'client_credentials' | 'refresh_token'
OAuthResponseTypeSupported OAuth 2.0 response types.
type OAuthResponseType = 'code' | 'token'
getAuthorizationUrl(config, options)Builds the authorization URL that the user should be redirected to.
function getAuthorizationUrl(config: OAuthConfig, options?: AuthorizationUrlOptions): string
config — The OAuth provider configuration.options — Optional authorization URL parameters.Returns: The fully-qualified authorization URL.
getProvider()Retrieves the bonded OAuth client provider, throwing if none is configured.
function getProvider(): OAuthClientProvider
Returns: The bonded OAuth client provider.
getToken(config, code, options)Exchanges an authorization code for access/refresh tokens.
function getToken(
config: OAuthConfig,
code: string,
options?: TokenExchangeOptions,
): Promise<OAuthTokens>
config — The OAuth provider configuration.code — The authorization code received from the provider.options — Optional token exchange parameters.Returns: The token set.
hasProvider()Checks whether an OAuth client provider is currently bonded.
function hasProvider(): boolean
Returns: true if an OAuth client provider is bonded.
refreshToken(config, token)Refreshes an expired access token using a refresh token.
function refreshToken(config: OAuthConfig, token: string): Promise<OAuthTokens>
config — The OAuth provider configuration.token — The refresh token string.Returns: A new token set.
request(tokens, url, options)Makes an authenticated HTTP request to a resource server.
function request(tokens: OAuthTokens, url: string, options?: RequestOptions): Promise<unknown>
tokens — The current token set.url — The resource URL.options — Optional request parameters.Returns: The parsed response body.
revokeToken(config, token)Revokes an access or refresh token.
function revokeToken(config: OAuthConfig, token: string): Promise<void>
config — The OAuth provider configuration.token — The token to revoke.Returns: Resolves when the token is revoked.
setProvider(provider)Registers an OAuth client provider as the active singleton. Called by bond packages during application startup.
function setProvider(provider: OAuthClientProvider): void
provider — The OAuth client provider implementation to bond.| Provider | Package |
|---|---|
| Oauth Client | @molecule/api-oauth-client-generic |
Peer dependencies:
@molecule/api-bond ^1.0.1@molecule/api-i18n ^1.0.1@molecule/api-bond@molecule/api-i18nThis package CONSUMES external OAuth APIs on a user's behalf (calendar,
repo, CRM integrations). For "Log in with X" use @molecule/api-oauth +
@molecule/api-resource-user's logInOAuth, which already implement the
login flow's security checks — don't rebuild login on this client.
OAuthConfig — especially clientSecret — is SERVER-SIDE only,
built from env/secrets (never literals in code). The browser only ever
receives the authorization URL and returns the code to your API, which
performs the exchange.state and PKCE are optional parameters but NOT optional practice: send a
per-session random state (and a codeChallenge, method 'S256') on
getAuthorizationUrl, REJECT the callback unless the returned state
matches the stored one, then pass the matching codeVerifier in
getToken's options.OAuthTokens per user server-side (encrypted at
rest). refreshToken is only present when the provider grants one (e.g.
offline scopes); track expiresAt and refresh before use or on auth
failure — access tokens are short-lived.request(tokens, url, opts) attaches the token for you but does NOT
auto-refresh — it throws on a non-2xx response; refresh-and-retry on
auth failure is the caller's loop.Integration checklist — drive the real UI (live preview, no mocks), adapt
each item to this app's actual "connect account" screens/flows, and check
every box off one by one. A box you can't check is an integration bug to
fix — not a skip. The third-party CONSENT SCREEN cannot be driven in-sandbox,
so verify the token lifecycle + API-call wiring you own (authorize →
callback → getToken → token store → refreshToken → request), stubbing
the provider bond or the token endpoint where the real grant would occur:
getToken and STORES the returned OAuthTokens
(accessToken + refreshToken) server-side keyed to the authenticated
user; the connection then shows as "connected" in the UI.request(tokens, url)
using the STORED token succeeds and its result appears in the app (bond a
stub/test provider if available, else assert request is invoked with the
stored accessToken — never a hardcoded or browser-supplied one).accessToken (force/simulate expiry
via expiresAt) is transparently refreshed with refreshToken and the
call is RETRIED — confirm exactly ONE refresh + a stored-token update, not
an auth error surfaced to the user (request does not auto-refresh; the
caller's refresh-and-retry loop must).revokeToken + delete
from the store) and the connection no longer works — a subsequent API call
fails until the account is reconnected.accessToken/refreshToken + clientSecret live
server-side only (encrypted at rest ideally) and are NEVER sent to the
browser — the client only ever receives the authorization URL and returns
the code.state (CSRF): a per-session random state sent
on getAuthorizationUrl must match on the callback, and a missing or
mismatched state is rejected BEFORE any token exchange.