# Bulk authentication grants

Source: https://developer.nylas.com/docs/v3/auth/bulk-auth-grants/

Bulk authentication grants let you authenticate users without requiring each person to go through an individual OAuth flow. This is useful when you need to access mailboxes or calendars for many users in an organization.

Google and Microsoft use different mechanisms for this:

- **Google** uses [service accounts](https://cloud.google.com/iam/docs/service-accounts) with domain-wide delegation. A Google Workspace admin grants your service account access to user data across the domain.
- **Microsoft** uses [admin consent](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/user-admin-consent-overview). An Azure AD admin approves your app's requested permissions for all users in the tenant. You don't need to create a service account or generate new keys -- you use your existing Azure app's client ID and secret.

Both flows require you to register your provider credentials with Nylas using the [Create Credential API](/docs/reference/api/connector-credentials/create_credential/), then create grants for individual users using the [Custom Authentication API](/docs/reference/api/manage-grants/byo_auth/).

These are not related to [Nylas Service Accounts](/docs/v3/auth/nylas-service-account/), which use cryptographic request signing for organization-level admin APIs.

## Before you begin

Ensure that your Nylas application has a working [Google](/docs/provider-guides/google/create-google-app/#add-a-connector-to-your-nylas-application) or [Microsoft](/docs/provider-guides/microsoft/create-azure-app/#add-a-microsoft-connector-to-nylas) connector. You can check this on the Nylas Dashboard, or make a [Get all connectors request](/docs/reference/api/connectors-integrations/get_connector_by_provider/).

If you don't have a connector, create one from the Dashboard or make a [Create Connector request](/docs/reference/api/connectors-integrations/create_connector/).

## Create Google bulk authentication grants

Google bulk auth grants use a Google Workspace service account with domain-wide delegation. The service account's private key lets Nylas request access tokens for any user in the domain without individual OAuth flows.

1. [Create a Google service account and delegate domain-wide authority](#step-1-create-a-google-service-account).
2. [Register the service account with Nylas](#step-2-register-the-service-account-with-nylas).
3. [Create a grant for a user](#step-3-create-a-google-bulk-auth-grant).

### Step 1: Create a Google service account

Follow the Google provider guide to [create a service account](/docs/dev-guide/provider-guides/google/google-workspace-service-accounts/#create-a-service-account) and [delegate domain-wide authority](/docs/dev-guide/provider-guides/google/google-workspace-service-accounts/#optional-create-a-service-account-key). You'll need the service account's JSON key file for the next step.

### Step 2: Register the service account with Nylas

Make a [Create Credential request](/docs/reference/api/connector-credentials/create_credential/) to register your Google service account with Nylas. Include the service account details from the JSON key file you downloaded.

```bash
curl --request POST \
  --url 'https://api.us.nylas.com/v3/connectors/google/creds' \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --data '{
    "name": "Test Google service account credential",
    "credential_type": "serviceaccount",
    "credential_data": {
      "type": "service_account",
      "project_id": "marketplace-sa-test",
      "private_key_id": "<GOOGLE_PRIVATE_KEY_ID>",
      "private_key": "<GOOGLE_PRIVATE_KEY>",
      "client_email": "nyla@example.com"
    }
  }'
```

```json
{
  "request_id": "1",
  "data": {
    "id": "<NYLAS_CONNECTOR_CREDENTIAL_ID>",
    "credential_type": "serviceaccount",
    "name": "Test Google service account credential",
    "created_at": 1656082371,
    "updated_at": 1656082371
  }
}
```

Save the `id` from the response. You'll use this `credential_id` when creating grants.

### Step 3: Create a Google bulk auth grant

Make a [Custom Authentication request](/docs/reference/api/manage-grants/byo_auth/) to create a grant for a specific user's email address. Use the `credential_id` from the previous step.

```bash
curl --request POST \
  --url 'https://api.us.nylas.com/v3/connect/custom' \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --data '{
    "provider": "google",
    "settings": {
      "credential_id": "<NYLAS_CONNECTOR_CREDENTIAL_ID>",
      "email_address": "leyah@example.com",
      "scopes": ["https://www.googleapis.com/auth/gmail.readonly"]
    }
  }'
```

```json
{
  "request_id": "171cac55-10b6-4989-9e03-8f4a9795ca61",
  "data": {
    "id": "<NYLAS_GRANT_ID>",
    "grant_status": "valid",
    "provider": "google",
    "scope": [
      "openid",
      "https://www.googleapis.com/auth/userinfo.email",
      "https://www.googleapis.com/auth/userinfo.profile",
      "https://www.googleapis.com/auth/gmail.readonly"
    ],
    "email": "leyah@example.com",
    "settings": {
      "app_permission": true,
      "credential_id": "6c40d1e8-b1b4-4a58-a92a-93a34b666a0f",
      "credential_type": "serviceaccount",
      "scopes": ["https://www.googleapis.com/auth/gmail.readonly"]
    },
    "ip": "<IP_ADDRESS>",
    "user_agent": "sensitive_data",
    "created_at": 1749053226,
    "updated_at": 1749053226,
    "provider_user_id": "leyah@example.com",
    "blocked": false
  }
}
```

Repeat this step for each user you want to authenticate. Because the service account has domain-wide delegation, you can create grants for any user in the Google Workspace domain.

## Create Microsoft bulk authentication grants

Microsoft bulk auth grants use Azure AD admin consent to grant your app application-level permissions. Unlike Google (where you generate a service account key), you use your existing Azure app's client ID and secret. A Microsoft admin at your customer's organization then approves your app for their tenant, which gives it access to user mailboxes and calendars without individual OAuth flows.

1. [Configure your Azure app for application permissions](#step-1-configure-your-azure-app-for-application-permissions).
2. [Register your Azure app credentials with Nylas](#step-2-register-your-azure-app-credentials-with-nylas).
3. [Get admin consent for your app](#step-3-get-admin-consent).
4. [Create a grant for a user](#step-4-create-a-microsoft-bulk-auth-grant).

### Step 1: Configure your Azure app for application permissions

If you already have an Azure app from [setting up your Microsoft connector](/docs/provider-guides/microsoft/create-azure-app/), you just need to add application permissions. If you don't have one yet, [create an Azure auth app](/docs/provider-guides/microsoft/create-azure-app/) first, then configure it:

1. From the **Authentication** tab, click **Add a platform**.
2. Set the **Platform** to **Web** and enter the **Custom Auth** URI.
3. In the **Certificates & secrets** tab, click **New client secret** and add a client secret.
> **Warn:** 
> **[Save the client secret somewhere secure](/docs/dev-guide/best-practices/#store-secrets-securely), like a secrets manager.** The Azure Dashboard shows the `client_secret` value only once. If you lose it, you'll need to create a new one.
4. In the **API permissions** tab, click **Add a permission** and select **Microsoft Graph** from the list of APIs.
5. Select **Application permissions** and add all the Microsoft Graph scopes that your project needs, including `User.Read.All`.

You don't need to select **Grant admin consent** here. You'll grant consent in [Step 3](#step-3-get-admin-consent) using an authorization request.

### Step 2: Register your Azure app credentials with Nylas

Make a [Create Credential request](/docs/reference/api/connector-credentials/create_credential/) to register your Azure app's `client_id` and `client_secret` with Nylas. You don't need to generate any new credentials for this step -- use the client ID and secret from your existing Azure app.

```bash
curl --request POST \
  --url 'https://api.us.nylas.com/v3/connectors/microsoft/creds' \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --data '{
    "name": "Test Microsoft credential",
    "credential_type": "adminconsent",
    "credential_data": {
      "client_id": "<MICROSOFT_CLIENT_ID>",
      "client_secret": "<MICROSOFT_CLIENT_SECRET>",
      "tenant": "<MICROSOFT_TENANT>"
    }
  }'
```

```json
{
  "request_id": "1",
  "data": {
    "id": "<NYLAS_CONNECTOR_CREDENTIAL_ID>",
    "credential_type": "adminconsent",
    "name": "Test Microsoft credential",
    "created_at": 1656082371,
    "updated_at": 1656082371
  }
}
```

Save the `id` from the response. You'll use this `credential_id` in the next steps.

The `tenant` field controls which organizations can use the admin consent URL:

- **`common`** -- the consent URL works for any Microsoft organization. Your app gets the scopes configured in your Azure app's API permissions.
- **A specific tenant ID** -- the consent URL only works for that organization, but you can override scopes in the URL itself.

If you don't define `client_id` and `client_secret`, Nylas uses the credentials from your application's Microsoft connector.

### Step 3: Get admin consent

Send the following [OAuth Authorization URL](/docs/reference/api/authentication-apis/get_oauth2_flow/) to the Microsoft admin at your customer's organization. When they open it, Microsoft prompts them to approve your app's application-level permissions for their tenant. Use the `credential_id` from the previous step.

**If you set `tenant` to `common`** (scopes come from your Azure app's API permissions):

```bash [msConsent-Common tenant]
https://api.us.nylas.com/v3/connect/auth?
provider=microsoft&
redirect_uri=<REDIRECT_URI>&
response_type=adminconsent&
state=<STATE>&
credential_id=<NYLAS_CONNECTOR_CREDENTIAL_ID>&
client_id=<NYLAS_CLIENT_ID>
```

**If you specified a tenant ID** (you can override scopes in the URL):

```bash [msConsent-Specific tenant]
https://api.us.nylas.com/v3/connect/auth?
provider=microsoft&
redirect_uri=<REDIRECT_URI>&
response_type=adminconsent&
state=<STATE>&
credential_id=<NYLAS_CONNECTOR_CREDENTIAL_ID>&
client_id=<NYLAS_CLIENT_ID>&
scope=https%3A%2F%2Fgraph.microsoft.com%2FCalendars.Read%20https%3A%2F%2Fgraph.microsoft.com%2FCalendars.Read.Shared
```

After the admin approves, Nylas redirects to your `redirect_uri` with `admin_consent=true` and the `state` parameter. If the flow fails, Nylas returns an OAuth 2.0 error with `state`, `error`, `error_description`, and `error_uri`.

**Wait at least 5 minutes after admin consent before creating a grant.** Microsoft caches scopes and needs time to propagate the updated permissions.

### Step 4: Create a Microsoft bulk auth grant

Make a [Custom Authentication request](/docs/reference/api/manage-grants/byo_auth/) to create a grant for a specific user's email address.

```bash
curl --request POST \
  --url 'https://api.us.nylas.com/v3/connect/custom' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "provider": "microsoft",
    "settings": {
      "credential_id": "<NYLAS_CONNECTOR_CREDENTIAL_ID>",
      "email_address": "nyla@example.com"
    }
  }'
```

```json
{
  "request_id": "251cac55-10b6-4989-9e03-8f4a9795ca61",
  "data": {
    "id": "<NYLAS_GRANT_ID>",
    "grant_status": "valid",
    "provider": "microsoft",
    "scope": [
      "Directory.Read.All",
      "User.Read.All",
      "Mail.Read",
      "AccessReview.Read.All",
      "Application.Read.All",
      "Mail.ReadWrite",
      "Calendars.Read",
      "AccessReview.ReadWrite.All",
      "Calendars.ReadWrite",
      "Mail.Send"
    ],
    "email": "nyla@example.com",
    "settings": {
      "app_permission": true,
      "app_permission_scopes": [
        "Directory.Read.All",
        "User.Read.All",
        "Mail.Read",
        "AccessReview.Read.All",
        "Application.Read.All",
        "Mail.ReadWrite",
        "Calendars.Read",
        "AccessReview.ReadWrite.All",
        "Calendars.ReadWrite",
        "Mail.Send"
      ],
      "credential_id": "50f7fb25-8af7-49be-a35b-94e1d07c842b",
      "credential_type": "adminconsent"
    },
    "ip": "<IP_ADDRESS>",
    "user_agent": "sensitive_data",
    "created_at": 1749053636,
    "updated_at": 1749053636,
    "provider_user_id": "nyla@example.com",
    "blocked": false
  }
}
```

Repeat this step for each user you want to authenticate. The admin consent you obtained in the previous step covers all users in the tenant.

## Related API references

- [Create Credential](/docs/reference/api/connector-credentials/create_credential/) -- register provider credentials with Nylas
- [List Credentials](/docs/reference/api/connector-credentials/get_credential_all/) -- view credentials for a connector
- [Custom Authentication](/docs/reference/api/manage-grants/byo_auth/) -- create a grant using registered credentials
- [OAuth Authorization](/docs/reference/api/authentication-apis/get_oauth2_flow/) -- generate the admin consent URL for Microsoft
- [List Grants](/docs/reference/api/manage-grants/get-all-grants/) -- view grants associated with your application