# Integrate a custom identity provider with Nylas Connect

Source: https://developer.nylas.com/docs/v3/auth/nylas-connect/use-external-idp/custom/

Nylas Connect works with any identity provider that issues JWTs (JSON Web Tokens) and exposes a JWKS (JSON Web Key Set) endpoint. This means you can use open-source solutions like Keycloak or Ory, cloud services like Firebase Auth or Supabase Auth, or even your own custom JWT server.

If your identity provider isn't Auth0, Clerk, Google, or WorkOS, this is the guide for you.

## How JWKS works with Nylas

When you configure a custom identity provider, Nylas uses JWKS to verify the tokens your IDP issues:

1. Your IDP signs JWTs with a private key.
2. Your IDP exposes a JWKS endpoint (a public URL that serves the corresponding public keys).
3. When Nylas receives a request with your IDP token, it fetches the public keys from your JWKS endpoint and verifies the token signature.

This means Nylas never needs your IDP's private keys. It only needs the JWKS URL to verify that tokens are legitimate.

## Before you begin

You need an identity provider with JWKS support and a Nylas application configured to work together.


### Configure Nylas Dashboard

Before connecting your identity provider, configure the IDP settings in the Nylas Dashboard:

1. Navigate to your application in the [Nylas Dashboard](https://dashboard-v3.nylas.com).
2. Go to **Hosted Authentication** → **Identity Providers**.
3. Configure the following settings:
   - **Allowed Origins**: Add the domains where your application will be hosted (e.g., `http://localhost:3000`, `https://yourapp.com`). These origins will be allowed to make requests to Nylas with your IDP tokens.
   - **Callback URIs**: Add the redirect URIs that Nylas will use after authentication (e.g., `http://localhost:3000/auth/callback`). These must match the `redirectUri` configured in your NylasConnect instance.

> **Note:** 
> The allowed origins and callback URIs are security measures to prevent unauthorized use of your Nylas application. Include all domains where your application will run, including development, staging, and production environments.

You can access the Identity Provider settings page directly at:

```
https://dashboard-v3.nylas.com/applications/<YOUR_APP_ID>/hosted-authentication/idp-settings
```


### Configure your JWKS endpoint in Nylas

In addition to the standard Nylas Dashboard setup, you need to provide your JWKS endpoint URL:

1. In the [Nylas Dashboard](https://dashboard-v3.nylas.com), go to **Hosted Authentication** → **Identity Providers**.
2. Enter your IDP's **JWKS URI** (e.g., `https://your-idp.com/.well-known/jwks.json`).
3. Save the configuration.

### JWKS endpoint requirements

Your identity provider's JWKS endpoint must:

- Be publicly accessible over HTTPS (Nylas needs to fetch keys at runtime)
- Serve a valid JWKS JSON document with RSA or EC public keys
- Include the `kid` (key ID) header in issued JWTs that matches a key in the JWKS response
- Issue JWTs with a `sub` claim that uniquely identifies the user

Common JWKS endpoint paths by provider:

| Provider      | JWKS endpoint                                                                               |
| ------------- | ------------------------------------------------------------------------------------------- |
| Keycloak      | `https://<host>/realms/<realm>/protocol/openid-connect/certs`                               |
| Ory / Hydra   | `https://<host>/.well-known/jwks.json`                                                      |
| Firebase Auth | `https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com` |
| Supabase Auth | `https://<project-ref>.supabase.co/auth/v1/.well-known/jwks.json`                           |
| Custom server | Typically `https://your-domain.com/.well-known/jwks.json`                                   |

## Implementation

The pattern is the same as any other IDP integration: pass your token to Nylas Connect through the `identityProviderToken` callback. The specifics of how you obtain the token depend on your IDP.

Here's a generic example assuming your IDP provides a `getToken()` method:

```ts


async function getIdpToken(): Promise<string | null> {
  // Replace this with your IDP's token retrieval method.
  // Examples:
  //   Keycloak: keycloak.token
  //   Firebase: await firebase.auth().currentUser.getIdToken()
  //   Supabase: (await supabase.auth.getSession()).data.session?.access_token
  //   Custom:   await fetch("/api/auth/token").then(r => r.json()).then(d => d.token)
  return null;
}

const nylasConnect = new NylasConnect({
  clientId: "<NYLAS_CLIENT_ID>",
  redirectUri: "http://localhost:3000/auth/callback",
  identityProviderToken: async () => {
    try {
      return await getIdpToken();
    } catch (error) {
      console.error("Failed to get IDP token:", error);
      return null;
    }
  },
});

async function connectEmail() {
  try {
    const result = await nylasConnect.connect({ method: "popup" });
    console.log("Email connected:", result.grantInfo?.email);
  } catch (error) {
    console.error("Failed to connect email:", error);
  }
}

async function logout() {
  await nylasConnect.logout();
  // Also sign out from your IDP
}
```

### Keycloak example

```ts


const keycloak = new Keycloak({
  url: "https://your-keycloak-server.com",
  realm: "<REALM_NAME>",
  clientId: "<KEYCLOAK_CLIENT_ID>",
});

await keycloak.init({ onLoad: "login-required" });

const nylasConnect = new NylasConnect({
  clientId: "<NYLAS_CLIENT_ID>",
  redirectUri: "http://localhost:3000/auth/callback",
  identityProviderToken: async () => {
    await keycloak.updateToken(30);
    return keycloak.token || null;
  },
});
```

### Firebase Auth example

```ts


const auth = getAuth();

const nylasConnect = new NylasConnect({
  clientId: "<NYLAS_CLIENT_ID>",
  redirectUri: "http://localhost:3000/auth/callback",
  identityProviderToken: async () => {
    const user = auth.currentUser;
    if (!user) return null;
    return await user.getIdToken();
  },
});
```

## Make API calls

After the user authenticates with your IDP and connects their email, use the IDP token to make Nylas API requests. The pattern is the same as other providers: pass the token as a Bearer token and include the `X-Nylas-External-User-Id` header with the user's `sub` claim:

```ts
function parseSubFromJwt(token: string): string | null {
  try {
    const base64Payload = token.split(".")[1];
    const payload = JSON.parse(atob(base64Payload));
    return payload?.sub || null;
  } catch {
    return null;
  }
}

async function fetchEmails() {
  const token = await getIdpToken();
  const userId = parseSubFromJwt(token || "");

  const response = await fetch(
    `https://api.us.nylas.com/v3/grants/me/messages`,
    {
      headers: {
        Authorization: `Bearer ${token}`,
        "X-Nylas-External-User-Id": userId || "",
      },
    },
  );

  return await response.json();
}
```

> **Info:** 
> Use `https://api.us.nylas.com` for US-hosted applications or `https://api.eu.nylas.com` for EU-hosted applications.

## Troubleshooting

| Problem                         | Cause                        | Solution                                                                                                                              |
| ------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `401 Unauthorized` on API calls | Nylas can't verify the token | Confirm your JWKS URI is correct and publicly accessible. Check that the `kid` in your JWT header matches a key in the JWKS response. |
| Token verification fails        | Key mismatch                 | Ensure your IDP is using the same key pair for signing tokens as the one published at the JWKS endpoint.                              |
| `sub` claim missing             | Token format issue           | Check that your IDP includes a `sub` claim in the JWT payload. Some IDPs use custom claim names.                                      |
| JWKS endpoint unreachable       | Network or CORS issue        | The JWKS endpoint must be publicly accessible over HTTPS. It doesn't need CORS headers because Nylas fetches it server-side.          |

## What's next

- [Session management](/docs/v3/auth/nylas-connect/use-external-idp/#session-management) for monitoring connection state
- [Error handling](/docs/v3/auth/nylas-connect/use-external-idp/#error-handling) for handling authentication failures
- [Nylas Connect overview](/docs/v3/auth/nylas-connect/) for standalone OAuth without an IDP
- [Auth0](/docs/v3/auth/nylas-connect/use-external-idp/auth0/), [Clerk](/docs/v3/auth/nylas-connect/use-external-idp/clerk/), [Google](/docs/v3/auth/nylas-connect/use-external-idp/google/), or [WorkOS](/docs/v3/auth/nylas-connect/use-external-idp/workos/) for provider-specific guides