# Code examples

Actions are a powerful tool to extend ZITADEL, and you might wonder what use cases actions can be used for.

This page provides a non-exhaustive list of possibilities which is provided by [examples](https://github.com/zitadel/actions/tree/main/examples). If a use case is missing, feel free to contribute an issue or pull request to the repository, thanks in advance 🤗.

## [Customize OIDC response](/content/docs/apis/actions/code-examples#customize-oidc-response/index.html)

Append claims returned on OIDC requests.

### [Triggers](/content/docs/apis/actions/code-examples#triggers/index.html)

- Complement token
  - [Pre Userinfo creation](/content/docs/apis/actions/complement-token#pre-userinfo-creation-id-token-userinfo-introspection-endpoint/index.html)
  - [Pre access token creation](/content/docs/apis/actions/complement-token#pre-access-token-creation/index.html)

### [Set a hardcoded claim](/content/docs/apis/actions/code-examples#set-a-hardcoded-claim/index.html)

Extend the claims by a hardcoded value.

Code example

```javascript
/**
 * Add an additional claim to the token / userinfo, if it's not already present
 *
 * Flow: Complement token, Triggers: Pre Userinfo creation, Pre access token creation
 *
 * @param ctx
 * @param api
 */
function addClaim(ctx, api) {
  api.v1.claims.setClaim('year', 2023)
}
```

### [Set dynamic claim from user metadata](/content/docs/apis/actions/code-examples#set-dynamic-claim-from-user-metadata/index.html)

Extend the claims by dynamically reading metadata from a user and sets the picture-claim if idpPicture-metadata value is present.

Code example

```javascript
/**
 * Set picture claim from IdP picture metadata
 *
 * Flow: Complement token, Trigger: Pre Userinfo creation, Pre access token creation
 *
 * @param ctx
 * @param api
 */
function add_picture_claim_from_idp_metadata(ctx, api) {
  // return if picture already set
  if (ctx.v1.claims && ctx.v1.claims.picture) {
    return;
  }

const metadata = ctx.v1.user.getMetadata();

// assign picture from metadata, if present
  metadata.metadata.forEach(({ key, value: picture }) => {
    if (key === 'idpPicture' && picture) {
      api.v1.claims.setClaim('picture', picture);
    }
  });
}
```

### [Set dynamic claim from organization metadata](/content/docs/apis/actions/code-examples#set-dynamic-claim-from-organization-metadata/index.html)

Extend the claims by dynamically reading metadata from an organization and sets the present metadata.

Code example

```javascript
/**
 * This example demonstrates how to retrieve the organisation metadata.
 * In this case it will be used to set the values as custom claims in the tokens / userinfo and introspection response.
 *
 * Requires: ZITADEL >=v2.45.0
 *
 * Flow: Complement token, Triggers: Pre Userinfo creation, Pre access token creation
 *
 * @param ctx
 * @param api
 */
function setOrgClaims(ctx, api) {
    let metadata = ctx.v1.org.getMetadata()
    if (metadata === undefined || metadata.count == 0) {
        return
    }
    metadata.metadata.forEach(md => {
        api.v1.claims.setClaim('org_claim_'+md.key, md.value);
    })
}
```

### [Custom role mapping in claims](/content/docs/apis/actions/code-examples#custom-role-mapping-in-claims/index.html)

Some products require specific role mapping from ZITADEL, no worries we got you covered 😉

Code example

```javascript
/**
 * sets the roles an additional claim in the token with roles as value an project as key
 *
 * The role claims of the token look like the following:
 *
 * // added by the code below
 * "my:zitadel:grants": ["{projectId}:{roleName}", "{projectId}:{roleName}", ...],
 * // added automatically
 * "urn:zitadel:iam:org:project:roles": {
 *   "asdf": {
 *     "201982826478953724": "zitadel.localhost"
 *   }
 * }
 *
 * Flow: Complement token, Triggers: Pre Userinfo creation, Pre access token creation
 *
 * @param ctx
 * @param api
 */
function flatRoles(ctx, api) {
  if (ctx.v1.user.grants == undefined || ctx.v1.user.grants.count == 0) {
    return;
  }

let grants = [];
  ctx.v1.user.grants.grants.forEach(claim => {
    claim.roles.forEach(role => {
        grants.push(claim.projectId+':'+role)
    })
  })

api.v1.claims.setClaim('my:zitadel:grants', grants)
}
```

### [Custom role mapping including org metadata in claims](/content/docs/apis/actions/code-examples#custom-role-mapping-including-org-metadata-in-claims/index.html)

There's even a possibility to use the metadata of organizations the user is granted to

Code example

```javascript
/**
 * This example demonstrates how to set a custom groups claim using also the organisation metadata of the user grants.
 *
 * Requires: ZITADEL >=v2.51.0
 *
 * Flow: Complement token, Triggers: Pre Userinfo creation, Pre access token creation
 *
 * Assuming there are two organizations:
 *  - ID: 201982826478953724
 *    Domain: zitadel.localhost
 *    Metadata:
 *     - key: crm-id
 *       value: 6d6dee11-31d3-49c3-9087-99216c9cb6f6
 *  - ID: 263022974217486756
 *    Domain: other-org.localhost
 *    Metadata:
 *     - key: crm-id
 *       value: 77b597dc-8a5b-4e55-a6b5-80a6a475c062
 *
 * and the user is granted the `user` role on both organizations, the group claim of the token looks like the following:
 *
 * // added by the code below
 * "groups": ["user:6d6dee11-31d3-49c3-9087-99216c9cb6f6", "user:77b597dc-8a5b-4e55-a6b5-80a6a475c062", ...],
 * // added automatically
 * "urn:zitadel:iam:org:project:roles": {
 *   "user": {
 *     "201982826478953724": "zitadel.localhost",
 *     "263022974217486756": "other-org.localhost"
 *   }
 * }
 *
 * Flow: Complement token, Triggers: Pre Userinfo creation, Pre access token creation
 *
 * @param ctx
 * @param api
 */
function groups(ctx, api) {
    if (ctx.v1.user.grants == undefined || ctx.v1.user.grants.count == 0) {
        return;
    }

let groups = [];
    ctx.v1.user.grants.grants.forEach(grant => {
        let crmId = grant.getOrgMetadata().metadata.find(md => md.key == 'crm-id')
        if (crmId) {
         	grant.roles.forEach(role => {
	            groups.push(role+":"+crmId.value)
            })
        }
    })
    api.v1.claims.setClaim('groups', groups)
}
```

## [Customize SAML response](/content/docs/apis/actions/code-examples#customize-saml-response/index.html)

Append attributes returned on SAML requests.

### [Triggers](/content/docs/apis/actions/code-examples#triggers/index.html)

- Complement SAMLResponse
  - [Pre SAMLResponse creation](/content/docs/apis/actions/customize-samlresponse#pre-saml-response-creation/index.html)

### [Custom role mapping in attributes](/content/docs/apis/actions/code-examples#custom-role-mapping-in-attributes/index.html)

Some products require specific role mapping from ZITADEL, no worries we got you covered 😉

Code example

```javascript
/**
 * Add an custom attribute to the SAMLResponse, if it's not already present.
 * This example will add the resourceOwner as custom attribute `OrgID`.
 * It additionally shows how get the user's project authorization and add each role in the form of `projectId:role` as a `Roles` attribute.
 *
 * Flow: Complement SAMLResponse, Triggers: Pre SAMLResponse creation
 *
 * @param ctx
 * @param api
 */
function setCustomAttribute(ctx, api) {
    const user = ctx.v1.getUser()
    api.v1.attributes.setCustomAttribute('OrgID', '', user.resourceOwner)

if (ctx.v1.user.grants == undefined || ctx.v1.user.grants.count == 0) {
        return;
    }
    let roles = [];
    ctx.v1.user.grants.grants.forEach(grant => {
        grant.roles.forEach(role => {
            roles.push(grant.projectId+':'+role)
        })
    })
    api.v1.attributes.setCustomAttribute('Roles', '', ...roles)
  }
```

### [Set dynamic attribute from organization metadata](/content/docs/apis/actions/code-examples#set-dynamic-attribute-from-organization-metadata/index.html)

Extend the attributes by dynamically reading metadata from an organization and sets the present metadata.

Code example

```javascript
/**
 * This example demonstrates how to retrieve the organisation metadata.
 * In this case it will be used to set the values as custom attributes on the SAML response.
 *
 * Requires: ZITADEL >=v2.45.0
 *
 * Flow: Complement SAMLResponse, Triggers: Pre SAMLResponse creation
 *
 * @param ctx
 * @param api
 */
function setOrgAttribute(ctx, api) {
    let metadata = ctx.v1.org.getMetadata()
    if (metadata === undefined || metadata.count == 0) {
        return
    }
    metadata.metadata.forEach(md => {
        api.v1.attributes.setCustomAttribute('org_attribute_'+md.key,'', md.value);
    })
}
```

## [Manipulate user](/content/docs/apis/actions/code-examples#manipulate-user/index.html)

You can automate manual tasks such as assigning default roles during user creation.

### [Set email always verified](/content/docs/apis/actions/code-examples#set-email-always-verified/index.html)

Useful if you trust the provided information or don't want the users to verify their e-mail addresses.

#### [Triggers](/content/docs/apis/actions/code-examples#triggers/index.html)

- Internal Authentication
  - [Pre Creation](/content/docs/apis/actions/internal-authentication#pre-creation/index.html)
- External Authentication
  - [Pre Creation](/content/docs/apis/actions/external-authentication#pre-creation/index.html)

Code example

```javascript
/**
 * Set verified email of a user to true.
 * Useful if external identity provider doesn't send email verified attribute or you like to add all users with a verified email.
 *
 * Flow: Internal Authentication or External Authentication, Trigger: Pre Creation
 *
 * @param ctx
 * @param api
 */
function setEmailVerified(ctx, api) {
    api.setEmailVerified(true)
}
```

### [Assign roles to users](/content/docs/apis/actions/code-examples#assign-roles-to-users/index.html)

Allows you to assign default roles to a user after the user was created or federated.

#### [Triggers](/content/docs/apis/actions/code-examples#triggers/index.html)

- Internal Authentication
  - [Post Creation](/content/docs/apis/actions/internal-authentication#post-creation/index.html)
- External Authentication
  - [Post Creation](/content/docs/apis/actions/external-authentication#post-creation/index.html)

Code example

```javascript
/**
 * Add a usergrant to a new created/registered user
 *
 * Flow: Internal Authentication or External Authentication, Trigger: Post creation
 *
 * @param ctx
 * @param api
 */
function addGrant(ctx, api) {
    api.userGrants.push({
        projectID: '<the projects resource ID>',
        roles: ['<the role key>']
    });
}
```

### [Add metadata to users](/content/docs/apis/actions/code-examples#add-metadata-to-users/index.html)

Adding metadata to users allows you to set default metadata on users.

#### [Triggers](/content/docs/apis/actions/code-examples#triggers/index.html)

- Internal Authentication
  - [Pre Creation](/content/docs/apis/actions/internal-authentication#pre-creation/index.html)
  - [Post Authentication](/content/docs/apis/actions/internal-authentication#post-authentication/index.html)
- External Authentication
  - [Pre Creation](/content/docs/apis/actions/internal-authentication#pre-creation/index.html)
  - [Post Authentication](/content/docs/apis/actions/internal-authentication#post-authentication/index.html)

Code example

```javascript
/**
 * Add metadata if metadata are available
 *
 * Flow: External Authentication or Internal Authentication, Trigger: Pre Creation, Post Authentication
 *
 * @param ctx
 * @param api
 */
function add_metadata(ctx, api) {
  if (api.metadata === undefined) {
    return;
  }

api.v1.user.appendMetadata('add', 'me');
}
```

## [Use provided fields of identity providers](/content/docs/apis/actions/code-examples#use-provided-fields-of-identity-providers/index.html)

If you want to ensure that the data of a user are always up to date, you can automatically update user fields during authentication and save time of your customers and your team.

### [Trigger](/content/docs/apis/actions/code-examples#trigger/index.html)

- External Authentication
  - [Post Authentication](/content/docs/apis/actions/external-authentication#post-authentication/index.html)

### [Fields provided by Okta as OIDC IdP](/content/docs/apis/actions/code-examples#fields-provided-by-okta-as-oidc-id-p/index.html)

If you use [Okta as an identity provider](/content/docs/guides/integrate/identity-providers/okta-oidc/index.html), you can improve the onboarding experience of new users by prefilling some basic information during authentication.

Code example

```javascript
/**
 * Set first and lastname of a user on just in time provisioning for okta.
 * Useful if you like to fill the first and lastname with the name stored on okta, so the user doesn't have to fill himself.
 * Also set email to verified, so the user doesn't get a verification email
 *
 * Flow: External Authentication, Trigger: Post Authentication
 *
 * @param ctx
 * @param api
 */
let logger = require("zitadel/log")

function mapOktaOauth(ctx, api) {
  logger.log('Populating extra information for new Okta user');

if (ctx.v1.externalUser.externalIdpId != "your-idp-id") {
    return
  }
  api.setFirstName(ctx.v1.providerInfo.name);
  api.setLastName(ctx.v1.providerInfo.name);
  api.setEmailVerified(true)
  api.setEmail(ctx.v1.providerInfo.email)
  api.setPreferredUsername(ctx.v1.providerInfo.preferred_username)
}
```

### [Fields provided by Gitlab](/content/docs/apis/actions/code-examples#fields-provided-by-gitlab/index.html)

If you use [Gitlab as an identity provider](/content/docs/guides/integrate/identity-providers/gitlab/index.html), you can improve the onboarding experience of new users by prefilling some basic information during authentication.

Code example

```javascript
/**
 * Set first and lastname of a user on just in time provisioning for gitlab.
 * Useful if you like to fill the first and lastname with the name stored on gitlab, so the user doesn't have to fill himself.
 *
 * Flow: External Authentication, Trigger: Post Authentication
 *
 * @param ctx
 * @param api
 */
function mapGitLabOAuth(ctx, api) {
  if (ctx.v1.externalUser.externalIdpId != "your-idp-id") {
    return
  }
  api.setFirstName(ctx.v1.providerInfo.name);
  api.setLastName(ctx.v1.providerInfo.name);
}
```

### [Fields provided by GitHub](/content/docs/apis/actions/code-examples#fields-provided-by-git-hub/index.html)

If you use [GitHub as an identity provider](/content/docs/guides/integrate/identity-providers/github/index.html), you can improve the onboarding experience of new users by prefilling some basic information during authentication.

Code example

```javascript
/**
 * Set first and lastname of a user on just in time provisioning for github.
 * Useful if you like to fill the first and lastname with the name stored on github, so the user doesn't have to fill himself.
 *
 * Flow: External Authentication, Trigger: Post Authentication
 *
 * @param ctx
 * @param api
 */
function mapGitHubOAuth(ctx, api) {

if (ctx.v1.externalUser.externalIdpId != "your-idp-id") {
    return
  }
  api.setFirstName(ctx.v1.providerInfo.name);
  api.setLastName(ctx.v1.providerInfo.name);
}
```

### [Claims provided by a generic OIDC identity provider](/content/docs/apis/actions/code-examples#claims-provided-by-a-generic-oidc-identity-provider/index.html)

If you use a [generic OIDC identity provider](/content/docs/guides/integrate/identity-providers/migrate#migrate-generic-oidc-provider/index.html), you can improve the onboarding experience of new users by prefilling some basic information during authentication.

Code example

```javascript
/**
 * Set IdP picture as metadata
 *
 * Flow: External Authentication, Trigger: Post authentication
 *
 * @param ctx
 * @param api
 */
function set_idp_picture_metadata(ctx, api) {
  // for production use cases, implement logging or alerting here to ensure traceability

// return if api undefined
  if (api === undefined) {
    return;
  }

const picture = ctx.getClaim('picture');

if (picture !== null) {
    api.v1.user.appendMetadata('idpPicture', picture);
  }
}
```

### [Attributes provided by Okta as SAML IDP](/content/docs/apis/actions/code-examples#attributes-provided-by-okta-as-saml-idp/index.html)

If you use [Okta as an identity provider](/content/docs/guides/integrate/identity-providers/okta_saml#add-attribute-statements/index.html), you can improve the onboarding experience of new users by prefilling some basic information during authentication.

Code example

```javascript
/**
 * Use SAML attributes from OKTA SAML SP as attributes for user creation/update
 *
 * Flow: External Authentication, Trigger: Post authentication
 *
 * @param ctx
 * @param api
 */
function prefilRegisterFromOKTASAML(ctx, api) {
	if (ctx.v1.externalUser.externalIdpId != "<SAML IDP ID>") {
        return
    }
    // the attribute names below represent a attribute statement with basic format (configured in OKTA App)
    let firstname = ctx.v1.providerInfo.attributes["givenname"];
    let lastname = ctx.v1.providerInfo.attributes["surname"];
    let email = ctx.v1.providerInfo.attributes["emailaddress"];
    let username = ctx.v1.providerInfo.attributes["emailaddress"];
    if (firstname != undefined) {
     api.setFirstName(firstname[0]);
    }
    if (lastname != undefined) {
	    api.setLastName(lastname[0]);
    }
    if (email != undefined) {
     api.setEmail(email[0]);
	    api.setEmailVerified(true);
    }
    if (username != undefined) {
	    api.setPreferredUsername(username[0]);
    }
}
```

### [Attributes provided by Microsoft Entra as SAML IDP](/content/docs/apis/actions/code-examples#attributes-provided-by-microsoft-entra-as-saml-idp/index.html)

If you use [Microsoft Entra as SAML identity provider](/content/docs/guides/integrate/identity-providers/azure-ad-saml/index.html), you can improve the onboarding experience of new users by prefilling some basic information during authentication.

Code example

```javascript
/**
 * Use SAML attributes from entra id SAML SP as attributes for user creation/update
 *
 * Flow: External Authentication, Trigger: Post authentication
 *
 * @param ctx
 * @param api
 */
function prefilRegisterFromEntraId(ctx, api) {
	if (ctx.v1.externalUser.externalIdpId != "<SAML SP id>") {
        return
    }
    // the attribute names below represent the crewjam IDP example, be sure to update them to match your provider info
    let firstname = ctx.v1.providerInfo.attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"];
    let lastname = ctx.v1.providerInfo.attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"];
    let email = ctx.v1.providerInfo.attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"];
    let displayname = ctx.v1.providerInfo.attributes["http://schemas.microsoft.com/identity/claims/displayname"];
    // username would look like this: adlerhurst_zitadel.com#EXT#@adlerhurstzitadel.onmicrosoft.com
    let username = ctx.v1.providerInfo.attributes["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"];
    if (firstname != undefined) {
     api.setFirstName(firstname[0]);
    }
    if (lastname != undefined) {
	    api.setLastName(lastname[0]);
    }
    if (email != undefined) {
     api.setEmail(email[0]);
	    api.setEmailVerified(true);
    }
    if (displayname != undefined) {
	    api.setDisplayName(displayname[0]);
    }
    if (username != undefined) {
	    api.setPreferredUsername(username[0]);
    }
}
```

### [Attributes provided by a generic SAML identity provider](/content/docs/apis/actions/code-examples#attributes-provided-by-a-generic-saml-identity-provider/index.html)

If you use a [SAML identity provider like mocksaml](/content/docs/guides/integrate/identity-providers/mocksaml/index.html), you can improve the onboarding experience of new users by prefilling some basic information during authentication.

Code example

```javascript
/**
 * Use SAML attributes from external IDP as attributes for user creation/update
 *
 * Flow: External Authentication, Trigger: Post authentication
 *
 * @param ctx
 * @param api
 */
function map(ctx, api) {
    if (ctx.v1.externalUser.externalIdpId != "your_external_idp") {
        return
    }
    // the attribute names below represent the crewjam IDP example, be sure to update them to match your provider info
    let firstname = ctx.v1.providerInfo.attributes["urn:oid:2.5.4.42"];
    let lastname = ctx.v1.providerInfo.attributes["urn:oid:2.5.4.4"];
    let email = ctx.v1.providerInfo.attributes["urn:oid:1.3.6.1.4.1.5923.1.1.1.6"];
    let displayname = ctx.v1.providerInfo.attributes["urn:oid:2.5.4.3"];
    let username = ctx.v1.providerInfo.attributes["urn:oid:0.9.2342.19200300.100.1.1"];
    if (firstname != undefined) {
     api.setFirstName(firstname[0]);
    }
    if (lastname != undefined) {
	    api.setLastName(lastname[0]);
    }
    if (email != undefined) {
     api.setEmail(email[0]);
     api.setEmailVerified(true);
    }
    if (displayname != undefined) {
	    api.setDisplayName(displayname[0]);
    }
    if (username != undefined) {
	    api.setPreferredUsername(username[0]);
    }
}
```

## [Context-aware execution](/content/docs/apis/actions/code-examples#context-aware-execution/index.html)

Based on the context, the execution path of an action can change. ZITADEL allows complex execution paths, of course. 😎

### [Based on auth request information](/content/docs/apis/actions/code-examples#based-on-auth-request-information/index.html)

Execution paths might change based on the application initiating the authentication.

#### [Triggers](/content/docs/apis/actions/code-examples#triggers/index.html)

- Internal Authentication
  - [Pre Creation](/content/docs/apis/actions/internal-authentication#pre-creation/index.html)
  - [Post Creation](/content/docs/apis/actions/internal-authentication#post-creation/index.html)
  - [Post Authentication](/content/docs/apis/actions/internal-authentication#post-authentication/index.html)
- External Authentication
  - [Pre Creation](/content/docs/apis/actions/external-authentication#pre-creation/index.html)
  - [Post Creation](/content/docs/apis/actions/external-authentication#post-creation/index.html)
  - [Post Authentication](/content/docs/apis/actions/external-authentication#post-authentication/index.html)

Code example

```javascript
/**
 * Logs if the app is console
 * Useful if you like to execute an action for specific apps
 *
 * Flows:
 *
 *  - Internal Authentication, Triggers: Pre Creation, Post Creation, Post Authentication
 *  - External Authentication, Triggers: Pre Creation, Post Creation, Post Authentication
 *
 * @param ctx
 * @param api
 */
let logger = require('zitadel/log');

function logConsole(ctx, api) {
    if (ctx.v1.authRequest == undefined || ctx.v1.authRequest.applicationId == '') {
        logger.log('🤖 No auth request or app id provided');
        return;
    }
    if (ctx.v1.authRequest.applicationId == 'your-zitadel-console--client-id') {
        logger.log('🤖 authentication with console');
        return;
    }
    logger.log('🤖 authentication with another app: ' + ctx.v1.authRequest.applicationId);
}
```

This example uses [zitadel's log module](/content/docs/apis/actions/modules#log/index.html)

### [Check authentication error](/content/docs/apis/actions/code-examples#check-authentication-error/index.html)

Your action can also check for errors during the login process.

#### [Triggers](/content/docs/apis/actions/code-examples#triggers/index.html)

- Internal Authentication
  - [Post Authentication](/content/docs/apis/actions/internal-authentication#post-authentication/index.html)
- External Authentication
  - [Post Authentication](/content/docs/apis/actions/external-authentication#post-authentication/index.html)

Code example

```javascript
/**
 * Log successful and failed authentications with relevant information
 *
 * Flow: External/Internal Authentication, Trigger: Post authentication
 *
 * @param ctx
 * @param api
 */
let logger = require("zitadel/log")
function log(ctx, api) {
    if (ctx.v1.authError == "none") {
        logger.log("successful login: username/" + ctx.v1.authRequest.userName + ", timestamp/" + ctx.v1.authRequest.changeDate + ", appID/" + ctx.v1.authRequest.applicationId + ", remoteAddr/" + ctx.v1.httpRequest.remoteAddr + ", request/" + JSON.stringify(ctx.v1.httpRequest))
    } else {
        logger.log("authentication failed: error/" + ctx.v1.authError + ", username/" + ctx.v1.authRequest.userName + ", timestamp/" + ctx.v1.authRequest.changeDate + ", appID/" + ctx.v1.authRequest.applicationId + ", remoteAddr/" + ctx.v1.httpRequest.remoteAddr + ", request/" + JSON.stringify(ctx.v1.httpRequest))
    }
}
```

This example uses [zitadel's log module](/content/docs/apis/actions/modules#log/index.html)

### [Throw an error](/content/docs/apis/actions/code-examples#throw-an-error/index.html)

Allows you to limit the user interaction. The error thrown will be shown to the user if the action is not [allowed to fail](/content/docs/concepts/features/actions#how-it-works/index.html).

Code example

```javascript
/**
 * Returns an error
 * The error looks as follows in the login ui:
 * some error at err (:9:2(2))
 *
 * Flow: all flows
 */
function err(ctx, api) {
	throw "some error"
}
```
