> ## Documentation Index
> Fetch the complete documentation index at: https://connect-oauth.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth Integration Guide

> Integrate your application with MyRepChat (MRC) using OAuth 2.1 (Authorization Code + PKCE).

MRC Connect uses **OAuth 2.1 Authorization Code flow with PKCE** to let your application send and manage compliance-grade texting through **MyRepChat** on behalf of an advisor. This guide assumes FMG has provisioned your application.

<Info>
  MRC and FMG are **separate integrations**. This guide covers **MRC** (`mrc.*` scopes) with its own Client ID/Secret. For FMG contacts/content, see the **FMG APIs → OAuth** guide. If you integrate both, you run this flow **once per product** — two client credentials, two consents, two tokens.
</Info>

<Note>
  The MRC APIs are not yet available. The OAuth integration below is ready to use; API endpoints, scopes, and the API base URL will be published when the MRC APIs are released.
</Note>

## What FMG provides

FMG provisions your MRC application **per environment — sandbox first, then production**. Build and test against sandbox, then repeat with the production values.

| Item              | Sandbox                                                        | Production                                      |
| ----------------- | -------------------------------------------------------------- | ----------------------------------------------- |
| **Client ID**     | Issued by FMG (sandbox)                                        | Issued by FMG (production)                      |
| **Client Secret** | Issued by FMG — server-side only                               | Issued by FMG — server-side only                |
| **Authorize URL** | `https://connect.myrepchat.com/oauth/authorize`                | `https://connect.myrepchat.com/oauth/authorize` |
| **Token URL**     | `https://oauth.fmgsuite.com/v1/oauth2/token`                   | `https://oauth.fmgsuite.com/v1/oauth2/token`    |
| **API Base URL**  | Provided at onboarding                                         | Provided at onboarding                          |
| **Scopes**        | The `mrc.*` scopes granted to your app (see [Scopes](#scopes)) | Same                                            |

<Warning>
  The OAuth endpoints (`oauth.fmgsuite.com`) are shared across environments, but the **Client ID and Secret differ between sandbox and production** — use each set only with the environment it was issued for.
</Warning>

## What you provide

You give FMG one thing up front:

| Item                | Description                                                                                                                                                                                                                 |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Redirect URI(s)** | The exact callback URL(s) in your app where FMG returns the authorization `code`. Provide one per environment (e.g. `https://app.example.com/callback` for production, `https://staging.example.com/callback` for sandbox). |

FMG registers these in its OAuth service (**Stytch**) against your MRC Client ID. Only registered URIs are accepted at authorization time.

### Why the redirect URI matters

The redirect URI is the most security-critical value you register, because it is **where the authorization `code` is delivered**:

* After the advisor approves consent, the authorization server sends the browser to `redirect_uri?code=...`. Whoever controls that URL receives the code and can exchange it for tokens.
* So the authorization server treats your registered URIs as a strict **allowlist**: the `redirect_uri` in the authorize request must **match a registered URI exactly** — scheme, host, port, and path. A mismatch is rejected before any code is issued.
* This closes **authorization-code interception / open-redirect** attacks — an attacker can't substitute their own callback to capture the code, because an unregistered URI never matches.
* It must be **HTTPS** and a URL your server controls (no wildcards, no fragments). Register **every** environment's callback, since sandbox and production use different values.

PKCE (Step 1) protects the code in transit; exact redirect-URI matching ensures the code is only ever *sent* to you. Both are required.

## Flow at a glance

<Steps>
  <Step title="Generate PKCE + state">
    Server-side, create a `code_verifier`, its `code_challenge` (S256), and a random `state`.
  </Step>

  <Step title="Redirect to authorize">
    Send the advisor's browser to the Authorize URL with your request parameters.
  </Step>

  <Step title="Handle the callback">
    FMG redirects back with `code` and `state`. Validate `state`.
  </Step>

  <Step title="Exchange code for tokens">
    Server-side `POST` to the Token URL with the `code`, `code_verifier`, and `client_secret`.
  </Step>

  <Step title="Call MRC APIs">
    Use the `access_token` as a Bearer token. Refresh it when it expires.
  </Step>
</Steps>

***

## Step 1 — Generate PKCE parameters

Generate these on your **server** and store `code_verifier` + `state` in the user's server-side session:

```text theme={null}
code_verifier  = base64url(random(32 bytes))   // 43-char string
code_challenge = base64url(SHA256(code_verifier))
state          = base64url(random(16 bytes))
```

## Step 2 — Redirect to authorization

Redirect the advisor's browser to the Authorize URL:

```text theme={null}
GET https://connect.myrepchat.com/oauth/authorize
  &response_type=code
  &client_id={CLIENT_ID}
  &redirect_uri={REDIRECT_URI}
  &code_challenge={code_challenge}
  &code_challenge_method=S256
  &state={state}
  &scope={SCOPES}
```

| Parameter               | Required | Value                                          |
| ----------------------- | -------- | ---------------------------------------------- |
| `response_type`         | Yes      | `code`                                         |
| `client_id`             | Yes      | Your MRC Client ID                             |
| `redirect_uri`          | Yes      | Must exactly match a registered URI            |
| `code_challenge`        | Yes      | S256 challenge from Step 1                     |
| `code_challenge_method` | Yes      | `S256`                                         |
| `state`                 | Yes      | Random CSRF value from Step 1                  |
| `scope`                 | Yes      | Space-separated `mrc.*` scopes assigned by FMG |

The advisor authenticates and approves a consent screen listing your requested permissions.

## Step 3 — Handle the callback

FMG redirects to your `redirect_uri`:

```text theme={null}
GET {REDIRECT_URI}?code={authorization_code}&state={state}
```

In your handler:

1. Compare `state` against the session value — abort on mismatch (CSRF).
2. Retrieve the `code_verifier` from the session.
3. Clear both from the session — they are single-use.

## Step 4 — Exchange the code for tokens

Server-side `POST` to the Token URL. Authenticate with your `client_secret`:

```bash theme={null}
curl -X POST https://oauth.fmgsuite.com/v1/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=authorization_code \
  -d code={authorization_code} \
  -d client_id={CLIENT_ID} \
  -d client_secret={CLIENT_SECRET} \
  -d code_verifier={code_verifier} \
  -d redirect_uri={REDIRECT_URI}
```

**Response:**

```json theme={null}
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "v2.abc...",
  "scope": "openid offline_access"
}
```

The `refresh_token` is only returned when the `offline_access` scope is granted. Store both tokens securely (server-side session or HttpOnly cookie — never `localStorage`).

## Step 5 — Call MRC APIs

<Note>
  The MRC APIs are not yet available. When released, you will call them with the access token as a Bearer token (`Authorization: Bearer {access_token}`); their endpoints and required scopes will be documented under **MRC APIs → API Reference**.
</Note>

## Step 6 — Refresh the access token

When the access token expires (`401` response), use the refresh token to get a new one without sending the advisor through the flow again:

```bash theme={null}
curl -X POST https://oauth.fmgsuite.com/v1/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=refresh_token \
  -d refresh_token={refresh_token} \
  -d client_id={CLIENT_ID} \
  -d client_secret={CLIENT_SECRET}
```

***

## Scopes

Request exactly the scopes FMG assigned you — requesting an unprovisioned scope fails.

| Scope            | Grants                                         |
| ---------------- | ---------------------------------------------- |
| `openid`         | Required — identity claims in the token.       |
| `offline_access` | Returns a refresh token for long-lived access. |

<Note>
  MRC API scopes (for sending SMS, reading delivery status, and similar operations) are not yet available and will be published here when the MRC APIs are released. The flow currently issues identity scopes only (`openid`, `offline_access`).
</Note>

***

## Errors

| Situation                | Result                                                 |
| ------------------------ | ------------------------------------------------------ |
| User denies consent      | Redirect to `redirect_uri` with `error=access_denied`. |
| `state` mismatch         | Reject the callback — possible CSRF.                   |
| Invalid / expired code   | Token exchange returns `400`.                          |
| `code_verifier` mismatch | Token exchange returns `400`.                          |
| Expired access token     | API returns `401` — refresh the token (Step 6).        |
| Expired refresh token    | Refresh returns `400` — restart from Step 2.           |
| MRC unavailable          | `503` — transient; retry after a short delay.          |

***

## Security requirements

* **PKCE (S256)** for every request; keep the `code_verifier` server-side.
* **Unique `state`** per request; validate on callback.
* **Token exchange and refresh are server-side only** — never expose `client_secret` or `code_verifier` to the browser.
* **HTTPS** for all redirect URIs and API calls.
* Store tokens in HttpOnly cookies or server-side sessions.
