close icon
Pulumi

Provisioning Auth0 resources with TypeScript and Pulumi

Use Pulumi to provision Auth0 resources using your familiar programming languages

September 30, 2022

Pulumi is a fantastic solution for IaC (Infrastructure as Code). It allows you to manage your cloud services with high-level SDKs for popular programming languages like TypeScript, C#, GoLang, and Python. The familiarity and characteristics of those programming languages make it easier to set up, maintain and write code for your cloud services, including your friendly authentication provider Auth0.

This blog post will show you how to provision Auth0 resources using TypeScript and Pulumi. We will use the Pulumi tool to create and manage our infrastructure as code which is a great way to keep your infrastructure in a safe, version-controlled repository.

Let's get started!

What Is Pulumi

Pulumi

Managing your cloud infrastructure can be a daunting task. When even automated, you need to learn a new programming language (or multiple languages) to write code for your cloud services.

Pulumi is a tool that enables developers to write code for their cloud services using familiar programming languages like TypeScript, C#, GoLang, and Python. This makes it easier than ever to get started with Infrastructure as Code.

Pulumi also abstracts away the cloud provider-specific resources and provides a unified view of all your resources in one place. This makes it easy to see what changes need to be made when you want to migrate to a different cloud provider.

What Is Auth0 and the Auth0 Marketplace

Auth0 is a cloud-based identity and authentication management platform. It provides a platform for developers to add user authentication to their applications and supports a variety of authentication methods, including social login, username and password, and SSO.

The Auth0 marketplace is where developers can find and use pre-built integrations for their applications. These integrations provide user authentication, management, and security features. The Auth0 marketplace offers a variety of integrations, including social login, enterprise federation, and developer tools.

Setting Up Pulumi with Auth0

For this tutorial, you don't need to have prior knowledge of either Pulumi or Auth0, and we will guide you through the process of signing up, installing, setting up, and seeing your cloud resources created.

Installing Pulumi

The first step before we start working on our project is to install Pulumi.

Pulumi is easy to install but slightly different on each operating system.

On a Mac, open your terminal, and enter.

brew install pulumi/tap/pulumi

On Linux, similarly, open your terminal, and enter:

curl -fsSL https://get.pulumi.com | sh

On Windows, it does require downloading an installer, so visit their official installation guide for more information.

Once installed on any OS, you can verify that it is properly installed by running the following command on your terminal:

pulumi version

If everything is fine, it will output the current Pulumi version at the time of writing v3.40.1.

Signing up for Pulumi

Pulumi is an open-source project and completely free to use; it requires having the Pulumi CLI installed and a backend system where the state and other configurations are installed.

You can set up and run a self-managed backend instance or use Pulumi's cloud service, which is free for individuals and offers several prices for teams and enterprises.

Pulumi Sign up screen

Since we want to get started quickly, we will sign up for a FREE account using any authentication provider.

After you log in to pulumi.com, go to your terminal and run the following command:

pulumi login

You will see an output like

Manage your Pulumi stacks by logging in.
Run `pulumi login --help` for alternative login options.
Enter your access token from https://app.pulumi.com/account/tokens
    or hit <ENTER> to log in using your browser                   :

Hit <Enter> to log in through your browser, and it's done. Alternatively, you can manually login into https://app.pulumi.com/account/tokens to generate a token and enter it into the CLI.

Create an Auth0 application for the Pulumi service

Pulumi can manage a lot of the resources of your Auth0 account, but it can't create one for you. Fortunately, that's easy to do. Go ahead and sign up for a free Auth0 account now.

While on the Auth0 dashboard, navigate to the "Applications" section on the left-side menu.

Auth0 Dashboard

Next, the new application dialog appears; enter an application name, e.g., "Pulumi App", and select the "Machine to Machine Applications" type.

Auth0 new app dialog

Since we selected the "Machine to Machine" type, we won't need a user for Pulumi; instead, we will use client credentials. But first, we need to authorize the app to access an API, and in our case, we will select the Auth0 Management API, which is available by default with your tenant.

Auth0 authorize machine to machine application dialog

After selecting the API, the dialog will expand, listing all the permissions available for that API. We recommended that you follow the principle of least-privilege and choose the authorizations carefully based on your project requirements, and no more.

With that said, and only because this is a sandbox account, we'll select all to continue, so you are not limited while following this tutorial and dealing with unauthorized access due to missing grants.

Create a new Pulumi project

We are done with all the platform sign-ups and configurations, and we are ready to start coding.

When working with Pulumi, or any other IaC tool, you'll have to decide if you want to include your Pulumi code alongside your application code or on a separate repository. The steps won't differ, though you may want to name and place directories differently.

To start, let's create a new working directory where we'll place all our Pulumi code:

mkdir pulumi-auth0-quickstart && cd pulumi-auth0-quickstart

Next, we will generate a new project using the Auth0 template:

pulumi new auth0-typescript

Note that we specified the template name auth0-typescript, but there are other languages available. You can read more about Auth0 and Pulumi in the Auth0 Marketplace and the Pulumi registry docs.

Once you run the command above, the terminal window will prompt you for a few values:

  • Project name: A unique project name.
  • Project description: A short description of your project.
  • Stack name: typically referred to as the environment or the organization plus the environment, e.g., "dev" or "auth0/dev".
  • auth0:clientId: The Auth0 client id for the Pulumi App; we'll go into details on how to get this information next.
  • auth0:clientSecret: The Auth0 client secret for the Pulumi App.
  • auth0:domain: The Auth0 domain where your Pulumi App is running.

How to capture the Auth0 values from my Auth0 account

Heading back to the Auth0 dashboard and into the recently created application "Pulumi App", you'll see the app overview, then click the Settings tab to access the information we need.

Auth0 Application Quick Start

Once on the settings page, the three values we need, clientId, client secret, and domain, are readily available to copy on your screen.

Auth0 application settings

Finally, enter those values in the terminal and way for the project to generate. It may take a minute or two, depending on the programming language.

And don't worry about adding your client secret here, it will be only stored encrypted, and you can decide the level of control and encryption provider of your choice if necessary.

Pulumi and Auth0 quick start project structure

After your project completes, Pulumi will have generated an npm project with three essential files:

  • index.ts
  • Pulumi.[env].yaml: Configuration file where all your Auth0 values are stored.
  • Pulumi: Project related metadata

Let's next take a look at the generated index.ts file;

import * as pulumi from "@pulumi/pulumi";
import * as auth0 from "@pulumi/auth0";

const client = new auth0.Client("client", {
    allowedLogoutUrls: ["https://www.example.com/logout"],
    allowedOrigins: ["https://www.example.com"],
    callbacks: ["https://example.com/auth/callback"],
    appType: "regular_web",
    jwtConfiguration: {
        alg: "RS256"
    },

})

export const clientId = client.clientId
export const clientSecret = client.clientSecret

It is a simple file that will create a new Auth0 Client (or Auth0 application), and will set configurations like the application type, logout URLs, callbacks, and allowed origins, all the typical settings you'll need to set up a regular web application.

Set up the auth0 provider into an existing Pulumi project

If you already have an existing Pulumi project and would like to provision Auth0's resources, you'll first have to install the Auth0 provider for your programming language.

If using typescript, from your terminal, on the root of your Pulumi project, run:

npm i @pulumi/auth0

If you are using other programming languages, check out their official documentation on how to install the Auth0 provider

After installing the provider, you'll have to configure the Auth0 clientId, client secret, and domain from your "Pulumi App".

To capture the value, check the previous section How to capture the Auth0 values from my Auth0 Account and, on your terminal, enter the following command with the updated values:

pulumi config set auth0:domain XXXXXXXXXXXXXX
pulumi config set auth0:client_id YYYYYYYYYYYYYY --secret
pulumi config set auth0:client_secret ZZZZZZZZZZZZZZ --secret

Don't forget to use --secret for clientid and clientsecret as that will tell Pulumi to encrypt the values.

Running Pulumi and Provisioning the Auth0 Resources

Now we are ready to use Pulumi to provision our Auth0 resources.

On your terminal, run:

pulumi up

Pulumi will first compare the current state (generated by the written code) versus the previously saved state (empty since it is our first execution) and will prepare a plan based on the results.

Here is what it looks like on the terminal:

Previewing update (dev)

View Live: https://app.pulumi.com/bajcmartinez/pulumi-auth0-quickstart/dev/previews/e93bebef-eecf-49ec-a58f-86d0b7ea11db

     Type                   Name                         Plan       
 +   pulumi:pulumi:Stack    pulumi-auth0-quickstart-dev  create     
 +   └─ auth0:index:Client  client                       create     
 
Outputs:
    clientId    : output<string>
    clientSecret: output<string>

Resources:
    + 2 to create

Do you want to perform this update? [Use arrows to move, enter to select, type to filter]
  yes
> no
  details

Since it is the first time we run Pulumi for this project, it will create a new Pulumi stack on the backend and will provision the Auth0 application as we defined it in the index.ts.

Since we agree with the plan, we proceed to execute by selecting the option yes on the screen.

Now Pulumi is creating all the resources and will print the results on the terminal when it finishes.

Updating (dev)

View Live: https://app.pulumi.com/bajcmartinez/pulumi-auth0-quickstart/dev/updates/1

     Type                   Name                         Status      
 +   pulumi:pulumi:Stack    pulumi-auth0-quickstart-dev  created     
 +   └─ auth0:index:Client  client                       created     
 
Outputs:
    clientId    : "ltiZx0e53LJoqr5IpIJrmZHAuwhsj2WZ"
    clientSecret: [secret]

Resources:
    + 2 created

Duration: 7s

What would happen if I were to run pulumi up again? It should be totally safe, so let's try it and see the results.

Previewing update (dev)

View Live: https://app.pulumi.com/bajcmartinez/pulumi-auth0-quickstart/dev/previews/7fd259e6-cadf-43ab-8b74-3e2329ed818c

     Type                 Name                         Plan     
     pulumi:pulumi:Stack  pulumi-auth0-quickstart-dev           
 
Resources:
    2 unchanged

Do you want to perform this update? [Use arrows to move, enter to select, type to filter]
  yes
> no
  details

As expected, Pulumi doesn't detect any changes, the state variable hosted in Pulumi's service and the local configuration given in the code match.

But what exactly happened in our Auth0 account? If we go back to the Auth0 dashboard, a new application will appear with the name client-{unique identifier}, e.g. client-8c41df9. Pulumi, by default, adds that unique identifier at the end of each resource name to prevent name clashing.

Example of application created with Pulumi in the Auth0 dashboard

Use Case Examples for the Pulumi Auth0 SDK

Let's see next some examples of what can be done with the Pulumi Auth0 SDK.

Provision a new Auth0 application

One of the most common tasks when automating the provisioning of Auth0 resources is to create applications, and as we discussed, we do that by leveraging the Client module.

The official documentation goes into detail on all the parameters and presets for applications, but here is a small sample for a typical scenario for a SPA application (since we already covered web apps):

const client = new auth0.Client("my-spa", {
    allowedLogoutUrls: ["https://www.my-spa.com/logout"],
    allowedOrigins: ["https://www.my-spa.com"],
    callbacks: ["https://my-spa.com/auth/callback"],
    appType: "spa",
});

Provision a new Auth0 user

Another typical use case is to create users. This is commonly done for admins, other super users, or even test users.

Let's see an example of creating an admins role and a user belonging to the group.

const adminGroup = new auth0.Role("admin", {description: "Administrator"});
const jc = new auth0.User("bajcmartinez", {
    connectionName: "Username-Password-Authentication",
    givenName: "Juan Cruz",
    familyName: "Martinez",
    email: "youremail@yourcompany.com",
    password: "very-secure-!nitial-passw0rd",
    emailVerified: true, // We don't want to email the user to confirm its registration
    roles: [adminGroup.id],
});

In the example above, we use the default database connection "Username-Password-Authentication". Optionally you can create and use other connections.

Remember that the user requirements from your connection will apply even when using Pulumi, and if a condition does not match, e.g., "Password is too weak", then the resource will fail to create.

Set your Branding and personalization with Pulumi and Auth0

Another area where Auth0 excels is personalization, allowing you to personalize the experience with your brand, your colors, logo, messages, email addresses, and even email templates.

You can customize everything about your user's experience through the Auth0 dashboard, but if you are using Pulumi, you can change those parameters through code, thanks to the modules like Branding, Email template, Prompts and more.

Here is an example of how to change your brand colors and logo using TypeScript:

const myBrand = new auth0.Branding("my_brand", {
    colors: {
        pageBackground: "#000000",
        primary: "#0059d6",
    },
    logoUrl: "https://mycompany.org/logo.png",
    universalLogin: {
        body: "<!DOCTYPE html><html><head>{%- auth0:head -%}</head><body>{%- auth0:widget -%}</body></html>",
    },
});

What resources are available with the Pulumi Auth0 integration?

With Pulumi, you can set up pretty much everything you can do with the Auth0 dashboard, so no surprise there are quite a few modules available for us to use, like Actions, Client Grants, Attack Protection.

You can read the full list on Pulumi's official docs.

Final Thoughts

More and more companies embrace DevOps and infrastructure as code to provision, manage and maintain the ever-increasing complexity of cloud services.

Pulumi helps individuals and teams to handle their IaC strategy through familiar programming languages, reducing the effort and skills needed.

Thanks to its extensibility with libraries, you can provision your servers, databases, queues, and, for example, Auth0 resources to build and customize the online identity experiences of your apps.

Thanks for learning!

  • Twitter icon
  • LinkedIn icon
  • Faceboook icon