Skip to content

Set up OAuth and sign in users ​

Let users authorize your platform with Trade It, then save their tokens on your server. These JavaScript snippets fit into your existing app; use your framework's routes, sessions, and database.

Prefer to have your coding client implement this? Start with the AI Skill and example prompt.

Client sideServer side
Show Sign in with Trade It and navigate to your authorization route.Build the authorization URL and redirect to Trade It.
Show the connected state when the user returns.Handle the callback, validate state, and exchange the code.
Call your server for accounts, holdings, trade history, and modal session URLs.Store and refresh tokens per user; call Trade It with those tokens.

1. Configure your client (server side) ​

Create your organization and save its credentials. Register your server-side callback URL in Trade It, for example:

text
https://app.example.com/auth/tradeit/callback

The redirect URI must match exactly, including scheme, host, port, path, and trailing slash. Register a separate localhost URL if you need local development.

Store these values in your server environment:

dotenv
TRADE_IT_CLIENT_ID=your_client_id
TRADE_IT_CLIENT_SECRET=your_client_secret
TRADE_IT_REDIRECT_URI=https://app.example.com/auth/tradeit/callback

Load them in your server and validate that they are set when your app starts:

js
const clientId = process.env.TRADE_IT_CLIENT_ID;
const clientSecret = process.env.TRADE_IT_CLIENT_SECRET;
const redirectUri = process.env.TRADE_IT_REDIRECT_URI;

The Client Secret and user tokens must stay on your server. Do not put them in browser code or local storage.

2. Discover endpoints (server side) ​

Fetch Trade It's OAuth metadata and use the returned endpoints:

js
const response = await fetch(
  'https://tradeit.app/.well-known/oauth-authorization-server',
);
if (!response.ok) throw new Error('OAuth discovery failed');
const metadata = await response.json();
const authorizationEndpoint = metadata.authorization_endpoint;
const tokenEndpoint = metadata.token_endpoint;

Trade It supports authorization-code and refresh-token grants, PKCE with S256, and client authentication with client_secret_basic or client_secret_post. The examples below use client_secret_post.

Permissions are assigned automatically based on your client type. You do not need to request scopes in the authorization URL.

3. Add Sign in with Trade It (client side) ​

Link to an authorization route on your server:

html
<a href="/auth/tradeit">Sign in with Trade It</a>

The browser follows your server's redirect to Trade It, where the user signs in and approves access.

4. Start authorization with PKCE (server side) ​

In your /auth/tradeit handler, generate a new state and PKCE verifier for each attempt. Save them in the user's server-side session before redirecting.

Here, session is your existing server-side session and userId is the authenticated platform user. Persist session changes using your framework's session API.

js
import { randomBytes, createHash } from 'node:crypto';

const state = randomBytes(32).toString('base64url');
const codeVerifier = randomBytes(32).toString('base64url');
const codeChallenge = createHash('sha256')
  .update(codeVerifier).digest('base64url');

session.tradeItOAuth = { state, codeVerifier, userId, createdAt: Date.now() };

const authorizationUrl = new URL(authorizationEndpoint);
authorizationUrl.search = new URLSearchParams({
  response_type: 'code',
  client_id: clientId,
  redirect_uri: redirectUri,
  state,
  code_challenge: codeChallenge,
  code_challenge_method: 'S256',
}).toString();

Save the session, then return an HTTP redirect to authorizationUrl.toString() using your framework. Require the same authenticated platform user on the start route and callback; this flow links Trade It authorization to that user's platform account.

5. Validate the callback (server side) ​

Trade It redirects the browser to your registered callback with either:

text
?code=ONE_TIME_CODE&state=ORIGINAL_STATE

or an error such as ?error=access_denied&state=ORIGINAL_STATE.

In your callback handler, read the query parameters and the pending attempt from the same server-side session. callbackUrl below is the incoming request URL; userId is the current authenticated platform user.

js
const params = new URL(callbackUrl).searchParams;
const pending = session.tradeItOAuth;
delete session.tradeItOAuth;

if (!pending || params.get('state') !== pending.state ||
    pending.userId !== userId ||
    Date.now() - pending.createdAt > 10 * 60 * 1000) {
  throw new Error('Invalid or expired authorization. Start again.');
}
if (params.has('error')) {
  throw new Error('Trade It authorization was not completed.');
}
const code = params.get('code');
if (!code) throw new Error('Missing authorization code');

Persist removal of the pending attempt even on failure, so it cannot be reused. Handle these errors by showing a retry or canceled-authorization state in your client. Only continue to the token exchange after validation succeeds.

6. Exchange the code and save tokens (server side) ​

Send the code, original verifier, and client credentials to the token endpoint. Use the same redirect URI as the authorization request.

js
const response = await fetch(tokenEndpoint, {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    client_id: clientId,
    client_secret: clientSecret,
    redirect_uri: redirectUri,
    code,
    code_verifier: pending.codeVerifier,
  }),
});
if (!response.ok) throw new Error('Trade It token exchange failed');
const tokens = await response.json();

const tokenRecord = {
  userId,
  accessToken: tokens.access_token,
  refreshToken: tokens.refresh_token,
  expiresAt: Date.now() + tokens.expires_in * 1000,
};

Save tokenRecord in your database, keyed by the platform user bound to the authorization attempt. Encrypt tokens at rest and keep them out of logs. After saving, redirect the browser to your platform's connected screen. Return connection status to the client, not OAuth tokens.

Refresh expired tokens (server side) ​

Use the access token returned by OAuth until it approaches expiry. Before calling Trade It, load the current user's token record; refresh it on your server only when it is close to expiresAt:

js
const response = await fetch(tokenEndpoint, {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'refresh_token',
    client_id: clientId,
    client_secret: clientSecret,
    refresh_token: stored.refreshToken,
  }),
});
if (!response.ok) throw new Error('Trade It token refresh failed');
const tokens = await response.json();

const updatedRecord = {
  ...stored,
  accessToken: tokens.access_token,
  refreshToken: tokens.refresh_token ?? stored.refreshToken,
  expiresAt: Date.now() + tokens.expires_in * 1000,
};

Here, stored is the database record from step 6. Save updatedRecord atomically before using the new access token. Serialize refreshes per user so concurrent requests cannot overwrite rotated credentials. If the grant is expired or revoked, ask the user to sign in with Trade It again; a temporary network failure should not erase their saved credentials.

Use the connection ​

Your client calls your own authenticated server-side routes. Your server loads that user's current access token and sends Authorization: Bearer <access_token> to Trade It.

  • Connection modal: the server creates a session URL; the client opens it with the React SDK.
  • Accounts, holdings, and trade history: the server reads data; the client displays it.
  • Trading: the client collects order approval; the embedded modal or your server submits the approved order.

Troubleshooting ​

ProblemCheck
Callback rejectedThe registered redirect URI matches both requests exactly.
Invalid or expired authorizationThe session persists across redirects, the platform user is unchanged, and state matches.
Token exchange failsCorrect client credentials, unused code, matching redirect URI and PKCE verifier.
API returns 403The permissions assigned to your client type. Contact Trade It if your integration needs different access.

Before shipping, check successful sign-in, denied consent, invalid state, token refresh, and reconnection after revoked access. Confirm each platform user can access only their own saved Trade It connection.