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

# Complete the OAuth Flow with Discord and Roblox

> Connect a Discord and Roblox account to CA Colombia using OAuth 2.0. Follow these steps to initiate the flow, handle the callback, and establish a session.

CA Colombia uses OAuth 2.0 to verify your identity through two external providers: **Discord** and **Roblox**. Connecting both accounts ties your Discord identity to your Roblox player, which is required before you can create characters or access any protected resources. This guide walks you through the full flow — from kicking off the authorization request to having an active session ready to use.

## Overview

There are two providers: `discord` and `roblox`. You must complete the Discord OAuth flow first — it creates your CA Colombia account and issues your session cookies. Once a Discord session exists, you can link your Roblox account by running the same flow with `provider=roblox`.

Both flows use the same two endpoints:

| Step     | Method | Endpoint              |
| -------- | ------ | --------------------- |
| Initiate | `POST` | `/v1/oauth/:provider` |
| Callback | `GET`  | `/v1/oauth/:provider` |

## Step-by-Step

<Steps>
  <Step title="Initiate the OAuth flow">
    Send a `POST` request to `/v1/oauth/:provider` with your `redirectUrl`. The server generates a unique `state` token, caches it, and returns a `targetUrl` — the provider's authorization page — alongside the `state` value.

    ```javascript theme={null}
    const res = await fetch('https://api.cacolombia.com/v1/oauth/discord', {
      method: 'POST',
      credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ redirectUrl: 'https://yourapp.com/auth/callback' })
    });
    const { targetUrl, state } = await res.json();
    window.location.href = targetUrl;
    ```

    **Request body**

    | Field         | Type   | Required | Description                                                |
    | ------------- | ------ | -------- | ---------------------------------------------------------- |
    | `redirectUrl` | string | ✓        | The URL the provider redirects back to after authorization |

    **Response body**

    | Field       | Type   | Description                                               |
    | ----------- | ------ | --------------------------------------------------------- |
    | `targetUrl` | string | The full authorization URL to send the user to            |
    | `state`     | string | A unique token that identifies this authorization attempt |

    <Note>
      `redirectUrl` must belong to a domain that is registered with CA Colombia. Passing an unregistered domain returns `403 Forbidden` with `"Unwhitelisted redirectUrl"`. Contact the CA Colombia team to register your domain.
    </Note>
  </Step>

  <Step title="Redirect the user to the provider">
    Send the user to the `targetUrl` you received in the previous step. This is the Discord (or Roblox) authorization page where the user grants permission. You do not need to do anything else at this point — the provider handles the interaction entirely.
  </Step>

  <Step title="Handle the callback">
    After the user authorizes (or denies) access, the provider redirects them back to your `redirectUrl` with two query parameters appended: `state` and `code`. The CA Colombia server then processes these at `GET /v1/oauth/:provider`.

    ```text theme={null}
    GET /v1/oauth/discord?state=<state>&code=<code>
    ```

    The server validates the `state` against the cached value from Step 1, exchanges the `code` for provider tokens, and looks up or creates the user's CA Colombia account. If the user already has valid session cookies, those tokens are refreshed rather than replaced.

    If anything goes wrong (invalid state, expired session, failed token exchange), the server redirects to the CA Colombia root domain rather than returning an error response. Your application should detect an absent or failed `state` parameter on the redirect destination and prompt the user to retry.
  </Step>

  <Step title="Session is active">
    On success, the server sets two `HttpOnly` session cookies and redirects the browser to your `redirectUrl`:

    | Cookie        | Lifetime | Purpose                                                 |
    | ------------- | -------- | ------------------------------------------------------- |
    | Access token  | 24 hours | Authenticates individual API requests                   |
    | Refresh token | 8 days   | Obtains a new access token when the current one expires |

    Your `redirectUrl` also receives the `state` value as a query parameter so you can confirm which authorization attempt completed. From this point on, all requests that include these cookies are authenticated.
  </Step>
</Steps>

## Linking a Roblox Account

Once your Discord session is established, run the same flow with `provider=roblox`. The server detects your existing session and attaches the Roblox identity to your account rather than creating a new one.

```javascript theme={null}
const res = await fetch('https://api.cacolombia.com/v1/oauth/roblox', {
  method: 'POST',
  credentials: 'include',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ redirectUrl: 'https://yourapp.com/auth/callback' })
});
const { targetUrl } = await res.json();
window.location.href = targetUrl;
```

<Note>
  Attempting the Roblox flow without an active Discord session returns an error. Always complete the Discord flow first.
</Note>

## Error Reference

| Status | Error                       | Cause                                    |
| ------ | --------------------------- | ---------------------------------------- |
| `400`  | `Invalid request params`    | `:provider` is not `discord` or `roblox` |
| `400`  | `Invalid form of body`      | Request body is missing or malformed     |
| `403`  | `Unwhitelisted redirectUrl` | `redirectUrl` is not a registered domain |

<Warning>
  Session cookies grant full access to the authenticated account. Never expose them to third-party scripts, log them, or transmit them over unencrypted connections. Always use `credentials: 'include'` (not `'omit'`) when making API requests from a browser so the cookies are sent automatically.
</Warning>
