You can trigger functions in response to the creation and deletion of
Firebase Authentication user accounts. For example, you could send a welcome email to
a user who has just created an account in your app. Examples on this page are
based on a sample that does exactly this---sends welcome and farewell emails
upon account creation and deletion.

> [!WARNING]
> **Preview:** The triggers described in this guide are in a **Preview** release. This means that the functionality might change in backward-incompatible ways or have limited support. A preview release is not subject to any SLA or deprecation policy.

For more examples of use cases, see
[What can I do with Cloud Functions?](https://firebase.google.com/docs/functions/use-cases.md.txt).

## Trigger a function on user creation

You can create a function that triggers when an Authentication user is created using
the
[`onUserCreated`](https://firebase.google.com/docs/reference/functions/2nd-gen/node/firebase-functions.identity.md.txt#identityonusercreated)
event handler from the `firebase-functions/v2/identity` subpackage:

<br />

```
const { onUserCreated } = require("firebase-functions/identity");
const { defineSecret } = require("firebase-functions/params");
const { logger } = require("firebase-functions");
const { sendWelcomeEmail } = require("./utils/myEmailService");

const emailApiKey = defineSecret("EMAIL_API_KEY");

exports.newUserWelcome = onUserCreated(
  { secrets: [emailApiKey] },
  async (event) => {
    const { uid, email, displayName } = event.data;

    if (!email) {
      logger.log(`User ${uid} does not have an email address.`);
      return;
    }

    await sendWelcomeEmail(email, displayName);
  },
);
```

<br />

Authentication accounts will trigger user creation events for Cloud Functions
when:

- A user creates an email account and password.
- A user signs in for the first time using a federated identity provider.
- The developer creates an account using the Admin SDK.
- A user signs in to a new anonymous auth session for the first time.

A Cloud Functions event is *not* triggered when a user signs in for the
first time using a custom token.

### Configure trigger options and multi-tenancy

You can configure your function by passing an options object (`AuthOptions`) as
the first parameter to `onUserCreated`:

<br />

```
/**
 * Sends a welcome email scoped to a specific tenant in Identity Platform.
 */
exports.sendWelcomeEmailToTenant = onUserCreated(
  {
    secrets: [emailApiKey],
    // Only trigger when a user is a member of this tenant
    tenantId: "my-tenant-id",
  },
  async (event) => {
    const { uid, email, displayName } = event.data;
    // Customize the email for this tenant
    await sendWelcomeEmail(email, displayName, event.tenantId);
  },
);
  /**
 * Sends a welcome email only to users not associated with any tenant.
 */
exports.sendWelcomeEmailNoTenant = onUserCreated(
  {
    secrets: [emailApiKey],
    // Only trigger when a user is NOT a member of a tenant
    tenantId: IS_NOT_TENANT,
  },
  async (event) => {
    const { email, displayName } = event.data;

    // Send a generic welcome email
    await sendWelcomeEmail(email, displayName);
  },
);
```

<br />

If your project uses [Identity Platform multi-tenancy](https://cloud.google.com/identity-platform/docs/multi-tenancy),
you can scope the trigger:

- **Default project (no tenant)** : Set `tenantId` to `IS_NOT_TENANT` to listen only for users created in the default project.
- **Specific tenant** : Provide the string ID of the tenant (for example, `{ tenantId: "tenant-id-1" }`) to listen only for users created in that tenant.
- **All tenants and users** : If `tenantId` is omitted, the function triggers on user creation events across all tenants and default project users in the project.

In addition to `tenantId`, you can specify standard 2nd gen configuration
options including `region`, `concurrency`, `cpu`, `memory`, `timeoutSeconds`,
`minInstances`, `maxInstances`, and `secrets`.

### Access user attributes

From the user data returned to your function, you can access the list of user
attributes available in the newly created user's
[`UserRecord`](https://firebase.google.com/docs/reference/admin/node/firebase-admin.auth.userrecord.md.txt)
object via `event.data`. For example, you can get the user's email and display
name as shown:

<br />

```
const { uid, email, displayName } = event.data;
```

<br />

Authentication triggers in 2nd gen receive an
[`AuthEvent`](https://firebase.google.com/docs/reference/functions/2nd-gen/node/firebase-functions.identity.authevent.md.txt)
object. In addition to `event.data`, you can access event metadata such as:

- `event.id`: A unique identifier for the event.
- `event.type`: The event type (`google.firebase.auth.user.v2.created`).
- `event.time`: An ISO 8601 timestamp representing when the event occurred.
- `event.project`: The Google Cloud project ID.
- `event.tenantId`: The Identity Platform tenant ID associated with the user, if applicable.

> [!NOTE]
> **Note:** To support [migration from 1st gen](https://firebase.google.com/docs/functions/2nd-gen-upgrade.md.txt), 2nd gen also supports 1st gen compatibility destructuring (`const { user, context } = event;`).

## Trigger a function on user deletion

Just as you can trigger a function on user creation, you can respond to user
deletion events. Use the
[`onUserDeleted`](https://firebase.google.com/docs/reference/functions/2nd-gen/node/firebase-functions.identity.md.txt#identityonuserdeleted)
event handler from `firebase-functions/v2/identity` as shown:

<br />

```
const { onUserDeleted } = require("firebase-functions/identity");
const { defineSecret } = require("firebase-functions/params");
const { logger } = require("firebase-functions");
const { sendGoodbyeEmail } = require("./utils/myEmailService");

const emailApiKey = defineSecret("EMAIL_API_KEY");

exports.deletedUserFarewell = onUserDeleted(
  { secrets: [emailApiKey] },
  async (event) => {
    const { uid, email, displayName } = event.data;
    if (!email) {
      logger.log(`User ${uid} does not have an email address.`);
      return;
    }

    await sendGoodbyeEmail(email, displayName);
  },
);
```

<br />

As with `onUserCreated`, you can configure `onUserDeleted` with options like
`{ tenantId: IS_NOT_TENANT }` to restrict triggers to users in the default
project.

> [!CAUTION]
> **Caution:** Deleting multiple users at once using the Firebase Admin SDK (for example, `admin.auth().deleteUsers([uid1, uid2])` in Node.js) does not fire user deletion events, so event handlers set up using `onUserDeleted` *will not be triggered*. Delete users one at a time if you want user deletion events to fire for each deleted user.

## Trigger blocking functions

If you've upgraded to Firebase Authentication with Identity Platform, you can extend Firebase Authentication using
[blocking functions](https://firebase.google.com/docs/functions/auth-blocking-events.md.txt).

Blocking functions let you execute custom code synchronously that modifies the
result of a user registering or signing in to your app. Unlike background
triggers, which run asynchronously after an event has finished, blocking
functions allow you to prevent a user from authenticating if they don't meet
certain criteria, or update a user's information and claims before returning it
to your client app.

## Best practices for 2nd gen triggers

When implementing 2nd gen authentication triggers, keep the following best
practices in mind:

- **Account for concurrency**: Cloud Functions (2nd gen) instances process concurrent requests (defaulting to 80 concurrent requests when CPU ≥ 1). Ensure that your function does not rely on global mutable state between concurrent executions.
- **Design for idempotency**: Event delivery in 2nd gen is at-least-once via Eventarc. Ensure that your functions are idempotent; for example, verify that a welcome email has not already been sent or a database entry initialized before performing side effects.
- **Scope multi-tenant functions** : If your application uses Identity Platform multi-tenancy, verify whether your functions should handle events across all tenants or only specific ones. Use `tenantId: IS_NOT_TENANT` to prevent tenant users from triggering functions intended only for the primary project.
- **Manage regions and resource allocation** : Specify the function location (`region`) to minimize network latency between your authentication provider and your function execution environment.