> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.com/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.

### 1. Install the package

Use one of the following package managers to install the package:

**NPM**

Use `--save-dev` while installing the package to indicate that it's a development dependency to supplement your development tools.

```bash title="install-npm.sh" theme={null}
npm install @auth0/actions --save-dev
```

**Yarn**

Use `--dev` while installing the package to indicate that it's a development dependency to supplement your development tools.

```bash title="install-yarn.sh" theme={null}
yarn add @auth0/actions --dev
```

**Pnpm**

Use `--save-dev` while installing the package to indicate that it's a development dependency to supplement your development tools.

```bash title="install-pnpm.sh" theme={null}
pnpm add @auth0/actions --save-dev
```

### 2. Import the type definitions

Use one of the following alternatives to import the TypeScript definitions into your Actions depending on your technology:

**JSDocs @import**

Use this alternative when you want IntelliSense without changing your existing JavaScript code structure:

```js title="jsdocs-import.js" 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
}
```

**JSDocs @param**

Use this alternative for type safety in JavaScript files using import statements in JSDoc comments:

```js title="jsdocs-param.js" 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
};
```

**TS types import**

Use this alternative when developing with TypeScript for full type checking and modern syntax:

```ts title="types-import.ts" 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
};
```

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`

> **Library structure**
>
> **@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**

### 3. Configure your project

The following configuration examples are intentionally presented in both JavaScript and TypeScript to provide a direct, side-by-side comparison.

**JavaScript**

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

```json title="package.json" theme={null}
{
  "name": "actions-npm-example-js",
  "version": "1.0.0",
  "description": "Auth0 Actions npm dependency example using JavaScript",
  "main": "example.js",
  "author": "Auth0",
  "license": "MIT",
  "devDependencies": {
    "@auth0/actions": "^0.33.0"
  }
}
```

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

```json title="jsconfig.json" theme={null}
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "checkJs": false,
    "baseUrl": ".",
    "paths": {
      "actions:*": ["src/*"]
    }
  },
  "include": ["src/**/*.js"]
}

```

**TypeScript**

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

```json title="package.json" theme={null}
{
  "name": "actions-npm-example-ts",
  "version": "1.0.0",
  "description": "Auth0 Actions npm dependency example using TypeScript",
  "main": "example.ts",
  "author": "Auth0",
  "license": "MIT",
  "devDependencies": {
    "@auth0/actions": "^0.33.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 title="tsconfig.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,
    "noEmit": true,
    "paths": {
      "actions:*": ["./src/*"]
    }
  },
  "exclude": [
    "node_modules",
    "dist"
  ],
  "include": [
    "**/*.ts"
  ],
  "ts-node": {
    "transpileOnly": true
  }
}

```

### 4. Write your Action code

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.

**JavaScript**

```js title="example.js" 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);
}
```

**TypeScript**

```ts title="example.ts" 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.

> [!TIP]
>
> **Checkpoint**
>
> You should now have a working Action, written and type-checked in your own code editor, ready to be deployed to Auth0.
