> ## Documentation Index
> Fetch the complete documentation index at: https://auth0-actions-modules-ga.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Install the official @auth0/actions NPM package as a dev dependency to add TypeScript type definitions, IntelliSense, and error checking when writing and unit testing Auth0 Actions by trigger and version in external editors.

# Write Your Action Using Your Code Editor

***

Use the [`@auth0/actions`](https://www.npmjs.com/package/@auth0/actions) NPM package to write and unit test your Actions in your own code editor or IDE, with full IntelliSense, type checking, and error checking.

<Steps>
  <Step title="Install the package" titleSize="h3" stepNumber={1}>
    Use one of the following package managers to install the package:

    <Tabs>
      <Tab title="NPM">
        <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
          Use `--save-dev` while installing the package to indicate that it's a development dependency to supplement your development tools.
        </Callout>

        ```bash theme={null}
        npm install @auth0/actions --save-dev
        ```
      </Tab>

      <Tab title="Yarn">
        <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
          Use `--dev` while installing the package to indicate that it's a development dependency to supplement your development tools.
        </Callout>

        ```bash theme={null}
        yarn add @auth0/actions --dev
        ```
      </Tab>

      <Tab title="Pnpm">
        <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
          Use `--save-dev` while installing the package to indicate that it's a development dependency to supplement your development tools.
        </Callout>

        ```bash theme={null}
        pnpm add @auth0/actions --save-dev
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Import the type definitions" titleSize="h3" stepNumber={2}>
    Use one of the following alternatives to import the TypeScript definitions into your Actions depending on your technology:

    <Tabs>
      <Tab title="JSDocs @import">
        Use this alternative when you want IntelliSense without changing your existing JavaScript code structure:

        ```javascript theme={null}
        /** @import {Event, PostLoginAPI} from "@auth0/actions/post-login/v3" */

        /**
        * Handler that will be called during the execution of a PostLogin flow.
        *
        * @param {Event} event - Details about the user and the context in which they are logging in.
        * @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
        */
        exports.onExecutePostLogin = async (event, api) => {
          // Your code
        }
        ```
      </Tab>

      <Tab title="JSDocs @param">
        Use this alternative for type safety in JavaScript files using import statements in JSDoc comments:

        ```javascript theme={null}
        /**
        * Handler that will be called during the execution of a PostLogin flow.
        *
        * @param {import('@auth0/actions/post-login/v3').Event} event - Details about the user and the context in which they are logging in.
        * @param {import('@auth0/actions/post-login/v3').PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
        */
        exports.onExecutePostLogin = async (event, api) => {
            // Your code
        };
        ```
      </Tab>

      <Tab title="TS types import">
        Use this alternative when developing with TypeScript for full type checking and modern syntax:

        ```javascript theme={null}
        import type { Event, PostLoginAPI } from '@auth0/actions/post-login/v3';

        /**
        * Handler that will be called during the execution of a PostLogin flow.
        *
        * @param {Event} event - Details about the user and the context in which they are logging in.
        * @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
        */
        exports.onExecutePostLogin = async (event: Event, api: PostLoginAPI) => {
          // Your code
        };
        ```
      </Tab>
    </Tabs>

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      The import statement should be based on each **trigger name** and **version number** considering the [library structure](#library-structure).

      **Follow the pattern**: `@auth0/actions/[trigger_name]/[trigger_version]`

      **For example**: `@auth0/actions/post-login/v3`
    </Callout>

    <Accordion title="Library structure">
      ```bash theme={null}
      @auth0/actions
      │
      └───credentials-exchange
      │   └───v1
      │   └───v2
      └───custom-email-provider
      │   └───v1
      └───custom-phone-provider
      │   └───v1
      └───custom-token-exchange
      │   └───v1
      └───event-stream
      │   └───v1
      └───password-reset-post-challenge
      │   └───v1
      └───post-change-password
      │   └───v1
      │   └───v2
      └───post-login
      │   └───v1
      │   └───v2
      │   └───v3
      └───post-user-registration
      │   └───v1
      │   └───v2
      └───pre-user-registration
      │   └───v1
      │   └───v2
      └───send-phone-message
          └───v1
          └───v2
      ```
    </Accordion>
  </Step>

  <Step title="Configure your project" titleSize="h3" stepNumber={3}>
    The following configuration examples are intentionally presented in both JavaScript and TypeScript to provide a direct, side-by-side comparison.

    <Tabs>
      <Tab title="JavaScript">
        In your `package.json`, define any development dependencies to have intelliSense help when writing your Action:

        ```json theme={null}
        {
          "name": "actions-js",
          "version": "1.0.0",
          "description": "Actions JS",
          "main": "example.js",
          "author": "John Doe",
          "license": "ISC",
          "devDependencies": {
            "@auth0/actions": "^0.32.0"
          }
        }
        ```
      </Tab>

      <Tab title="TypeScript">
        In your `package.json`, define any development dependencies to have intelliSense help when writing your Action.

        ```json theme={null}
        {
          "name": "actions-ts",
          "version": "1.0.0",
          "description": "Actions TS",
          "main": "example.ts",
          "author": "John Doe",
          "license": "ISC",
          "devDependencies": {
            "@auth0/actions": "^0.32.0",
            "@types/node": "22.14.0",
            "typescript": "^5.9.2"
          }
        }
        ```

        In your `tsconfig.json`, define any development dependencies to have intelliSense help when writing your Action.

        ```json theme={null}
        {
          "compilerOptions": {
            "target": "ES2020",
            "module": "NodeNext",
            "moduleResolution": "nodenext",
            "esModuleInterop": true,
            "allowSyntheticDefaultImports": true,
            "strict": true,
            "outDir": "dist",
            "declaration": true,
            "sourceMap": true,
            "allowJs": true,
            "checkJs": false,
            "resolveJsonModule": true,
            "skipLibCheck": true,
            "forceConsistentCasingInFileNames": true,
            "isolatedModules": true
          },
          "include": [
            "**/*.ts"
          ],
          "exclude": [
            "node_modules",
            "dist"
          ]
        }
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Write your Action code" titleSize="h3" stepNumber={4}>
    The following example Action would execute during the Post-Login flow. It checks if the user has roles assigned, and calls `api.access.deny()` if none are found. If roles are present, it proceeds to set the custom claim on the ID token.

    The import statement declares the availability of external types to your code. This allows the editor to know the structure of the `event` and `api` objects.

    <Tabs>
      <Tab title="JavaScript">
        ```javascript theme={null}
        /** @import {Event, PostLoginAPI} from "@auth0/actions/post-login/v3" */

        const CUSTOM_CLAIM_NAMESPACE = 'https://example.com';

        /**
        * Handler that will be called during the execution of a PostLogin flow.
        *
        * @param {Event} event - Details about the user and the context in which they are logging in.
        * @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
        */
        exports.onExecutePostLogin = async (event, api) => {
          const roles = event.authorization?.roles;

          if (roles === undefined || roles.length === 0) {
            api.access.deny('Restricted');
            return;
          }

          api.idToken.setCustomClaim(`${CUSTOM_CLAIM_NAMESPACE}/roles`, roles);
        }
        ```
      </Tab>

      <Tab title="TypeScript">
        ```javascript theme={null}
        import type { Event, PostLoginAPI } from '@auth0/actions/post-login/v3';

        const CUSTOM_CLAIM_NAMESPACE = 'https://example.com';

        /**
        * Handler that will be called during the execution of a PostLogin flow.
        *
        * @param {Event} event - Details about the user and the context in which they are logging in.
        * @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
        */
        exports.onExecutePostLogin = async (event: Event, api: PostLoginAPI) => {
          const roles = event.authorization?.roles;

          if (roles === undefined || roles.length === 0) {
            api.access.deny('Restricted');
            return;
          }

          api.idToken.setCustomClaim(`${CUSTOM_CLAIM_NAMESPACE}/roles`, roles);
        };
        ```

        <Warning>
          When using TypeScript, you must compile your code to JavaScript before deploying to Auth0. The Auth0 Actions runtime only executes JavaScript. Use the TypeScript compiler (`tsc`) to transpile your `.ts` files to `.js` files, before it can be deployed. You must also include JSDoc comments to enable IntelliSense in the Dashboard.
        </Warning>
      </Tab>
    </Tabs>
  </Step>
</Steps>

<Check>
  **Checkpoint**

  You should now have a working Action, written and type-checked in your own code editor, ready to be deployed to Auth0.
</Check>
