Skip to Content
Browse docs

Maintained by

Use Your Own Domain for OAuth Callbacks

When using your own Google OAuth app, you can receive the authorization callback on your domain. For example, Google redirects to https://auth.example.com/oauth/callback, and your endpoint returns a 302 redirect to Connector to complete authorization.

Deploy an HTTPS callback endpoint on your domain. You manage the domain and certificate; Connector handles the token exchange, credential storage, and token refresh.

This setup applies to Connector for SaaS providers using a custom client that return OAuth results through GET query parameters. Create a Project with the Connector for SaaS guide first. When using a system client, use the default callback URL provided by Console.

Prepare the three URLs

These examples use the production Connector service:

URLExampleWhere to configure it
Your OAuth callbackhttps://auth.example.com/oauth/callbackThe Google client’s Authorized redirect URIs and the OOMOL provider config’s Custom callback URL. Use exactly the same URL in both.
Connector callbackhttps://connector.oomol.com/v1/oauth/callbackThe 302 Location returned by your callback endpoint.
Product return URLhttps://app.example.com/connections/doneThe returnUri when creating an authorization link, where your product displays the connection result.

The flow is Google → your callback endpoint → Connector callback → product return URL. The browser passes through the Connector domain.

Step 1: Deploy the 302 endpoint

Serve /oauth/callback on auth.example.com and return a 302 response immediately. Save this code as oauth-callback.ts, start it with bun run oauth-callback.ts, and expose it through your existing HTTPS gateway:

Bun.serve({
  routes: {
    "/oauth/callback": {
      GET(request) {
        const query = new URL(request.url).search;
        return new Response(null, {
          status: 302,
          headers: {
            Location: `https://connector.oomol.com/v1/oauth/callback${query}`,
            "Cache-Control": "no-store",
            "Referrer-Policy": "no-referrer",
          },
        });
      },
    },
  },
});

Use the same response logic when adding the endpoint to an existing service. Keep the Connector callback as the fixed Location destination and append the original query string.

  • Preserve every parameter and its original encoding, including code, state, errors, and provider-specific fields such as QuickBooks realmId or Shopify hmac. Do not decode and rebuild the query with URLSearchParams.
  • Return the 302 directly. This endpoint does not require sign-in, exchange tokens, or consume state. Do not fetch the Connector callback from your server; the browser must follow the redirect.
  • Disable query-string capture for this route in application logs, gateways, CDNs, error reporting, and tracing so that authorization codes and state are not recorded. Return the response without rendering a page or loading third-party resources.

Step 2: Register the callback with Google

In Google Cloud Console, create or open your Web application OAuth client. Add this URL to Authorized redirect URIs:

https://auth.example.com/oauth/callback

Use the HTTPS URL you deployed. Its scheme, host, path, trailing slash, and any existing query parameters must match the OOMOL config. See Google’s web server OAuth documentation for redirect URI requirements.

For brand verification, verify ownership of the root domain, example.com, in Google Search Console and add it to your OAuth app’s Authorized domains. The Google account used for domain verification must be associated with the Google Cloud project. Domains used by your home page, privacy policy, other redirect URIs, or JavaScript origins are also in scope. See Google’s brand verification requirements.

Registering a callback on your own domain lets you verify that domain with Google. Your app must still meet Google’s other brand requirements and complete any required sensitive or restricted scope reviews.

Step 3: Configure a custom client in OOMOL

In OOMOL Console:

  1. Open Projects, select the project, and open Provider configs.
  2. Click Create provider config and select Gmail with OAuth2.
  3. Set Client config source to Custom client and enter your Google Client ID and Client Secret.
  4. Enter https://auth.example.com/oauth/callback in Custom callback URL (optional).
  5. Create the config and copy its Provider Config ID for your backend’s providerConfigId.

The Default callback URL is the destination in your forwarding code. Leave the custom callback empty to have Google redirect directly to the default URL.

Your backend can also call POST https://connector.oomol.com/v1/saas/projects/:projectId/provider-configs with a Project API key, an Authorization: Bearer <project-api-key> header, and this body:

{
  "service": "gmail",
  "slug": "gmail-custom",
  "displayName": "Gmail",
  "authType": "oauth2",
  "oauth": {
    "clientConfigSource": "custom",
    "clientId": "<google-client-id>",
    "clientSecret": "<google-client-secret>",
    "redirectUri": "https://auth.example.com/oauth/callback",
    "scopes": ["https://www.googleapis.com/auth/gmail.readonly"]
  }
}

Use the Project API key and Client Secret only in trusted backend code or Console. The example scope allows read-only Gmail access; choose the permissions needed by your operations.

oauth.redirectUri must use HTTPS and cannot contain a username, password, or # fragment. It may include ordinary query parameters such as tenant, but must not predefine state, code, error, error_description, error_uri, or scope, including percent-encoded forms of those names. These restrictions apply to the registered URL; your endpoint must still forward all parameters received from the provider.

redirectUri is accepted only with clientConfigSource: "custom". The callbackUrl returned by config queries is the URL actually sent to the provider. To change an existing config’s callback URL, create a new provider config and start authorization with its ID.

Step 4: Start authorization and verify the connection

Your backend uses the existing authorization-link endpoint with the new Provider Config ID:

POST https://connector.oomol.com/v1/saas/connected-accounts/link
Authorization: Bearer <project-api-key>
Content-Type: application/json
{
  "providerConfigId": "<provider-config-id>",
  "userId": "customer-1",
  "returnUri": "https://app.example.com/connections/done"
}

Save the response’s data.id and its user association on your backend before opening data.authorizationUrl in the browser. After authorization, your endpoint forwards the full query string to Connector. Connector exchanges the code using the registered custom callback URL, then redirects to returnUri.

Before storing an account binding, query the connection request from your backend and verify its user and config. Follow the SaaS authorization and connection verification steps. With the SDK, continue using the ProjectConnector connection methods and pass the corresponding providerConfigId.

Before going live, check the forwarder with dummy callback data:

curl -sS -D - -o /dev/null \
  'https://auth.example.com/oauth/callback?code=test%2Bvalue&state=test-state'

Expect a 302 response with Location: https://connector.oomol.com/v1/oauth/callback?code=test%2Bvalue&state=test-state. Then complete a real authorization and test cancellation. Confirm that both outcomes return to your product.

Troubleshooting

SymptomWhat to check
Google returns redirect_uri_mismatchThe URL registered with Google must exactly match oauth.redirectUri. Check that the authorization request uses the correct Provider Config ID.
Missing or invalid state, or a provider signature errorYour gateway and app must preserve the original query string. Check for decoding, reconstruction, dropped parameters, or consuming the callback more than once.
QuickBooks reports a missing realmIdForward the complete query string rather than selecting only code and state.
Your endpoint responds, but the browser does not continueReturn HTTP 302 and Location to the browser instead of requesting Connector from your server.
The user needs to return to your product after authorizationSet returnUri when creating the authorization link. Your custom callback endpoint must forward to Connector first.

Your everyday apps, now for your AI

Let your AI find emails, read documents and look through code in the apps you already use.