> ## Documentation Index
> Fetch the complete documentation index at: https://finance.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth2 Authentication

> Overview of OAuth2 flows for the Aries API. Choose between Authorization Code (server-side) and PKCE (SPAs, mobile apps).

The Aries API uses **OAuth2 Authorization Code** flows for authentication. In plain English: your app sends the user to Aries to log in, the user approves what your app is allowed to see/do, and Aries hands your app an **access token** that you include in every API call to prove who you are and what you're allowed to do. Tokens expire on a schedule, so Aries also gives you a **refresh token** that you can swap for a fresh access token without re-prompting the user.

Pick the flow that matches the kind of app you're building (see [Choose your flow](#choose-your-flow) below).

<Note>
  **New to OAuth2?** Don't worry about reading this whole page first — head to the [Quick Start](/api-reference/quickstart) to get a working API call in a few minutes, then come back here when you need the details.
</Note>

***

## Endpoints

| Purpose                  | Endpoint                                     |
| ------------------------ | -------------------------------------------- |
| Authorization            | `https://app.aries.com/oauth2/authorize`     |
| Token exchange & refresh | `POST https://api.aries.com/v1/oauth2/token` |

***

## Before you start

If OAuth2 is new to you, this is the easiest way to think about it:

1. Your app asks the user to sign in with Aries.
2. Aries sends your app a short-lived **authorization code**.
3. Your app sends that code to the token endpoint.
4. Aries returns an **access token** and usually a **refresh token**.
5. Your app uses the access token when calling Aries APIs.

There is only **one** token endpoint: `POST /v1/oauth2/token`.

That endpoint can be used in **two different ways**:

1. **Code exchange**: trade an authorization code for tokens.
2. **Refresh**: trade a refresh token for a new access token.

For the code exchange, there are **two security styles**:

1. **Server-side / confidential client**: send `client_secret`
2. **PKCE / public client**: send `code_verifier`

So the flow is not "three different token endpoints." It is one token endpoint with a few different valid request shapes depending on what your app is doing.

***

## Key terms in plain English

| Term                 | What it means                                                    |
| -------------------- | ---------------------------------------------------------------- |
| `client_id`          | The public identifier for your app                               |
| `client_secret`      | A private password for your app. Only safe on a backend server   |
| `authorization code` | A short-lived one-time code Aries sends back after login         |
| `access_token`       | The token you send with API requests                             |
| `refresh_token`      | A token you use later to get a new access token                  |
| `redirect_uri`       | The URL Aries sends the user back to after login                 |
| `scope`              | A list of permissions your app is asking for                     |
| `state`              | A random value used to protect the login flow from tampering     |
| `code_verifier`      | A one-time secret used by PKCE instead of `client_secret`        |
| `code_challenge`     | A hashed version of the `code_verifier` sent earlier in the flow |

<Note>
  If your app has a backend server that can safely store secrets, use the Authorization Code flow with `client_secret`.
  If your app runs in the browser or on a phone, use PKCE with `code_verifier`.
</Note>

***

## Available Scopes

**What's a scope?** A scope is a label that says "this app is allowed to do *X*." When you redirect the user to log in, you pass a list of scopes you need. The consent screen shows the user exactly what you're asking for, and the access token they approve will only work for those things.

**Rule of thumb:** request the smallest set of scopes that lets your app do its job. Asking for more than you need scares users away on the consent screen and increases the blast radius if a token leaks.

| Scope                   | Description                                                                                          | Example endpoints                                                                                        |
| ----------------------- | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `user:information`      | View user profile and personal details                                                               | `PATCH /v1/users/me`<br />`GET /v1/users/me/profile`                                                     |
| `account:information`   | View account balances, positions, and transaction history                                            | `GET /v1/users/me/accounts`<br />`GET /v1/accounts/{id}/balances`<br />`GET /v1/accounts/{id}/positions` |
| `order:execution`       | Place, modify, and cancel orders                                                                     | `POST /v1/orders`<br />`PUT /v1/orders`<br />`DELETE /v1/orders`                                         |
| `order:information`     | View order history, status, and execution reports                                                    | `GET /v2/accounts/{id}/orders`                                                                           |
| `position:information`  | View current positions and holdings                                                                  | `GET /v1/accounts/{id}/positions`                                                                        |
| `market:information`    | Access live and historical market data                                                               | `GET /v1/marketdata/search`<br />`WSS /v1/market/ws`                                                     |
| `calendar:information`  | Access earnings, economic, and market schedule data                                                  | `GET /v1/calendars/economics`<br />`GET /v1/calendars/earnings`                                          |
| `options:information`   | Access options chains, Greeks, and expiration data                                                   | `GET /v1/options/stocks/top-volume`<br />`GET /v1/options/etfs/top-volume`                               |
| `analytics:information` | View analytics, ratings, and market insights                                                         | `GET /v1/analytics/ratings`<br />`GET /v1/analytics/market-breadth`                                      |
| `market:supplemental`   | Comprehensive market data: news, company profiles, financials, filings, ETF data, technical analysis | `GET /v1/news`<br />`GET /v1/company/profile`<br />`GET /v1/financials/statements`                       |

<Note>
  Specify multiple scopes as a space-separated string: `account:information order:execution market:information`
</Note>

***

## Choose your flow

There are two flows. Pick based on **whether your app can keep a secret safe**.

<CardGroup cols={2}>
  <Card title="Authorization Code Flow" icon="server" href="/api-reference/oauth2/auth-code-flow">
    **Use if:** your app has a backend server (Node, Python, Go, Ruby, PHP, etc.) that can hold a `client_secret` that the user never sees. This is the standard, most-secure flow.
  </Card>

  <Card title="PKCE Flow" icon="mobile-screen" href="/api-reference/oauth2/pkce-flow">
    **Use if:** your app runs entirely in the browser (single-page app) or on a mobile device, where any 'secret' you ship can be extracted. PKCE swaps the secret for a per-request proof your app generates on the fly.
  </Card>
</CardGroup>

***

## How it works

```mermaid theme={null}
sequenceDiagram
    participant User
    participant YourApp
    participant Aries

    User->>YourApp: 1. Clicks "Connect with Aries"
    YourApp->>Aries: 2. Redirects to /oauth2/authorize
    Aries->>User: 3. Shows login & consent screen
    User->>Aries: 4. Approves access
    Aries->>YourApp: 5. Redirects with authorization code
    YourApp->>Aries: 6. POST /oauth2/token (exchange code)
    Aries->>YourApp: 7. Returns access & refresh tokens
    YourApp->>Aries: 8. API requests with access token
```

Both flows follow this sequence. The only difference is in step **6** — how your app proves it's really yours when trading the one-time `code` for tokens:

* **Authorization Code flow** — your backend sends its `client_secret` along with the `code`.
* **PKCE flow** — your client sends a `code_verifier` (a random value it generated before step 2 and has been holding onto) that mathematically matches the `code_challenge` it sent at the start.

The end result is the same: Aries returns `access_token` (use this in API calls) and `refresh_token` (use this to get a new access token later without re-prompting the user).

***

## What you send to the token endpoint

This is the part that usually confuses people, so here it is in a simple table.

### 1. When you are exchanging a login code on a backend server

Send:

* `grant_type: code`
* `client_id`
* `client_secret`
* `code`
* `redirect_uri`

Use this when your app has a backend that can safely keep the `client_secret` private.

### 2. When you are exchanging a login code from a browser or mobile app

Send:

* `grant_type: code`
* `client_id`
* `code`
* `redirect_uri`
* `code_verifier`

Use this for PKCE. You do **not** need to send `client_secret` here.

### 3. When your access token has expired and you want a new one

Send:

* `grant_type: refresh_token`
* `client_id`
* `client_secret`
* `refresh_token`

Use this after you already have tokens and only need a fresh access token.

<Info>
  The Aries backend uses a single request model for `/v1/oauth2/token`. What changes is which fields are required for the situation you are in.
</Info>

***

## Step-by-step walkthrough

### Step 1: Register your app

Create an OAuth client in Client Center / Manage Account.

You will get:

* a `client_id`
* a `client_secret` if your app is a confidential/server-side client

You also need to register the exact `redirect_uri` values your app will use.

### Step 2: Send the user to Aries to sign in

Your app redirects the user to:

`https://app.aries.com/oauth2/authorize`

At this stage, you tell Aries:

* which app is asking (`client_id`)
* where to send the user back (`redirect_uri`)
* which permissions you want (`scope`)
* which response you want (`response_type=code`)
* a random safety value (`state`)
* for PKCE only: `code_challenge` and `code_challenge_method`

### Step 3: User signs in and approves

The user sees the Aries login and consent screen.

If they approve, Aries sends them back to your `redirect_uri` with a one-time `code`.

### Step 4: Your app exchanges the code for tokens

Your app sends that code to:

`POST https://api.aries.com/v1/oauth2/token`

This is where the flow splits:

* backend apps send `client_secret`
* browser/mobile apps send `code_verifier`

If the request is valid, Aries returns:

* `access_token`
* `refresh_token`
* `expires_in`
* `token_type`
* granted `scope`

### Step 5: Call Aries APIs

Now your app can call protected endpoints by sending:

```http theme={null}
Authorization: Bearer YOUR_ACCESS_TOKEN
```

### Step 6: Refresh when needed

When the access token expires, your app sends the `refresh_token` to the same token endpoint to get a new access token.

This means the user usually does **not** need to sign in again every time a token expires.

***

## Security Best Practices

<CardGroup cols={2}>
  <Card title="Store credentials securely" icon="lock">
    Never hardcode `client_secret` or tokens in source code. Use environment variables or a secrets manager.
  </Card>

  <Card title="Use HTTPS only" icon="shield">
    Always use HTTPS for redirect URIs and all API calls in production. Never transmit credentials over HTTP.
  </Card>

  <Card title="Validate the state parameter" icon="check">
    Always generate and verify `state` to prevent CSRF attacks. Generate a new random value per authorization request.
  </Card>

  <Card title="Rotate tokens proactively" icon="rotate">
    Refresh access tokens before they expire. Persist any newly issued `refresh_token` returned in the response.
  </Card>
</CardGroup>

***

## Rate Limits

Rate limits vary by endpoint category:

<CardGroup cols={2}>
  <Card title="Authentication" icon="shield">
    **10** requests/minute
  </Card>

  <Card title="User Management" icon="users">
    **100** requests/minute
  </Card>

  <Card title="Market Data" icon="chart-bar">
    **1,000** requests/minute
  </Card>

  <Card title="Trading" icon="chart-line">
    **50** requests/minute
  </Card>
</CardGroup>

Rate limit headers are included in every response:

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640000000
```

When you hit a rate limit (`429 Too Many Requests`), wait until `X-RateLimit-Reset` before retrying, or use exponential backoff.

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="invalid_grant — Authorization code expired or already used">
    **Causes:** The code expired (10 minutes) or was already exchanged (single-use).\
    **Solution:** Start the OAuth flow again and exchange the code immediately after receiving it.
  </Accordion>

  <Accordion title="invalid_client — Client authentication failed">
    **Causes:** Incorrect `client_id` or `client_secret`, or the client was deleted or disabled.\
    **Solution:** Verify credentials in Client Center / Manage Account. Regenerate `client_secret` if lost (it is shown only once).
  </Accordion>

  <Accordion title="invalid_scope — Requested scope is invalid">
    **Causes:** Typo in scope name (case-sensitive) or scope not enabled for your client.\
    **Solution:** Check scope names against the [Available Scopes](#available-scopes) table and client configuration.
  </Accordion>

  <Accordion title="redirect_uri_mismatch">
    **Causes:** The `redirect_uri` does not exactly match a registered URI (including protocol, path, and trailing slashes).\
    **Solution:** Register all redirect URIs in Client Center / Manage Account. Values must match character for character.
  </Accordion>

  <Accordion title="access_denied — User denied authorization">
    **Cause:** The user clicked "Deny" on the consent screen.\
    **Solution:** Show a clear message explaining why permissions are needed and offer a retry. Consider requesting fewer scopes if users frequently deny.
  </Accordion>
</AccordionGroup>

***

## Next steps

<CardGroup cols={2}>
  <Card title="Authorization Code Flow" icon="server" href="/api-reference/oauth2/auth-code-flow">
    Implement server-side OAuth2 with `client_secret`.
  </Card>

  <Card title="PKCE Flow" icon="mobile-screen" href="/api-reference/oauth2/pkce-flow">
    Implement OAuth2 for SPAs and mobile apps without `client_secret`.
  </Card>

  <Card title="OAuth2 Token API" icon="key" href="/api-reference/oauth2/token">
    Token endpoint reference and interactive testing.
  </Card>

  <Card title="Quick Start" icon="bolt" href="/api-reference/quickstart">
    Get your first API call working in minutes.
  </Card>
</CardGroup>
