---
title: "OAuth redirect target (public; authenticated by the signed state)"
method: GET
path: "/connect/oauth/callback"
tags: ["Connections"]
---

# OAuth redirect target (public; authenticated by the signed state)

`GET /connect/oauth/callback`

## Request

- Base URL: `https://api.customdomain.ai/v1`
- URL: `https://api.customdomain.ai/v1/connect/oauth/callback`
- Auth: none required

The provider's browser redirect target, **not** a bearer-authenticated endpoint, and the Redirect URL of the CustomDomain™ Vercel integration. It consumes the signed single-use `state`, turns what the provider sent into a credential (exchanges the `code`; for Porkbun retrieves the approved key pair with the PKCE verifier; for OVHcloud uses the validated consumer key), writes the connection's records with it (dropped after, unless kept for managed mode), and returns an HTML page that postMessages `{ type: "customdomain:oauth", payload }` to the vetted return origin. `payload` carries `ok`, `managed`, and on failure a `code` and `message`: besides the provider's own `error` (for example `access_denied`) and `ProviderAuthenticationError`, `apply_failed`, `apex_not_supported`, `forwarding_not_supported`, the rail specific codes are `porkbun_api_access_disabled` (turn on API access for the domain at Porkbun), `vercel_team_scope` (install on the team that owns the domain), `ovh_zone_not_found` (pick the OVHcloud region the account lives in), `oauth_scope_not_granted` (a permission was left unticked on the provider's consent screen; sign in again and allow them all), for Google Cloud DNS `gcpdns_zone_not_found` (no public Cloud DNS zone for the domain in a Google Cloud project the account can edit), `gcpdns_zone_ambiguous` (more than one) and `gcpdns_search_incomplete` (the account can see more projects than the search reaches, so the one zone found is not written to), and for Azure DNS `azuredns_zone_not_found` (no public Azure DNS zone for the domain in a subscription the Microsoft account can list zones in), `azuredns_zone_ambiguous` (more than one), `azuredns_search_incomplete` (the account can see more subscriptions or zones than the search reaches, so the one zone found is not written to) and `azuredns_mfa_required` (Azure requires multifactor authentication for the change and the sign-in did not use it). With the not found and ambiguous codes, `payload.account` names the Google or Microsoft account that signed in, when the provider said which; the connection's stored `error_message` never does. After an `mcp_oauth` sign-in, `apply_failed` also reports a write refused before anything changed because a record the provider's DNS tools may not remove is in the way (a Namecheap URL redirect, a record a provider's product manages; the `message` names it and where to remove it), and `ProviderAuthenticationError` a DNS tool the user did not approve at the provider (sign in again and approve DNS access). A failure is also stored as the connection's `error_code`.

## Query parameters

- `code` string
- `state` string, required
- `teamId` string
- `configurationId` string
- `status` 'approved' | 'denied'
- `requestToken` string

## Response `200`

HTML finish page (postMessages the outcome to the vetted return origin)

## Other responses

- `400`: Invalid, expired, or replayed state

---

[API](https://skmtc.dev/customdomain/apis/customdomain-control-plane-api.md) · [All operations](https://skmtc.dev/customdomain/apis/customdomain-control-plane-api/llms.txt) · [OpenAPI document](https://skmtc.dev/customdomain/apis/customdomain-control-plane-api/revisions/34d89cb7a7cd?raw)
