Skip to main content
The Authorization Code flow uses a client_secret to authenticate when exchanging the authorization code for tokens. Use this flow when your application runs on a server and can securely store credentials — for example, Node.js, Python, or PHP backends.

Prerequisites

Before you implement this flow, ensure you have:
  • OAuth2 client credentialsRegister your app in Client Center to get client_id and client_secret
  • Redirect URI — Must be pre-registered in Client Center and must exactly match (protocol, host, path, trailing slashes)
  • Server-side runtime — Node.js 18+, Python 3.8+, or equivalent for your language
  • Session or secure storage — To persist state between redirect and callback, and to store tokens after exchange
The client_secret is shown only once when you create the client. Copy it immediately and store it in environment variables or a secrets manager. If lost, regenerate it in Client Center.

Step 1: Build the authorization URL and redirect

Redirect the user to the Aries authorization endpoint. They will see a login and consent screen where they can approve or deny the requested permissions. Endpoint: https://app.aries.com/oauth2/authorize Required query parameters:
ParameterDescription
response_typeMust be code
client_idYour OAuth2 client ID
redirect_uriMust exactly match a registered URI
scopeSpace-separated scopes (e.g., account:information order:execution)
stateCryptographically random string for CSRF protection — verify on callback
const crypto = require('crypto');

// Generate state and save to session for callback verification
const state = crypto.randomBytes(32).toString('hex');
req.session.oauth_state = state;

const params = new URLSearchParams({
  response_type: 'code',
  client_id: process.env.ARIES_CLIENT_ID,
  redirect_uri: process.env.ARIES_REDIRECT_URI,
  scope: 'account:information order:execution market:information',
  state: state,
});

const authUrl = `https://app.aries.com/oauth2/authorize?${params}`;
res.redirect(authUrl);
Always generate a new, cryptographically random state for each authorization request and verify it when the user returns. This prevents CSRF attacks.

Step 2: Handle the callback

After the user approves, Aries redirects to your redirect_uri with an authorization code and the state you provided. If the user denies access, you receive error parameters instead. Success callback:
https://yourapp.com/oauth/callback?code=AUTHORIZATION_CODE&state=YOUR_STATE
Error callback (user denied or error):
https://yourapp.com/oauth/callback?error=access_denied&error_description=User+denied+access&state=YOUR_STATE
ParameterDescription
codeAuthorization code — valid for 10 minutes, single-use. Exchange immediately.
stateMust match the value you sent. Verify before proceeding.
app.get('/oauth/callback', async (req, res) => {
  // Verify state to prevent CSRF
  if (req.query.state !== req.session.oauth_state) {
    return res.status(400).send('Invalid state parameter');
  }

  // Handle user denial or other errors
  if (req.query.error) {
    return res.status(400).send(`Authorization error: ${req.query.error}`);
  }

  const authCode = req.query.code;
  if (!authCode) {
    return res.status(400).send('No authorization code received');
  }

  try {
    const tokens = await exchangeCodeForToken(authCode);
    req.session.access_token = tokens.access_token;
    req.session.refresh_token = tokens.refresh_token;
    req.session.token_expires_at = Date.now() + tokens.expires_in * 1000;
    res.redirect('/dashboard');
  } catch (err) {
    res.status(500).send('Token exchange failed');
  }
});

Step 3: Exchange the code for tokens

Send the authorization code to the token endpoint to receive an access token and refresh token. The code is single-use — exchange it immediately after receiving it. Endpoint: POST https://api.aries.com/v1/oauth2/token Request body:
FieldRequiredDescription
client_idYesYour OAuth2 client ID
client_secretYesYour OAuth2 client secret
grant_typeYescode
codeYesThe authorization code from the callback
redirect_uriYesMust match the redirect URI used in Step 1
curl -X POST 'https://api.aries.com/v1/oauth2/token' \
  -H 'Content-Type: application/json' \
  -d '{
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "grant_type": "code",
    "code": "AUTHORIZATION_CODE",
    "redirect_uri": "YOUR_REDIRECT_URI"
  }'
Response:
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ...",
  "scope": "account:information order:execution market:information"
}
Store the access_token, refresh_token, and expires_in (use it to compute expiry time). Replace your stored refresh_token if a new one is returned.

Step 4: Make authenticated API requests

Include the access token in the Authorization header for every API request.
Authorization: Bearer YOUR_ACCESS_TOKEN
curl -X GET 'https://api.aries.com/v1/users/me' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

Step 5: Refresh the access token

Access tokens expire after expires_in seconds (typically 1 hour). Use the refresh token to obtain a new access token without requiring the user to log in again. Refresh proactively before expiry. Endpoint: POST https://api.aries.com/v1/oauth2/token Request body:
FieldRequiredDescription
client_idYesYour OAuth2 client ID
client_secretYesYour OAuth2 client secret
grant_typeYesrefresh_token
refresh_tokenYesThe refresh token from the initial exchange
redirect_uriYesMust match the redirect URI used in the original flow
curl -X POST 'https://api.aries.com/v1/oauth2/token' \
  -H 'Content-Type: application/json' \
  -d '{
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "grant_type": "refresh_token",
    "refresh_token": "YOUR_REFRESH_TOKEN",
    "redirect_uri": "YOUR_REDIRECT_URI"
  }'
The response format is the same as the initial token exchange. If a new refresh_token is returned, persist it — it replaces the previous one.

Complete example (Node.js)

Here is a minimal Express.js server demonstrating the full flow:
Node.js
const express = require('express');
const crypto = require('crypto');
const session = require('express-session');

const app = express();
app.use(session({ secret: 'your-session-secret', resave: false, saveUninitialized: false }));

// Step 1: Redirect to Aries
app.get('/login', (req, res) => {
  const state = crypto.randomBytes(32).toString('hex');
  req.session.oauth_state = state;

  const params = new URLSearchParams({
    response_type: 'code',
    client_id: process.env.ARIES_CLIENT_ID,
    redirect_uri: process.env.ARIES_REDIRECT_URI,
    scope: 'user:information account:information',
    state,
  });

  res.redirect(`https://app.aries.com/oauth2/authorize?${params}`);
});

// Step 2 & 3: Callback and token exchange
app.get('/oauth/callback', async (req, res) => {
  if (req.query.state !== req.session.oauth_state) {
    return res.status(400).send('Invalid state');
  }
  if (req.query.error) {
    return res.status(400).send(`Error: ${req.query.error}`);
  }

  const response = await fetch('https://api.aries.com/v1/oauth2/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      client_id: process.env.ARIES_CLIENT_ID,
      client_secret: process.env.ARIES_CLIENT_SECRET,
      grant_type: 'code',
      code: req.query.code,
      redirect_uri: process.env.ARIES_REDIRECT_URI,
    }),
  });

  if (!response.ok) {
    return res.status(500).send('Token exchange failed');
  }

  const tokens = await response.json();
  req.session.access_token = tokens.access_token;
  req.session.refresh_token = tokens.refresh_token;

  res.redirect('/dashboard');
});

// Step 4: Use the token
app.get('/dashboard', async (req, res) => {
  if (!req.session.access_token) {
    return res.redirect('/login');
  }

  const profile = await fetch('https://api.aries.com/v1/users/me', {
    headers: { 'Authorization': `Bearer ${req.session.access_token}` },
  }).then(r => r.json());

  res.json(profile);
});

Next steps