# OAuth 2.0 Authorization Code Flow

Use the OAuth 2.0 Authorization Code Flow when the Advertiser already operates an OAuth service. The user authenticates
with the Advertiser, the Advertiser issues a short-lived authorization code, and Onward exchanges that code from one
backend to another before linking the identities.

This is the preferred mechanism for Advertisers with established OAuth infrastructure because browser redirects carry
only a temporary code. Advertiser credentials and access tokens remain on backend systems.

## Responsibilities

| Actor | Responsibility |
| --- | --- |
| Platform | Verify its current user, start the connection, and redirect the browser to the URL returned by Onward. |
| Advertiser | Authenticate or register the user, issue an authorization code, and expose a token endpoint. |
| Onward | Protect the flow state, exchange the code, read the stable Advertiser user identifier, link the identities, and return the browser to the Platform. |

## Flow

1. The Platform reads the active quest chain and identifies a task with `condition_event_type: "link_account"`.
2. The Platform backend calls
   [`POST /v1/account/start-connect`](/docs/api-reference/account-connection-api#start-oauth-account-linking) with
   `platform_user_id`, `quest_chain_id`, and its return `redirect_url`.
3. Onward returns a `redirect_url` pointing to the Advertiser's authorization endpoint.
4. The Platform redirects the browser to that URL.
5. The Advertiser signs the user in or creates an account on its `/authorize` page.
6. The Advertiser redirects the browser to the Onward callback with an authorization `code` and the original `state`.
7. Onward validates the state and exchanges the code through the Advertiser's `/token` endpoint.
8. The token response identifies the user through a stable `advertiser_user_id`.
9. Onward links the Platform and Advertiser identities and updates quest-chain progress.
10. Onward redirects the browser to the Platform's original `redirect_url` with a success or error result.

<Mermaid
  chart={`sequenceDiagram
    participant Browser
    participant PlatformBackend as Platform backend
    participant Onward as Onward API
    participant AdvertiserAuth as Advertiser OAuth service

    Browser->>PlatformBackend: Start account-linking task
    PlatformBackend->>Onward: POST /v1/account/start-connect
    Onward-->>PlatformBackend: redirect_url
    PlatformBackend-->>Browser: Redirect to /authorize
    Browser->>AdvertiserAuth: Sign up or sign in
    AdvertiserAuth-->>Browser: Redirect with code and state
    Browser->>Onward: OAuth callback
    Onward->>AdvertiserAuth: Exchange authorization code at /token
    AdvertiserAuth-->>Onward: access_token and advertiser_user_id
    Onward->>Onward: Link identities and update progress
    Onward-->>Browser: Redirect to Platform redirect_url`}
  caption="OAuth 2.0 Authorization Code Flow. Secrets, codes, and access tokens are processed by backend systems."
/>

## Start the connection

The Platform must call `start-connect` from its backend after verifying that `platform_user_id` belongs to the current
authenticated user.

```http
POST /v1/account/start-connect
Content-Type: application/json
X-API-Key: <platform-api-key>
X-API-Secret: <platform-api-secret>

{
  "platform_user_id": "platform-user-456",
  "quest_chain_id": "6f2f6f4e-4a1e-4f6f-9a2b-2c9d1f0b7a31",
  "redirect_url": "https://platform.example/account-linking/result"
}
```

The successful response wraps the Advertiser authorization URL in `data.redirect_url`. The Platform should use the URL
as returned instead of parsing it or constructing an Advertiser URL itself.

## What the Advertiser provides

### Authorization endpoint

The Advertiser supplies an `/authorize` page that accepts the OAuth parameters configured during onboarding, including
`client_id`, `redirect_uri`, and `state`. It authenticates or registers the user and redirects to the exact registered
Onward callback with `code` and the unchanged `state`.

```text
https://api.onwardinc.net/v1/oauth/callback?code=AUTHORIZATION_CODE&state=OPAQUE_STATE
```

The exact callback origin and path are part of the Advertiser's Onward configuration. Do not copy an environment-specific
callback URL from an example.

### Token endpoint

The Advertiser supplies a backend `/token` endpoint. Onward sends an authorization-code exchange containing the code,
the registered redirect URI, and the OAuth client credentials provisioned for Onward.

```json
{
  "grant_type": "authorization_code",
  "code": "AUTHORIZATION_CODE",
  "redirect_uri": "https://api.onwardinc.net/v1/oauth/callback",
  "client_id": "ONWARD_CLIENT_ID",
  "client_secret": "ONWARD_CLIENT_SECRET"
}
```

After validating the code, the endpoint returns an access token, a stable `advertiser_user_id`, and its lifetime. Onward
uses the Advertiser user identifier to create the connection; the Platform never receives the Advertiser access token.

```json
{
  "access_token": "<advertiser-access-token>",
  "advertiser_user_id": "advertiser-user-123",
  "expires_in": 3600
}
```

### Configuration supplied during onboarding

| Setting | Purpose |
| --- | --- |
| Authorization URL | Advertiser page on which the user signs up or signs in. |
| Token URL | Backend endpoint used by Onward to exchange an authorization code. |
| Client ID | OAuth client identifier issued to Onward. |
| Client secret | Secret used only for backend token requests. |
| Redirect URI | Exact Onward callback registered by the Advertiser. |

## Returning to the Platform

After the exchange succeeds, Onward redirects to the Platform's original `redirect_url`. A successful redirect includes
`status=connected` and may identify the Advertiser. An unsuccessful redirect includes an `error` and a human-readable
`message`.

Common result shapes include:

```text
?status=connected&advertiser=AdvertiserName
?error=already_connected&message=This advertiser account is already connected
?error=invalid_state&message=Invalid or expired state token
?error=provider_error&message=OAuth provider error details
?error=database_error&message=Failed to save connection
?error=server_error&message=Internal server error
```

Treat redirect parameters as user-interface hints rather than proof that the connection exists. Refresh the active quest
chain after the user returns and use the API state as the authoritative result.

See [Security requirements](/docs/account-linking/security-requirements) before exposing the flow in production.
