Skip to main content
Before following this guide, configure an integration in the Nango dashboard by selecting a provider and entering your OAuth app credentials. See the Auth overview for context on providers, integrations, and connections.

Prerequisites

  • A Nango account and project set up at app.nango.dev
  • At least one integration configured in the dashboard
  • Your Nango secret key from Environment Settings
  • The @nangohq/node SDK installed in your backend
npm install @nangohq/node

How it works

The authorization flow involves three parties: your backend, your frontend, and Nango. Your backend generates a short-lived session token, your frontend uses it to open the Connect UI, and Nango handles the OAuth flow. After the user authorizes, Nango sends a webhook to your backend with the connection ID.

Step 1: Generate a session token (backend)

Set up an endpoint in your backend that your frontend calls before each authorization attempt. This endpoint requests a session token from Nango and returns it to your frontend.
import { Nango } from '@nangohq/node';

const nango = new Nango({ secretKey: process.env['NANGO_SECRET_KEY'] });

app.post('/session-token', async (req, res) => {
  const { data } = await nango.createConnectSession({
    tags: {
      end_user_id: '<END-USER-ID>',
      end_user_email: '<END-USER-EMAIL>',
      organization_id: '<ORGANIZATION-ID>'
    },
    allowed_integrations: ['<INTEGRATION-ID>']
  });

  res.status(200).json({ sessionToken: data.token });
});
The tags object lets you associate a connection with users, organizations, or other entities in your system. Nango includes these tags in auth webhooks so you can reconcile the generated connection ID with the right entity. Most apps use end_user_id, end_user_email, and organization_id. See Connection management for more on tags.
The allowed_integrations field controls what the user sees:
  • Passing multiple integration IDs shows a list of integrations the user can pick from
  • Passing a single integration ID sends the user directly to that integration’s authorization flow

Step 2: Trigger the auth flow (frontend)

In your frontend, install the Nango frontend SDK:
npm install @nangohq/frontend
Then initialize Nango and open the Connect UI when the user clicks “Connect”:
import Nango from '@nangohq/frontend';

const nango = new Nango();

const connect = nango.openConnectUI({
  onEvent: (event) => {
    if (event.type === 'close') {
      // The user closed the Connect UI without completing auth.
    } else if (event.type === 'connect') {
      // Authorization succeeded.
      console.log('Connected:', event.payload.connectionId);
    } else if (event.type === 'error') {
      // Authorization failed.
      console.error('Auth error:', event.payload.errorMessage);
    }
  },
});

// Retrieve the session token from your backend endpoint.
const res = await fetch('/session-token', { method: 'POST' });
const { sessionToken } = await res.json();

// Pass the token to the Connect UI. A loading indicator is shown until this is set.
connect.setSessionToken(sessionToken);
The openConnectUI() call renders the Connect UI in a full-screen iframe. The UI handles the entire authorization flow, including OAuth redirects and API-key collection forms.
The Connect UI is recommended, but optional. If you need full control over the authorization UX — for example, to build a custom form for API key entry — see the Connect UI guide for details on using nango.auth() directly.

Step 3: Save the connection ID (backend)

After the user authorizes, Nango creates a connection and sends a POST webhook to your backend with the connection ID. You persist this ID associated with the user or organization in your database. Configure the webhook:
  1. Go to Environment Settings in the Nango dashboard
  2. Set a Webhook URL pointing to an endpoint in your backend
  3. Enable Send New Connection Creation Webhooks
Nango sends the following payload on successful authorization:
{
  "type": "auth",
  "operation": "creation",
  "success": true,
  "connectionId": "<CONNECTION-ID>",
  "tags": {
    "end_user_id": "<END-USER-ID>",
    "end_user_email": "<END-USER-EMAIL>",
    "organization_id": "<ORGANIZATION-ID>"
  }
}
Store the connectionId value alongside the entity it belongs to in your system.
During development only: you can retrieve the connection ID from the connect event in the frontend SDK without relying on webhooks.
nango.openConnectUI({
  onEvent: (event) => {
    if (event.type === 'connect') {
      console.log(event.payload.connectionId, event.payload.providerConfigKey);
    }
  }
});
Do not rely on this in production — it is safer to avoid exposing the connection ID in the frontend.

Step 4: Test the flow

Run the authorization flow from your app and confirm a new connection appears in the Connections tab of the Nango dashboard. If a flow fails, check the Logs tab for a detailed error breakdown.

Step 5: Set up a custom OAuth callback URL (optional)

By default, Nango uses api.nango.dev as the OAuth callback domain. Some providers (such as Google and Zoom) require domain verification or show the callback domain to users during the flow. Setting up a custom callback URL lets you use your own domain.
  1. Add an endpoint in your app, for example https://example.com/oauth-callback, that performs a 308 redirect to https://api.nango.dev/oauth/callback, preserving all query parameters
  2. Register the new URL as the OAuth callback with each provider’s developer console
  3. Update the Callback URL in Environment Settings in the Nango dashboard
Complete steps 1 and 2 before updating the callback URL in Nango. If the redirect is missing or the wrong URL is registered with a provider, all authorization attempts for that integration will fail.

Step 6: Re-authorize an existing connection

When a connection’s credentials expire or scopes change, you can re-authorize without deleting the connection. Re-authorization updates the credentials while preserving all associated data and configuration. Detect an invalid connection by calling getConnection() and checking for a 4xx response:
import { Nango } from '@nangohq/node';

const nango = new Nango({ secretKey: process.env['NANGO_SECRET_KEY'] });

try {
  const connection = await nango.getConnection('<INTEGRATION-ID>', '<CONNECTION-ID>');
  // Connection is valid — show normal integration settings.
} catch (error) {
  if (error.status >= 400 && error.status < 500) {
    // Connection is invalid — show a reconnect prompt.
  }
}
Trigger re-authorization by requesting a reconnect session token and passing it to the frontend SDK the same way as a new connection:
import { Nango } from '@nangohq/node';

const nango = new Nango({ secretKey: process.env['NANGO_SECRET_KEY'] });

app.post('/reconnect-token', async (req, res) => {
  const { data } = await nango.createReconnectSession({
    connection_id: '<CONNECTION-ID>',
    integration_id: '<INTEGRATION-ID>'
  });

  res.status(200).json({ sessionToken: data.token });
});
After re-authorization succeeds, Nango sends an auth webhook with "operation": "override".

Environment variables

VariableDescription
NANGO_SECRET_KEYYour Nango secret key, found in Environment Settings. Keep this server-side only.

Next steps

Connect UI

Customize the Connect UI appearance and use a connect link for email-based flows.

Connection management

Retrieve credentials, set metadata, and manage connections programmatically.

Build docs developers (and LLMs) love