All the major OAuth providers. One profile API.Explore the quickstart
Documentation navigation

Redirect and callback protection

Exact callbacks and private browser-bound backend sessions protect parameter-free returns.

On this page

Register an exact callback

AnyOAuth redirects only to URLs on your project’s exact allowlist. HTTPS is required except for HTTP loopback during development. Credentials, queries, fragments, wildcards and ambiguous URL syntax are not callback registration features.

The API rechecks the allowlist before success and denial/error redirects. Removing a callback while sign-in is in progress prevents that transaction from returning to it.

Bind clean callbacks to the initiating browser

In the recommended flow, create a private random session key on your backend and register it with createLoginSession. Save it in a ten-minute server session selected by a Secure HttpOnly SameSite=Lax browser cookie. The launch URL uses a separate opaque ID; it does not disclose the private result key.

AnyOAuth returns to your registered callback without query parameters or a fragment. Require the saved browser cookie and use its original private key to call loginResult server-to-server. Reject query-bearing callbacks. Terminal results are retrieved once, with client credentials and exact callback binding. Only succeeded results with a valid profile can establish an application session.

Use one active pending login per browser. A callback must never select a transaction by guessing a key or searching all users’ pending records. Pending results are not proof of authentication. AnyOAuth still verifies provider state, nonce, PKCE and its own initiating browser cookie before completing the session.

Legacy flow: bind state to the initiating session

Create an unpredictable transaction and save it with the exact registered callback in the initiating browser’s server session or appropriate protected app storage.

Create transaction
import { AnyOAuth } from "@anyoauth/node";

const client = new AnyOAuth({
clientId: process.env.ANYOAUTH_CLIENT_ID ?? "YOUR_CLIENT_ID",
clientSecret: process.env.ANYOAUTH_CLIENT_SECRET ?? "YOUR_CLIENT_SECRET",
baseUrl: process.env.ANYOAUTH_API_ORIGIN ?? "https://api.anyoauth.com",
});

const transaction = await client.createTransaction();

@anyoauth/node on GitHubConfidential backend SDK

Validate the returned state and expiry before using a code. Consume the saved transaction atomically, even on denial; the helper does not provide persistent session storage.

Legacy flow: keep the PKCE verifier

The S256 challenge is sent during authorization; the original verifier is sent only to the code-exchange endpoint from the confidential backend. A mismatched verifier cannot redeem the grant. Do not place the verifier or secret in a redirect URL.

Pkce challenge
import { AnyOAuth } from "@anyoauth/node";

const client = new AnyOAuth({
clientId: process.env.ANYOAUTH_CLIENT_ID ?? "YOUR_CLIENT_ID",
clientSecret: process.env.ANYOAUTH_CLIENT_SECRET ?? "YOUR_CLIENT_SECRET",
baseUrl: process.env.ANYOAUTH_API_ORIGIN ?? "https://api.anyoauth.com",
});

const challenge = await client.pkceChallenge({
codeVerifier: process.env.ANYOAUTH_CODE_VERIFIER ?? "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
});

@anyoauth/node on GitHubConfidential backend SDK

Legacy flow: reject ambiguous callbacks

The API and SDK helpers reject duplicate state/code/error parameters and simultaneous code/error values. SDK callbacks must match the saved redirect rather than a callback destination supplied by the visitor.

Protect the post-login return page

A destination such as /billing is separate from the OAuth callback. Save an allowlisted internal destination in your application session. Reject absolute URLs and protocol-relative paths such as //attacker.example; never blindly redirect to a raw returnTo query parameter. The AnyOAuth dashboard uses a fixed configured return origin.