Implement a Unified E2E Membership Management Experience with Stigg
Published on December 5, 2024In this lab, you will learn how to deliver a unified end-to-end membership management experience using the Stigg's React components.
The Auth0 and Stigg integration connects an environment in Stigg to your Auth0 tenant by creating:
- One Action in your Auth0 tenant Post Login flow to handle Stigg customer provisioning from Auth0 users/organizations and send login events to Stigg.
- An "Active Users" metered feature in Stigg for tracking MAUs based on Auth0 logins.
Prerequisites
To begin integrating Auth0 into your Stigg project, there are a few requirements that you'll need to set up before getting started:
- A Stigg account with an environment you want to integrate with. To create an account, visit Stigg website and click "Try Stigg" to get started.
- A new Auth0 tenant. Using a new Auth0 tenant for this sample application ensures you don't encounter any conflicts due to existing configuration in an existing tenant. You can read more about how to set one up here.
- Node.js v20 or later is required to run the bootstrapping process.
You can sign up for a free Auth0 account at https://auth0.com/signup.
Set Up the Stigg Integration
To set up the integration, follow these steps:
- Log in to your Stigg account and select the Stigg environment to which this integration will have access. Note: The integration is limited to one environment per Auth0 tenant.
- Navigate to "Integrations" -> "Apps" -> "Auth0"
- You'll need to create a new Auth0 Machine-to-Machine Application and authorize Stigg to access the Auth0 Management API. Learn how to do it here.
- Under the integration Auth0 tenant step, enter your Auth0 Tenant ID and Region.
- Enter the Client ID and Client Secret of the application you've created in step 3.
- Click "Connect".
- Select and confirm the Auth0 application you want to integrate with Stigg.
- When selecting the Auth0 application, confirm the type of users Stigg will handle. This will be automatically preselected based on the Organization Behavior of the chosen Auth0 application:
- Individuals (B2C): Every individual user will be associated with a customer in Stigg. For example, Spotify associates every listener with a customer record to manage subscriptions and billing.
- Business users (B2B): Every organization will be associated with a customer in Stigg. For example, Slack connects each company using its platform to a customer account to manage workspace-wide billing and services.
- Both: Individual users and organizations will be associated with customers in Stigg. For example, OpenAI offers products like ChatGPT to individual users while also providing businesses with API access to integrate AI into their applications.
- Click "Continue"
- Select the initial subscription plan to be assigned automatically when this integration provisions new customers. If you haven't created a Product and Plan yet, you can learn how to do it by referring to the Docs.
- Click "Complete setup"
The integration is now active. You can confirm the setup by navigating to your tenant's Post Login actions within Auth0 (Select Actions > Triggers > "post-login"), where you will find a new custom action at the end of the flow.
Auth0 Action overview
After authentication, Stigg creates an action in the Auth0 tenant at the end of the Post Login flow.
The action handles both customer and subscription provisioning, usage metering, and enforcement of active users' limits belonging to an organization. It operates in the Post-Login flow of the Auth0 tenant and automates critical aspects of user management.
Visit the "Auth0 Action" section in the "Introducing the Auth0 + Stigg Integration" blog to learn more about the Auth0 Action that Stigg creates in your Auth0 tenant for the integration.
Set Up the B2B SaaS App Template
After you have successfully integrated Auth0 with your Stigg environment, you can add feature gating and monetization capabilities in your application using the Stigg's both Node SDK and React SDKs.
For this demo, you're going to use a simple B2B SaaS app template (learn more here). Follow the next steps to clone and set up the project.
Clone and Install Dependencies
Start by cloning the auth0-b2b-saas-starter project into your local machine:
git clone https://github.com/auth0-developer-hub/auth0-b2b-saas-starter.git
Make the project directory your current working directory:
cd auth0-b2b-saas-starter
Next, install the project dependencies:
npm install
Install the Auth0 CLI
This project uses the Auth0 CLI to make setting up your tenant a lot easier, by scripting away as much manual work as possible. If you want to familiarize yourself with the Auth0 CLI, read the Auth0 CLI Basics lab.
There are different ways to install the Auth0 CLI, depending on your operating system.
macOS
You can install the Auth0 CLI using Homebrew, package manager for macOS:
brew tap auth0/auth0-cli && brew install auth0
Windows
You can install the Auth0 CLI using Scoop, a command-line installer for Windows.
First, add the bucket:
scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
Then, install the application:
scoop install auth0
Linux
You can install the Auth0 CLI using cURL, a command line tool and library for transferring data with URLs.
Download the binary to ./auth0
:
curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b .
If you want to run the binary from any directory, move the installation to a place in your $PATH
. For example:
sudo mv ./auth0 /usr/local/bin
Test the Auth0 CLI installation
Run the following command to show in the terminal the version of your Auth0 CLI installation:
auth0 --version
You should see the following output:
auth0 version <version-number> <hash>
Now, log in by entering the following command and following the instructions to choose a specific tenant to authenticate with:
auth0 login --scopes "update:tenant_settings,create:connections,create:client_grants,create:email_templates,update:guardian_factors"
This will take you through a flow that will securely retrieve a Management API token for your Auth0 tenant.
Bootstrap the Auth0 Tenant
This step will create and update entities in your Auth0 tenant. The provided script will use the Auth0 CLI to provision the resources required for this sample application:
- Creating the appropriate clients (called Applications in Auth0)
- Creating admin and member roles,
- Creating actions for setting roles and security policies
- Creating email and login templates
- Enabling MFA factors
Run the following command to execute the bootstrap script:
npm run auth0:bootstrap
The bootstrap script will create a .env.local
file containing the environment variables at the root of your project directory when it completes successfully.
Run the Sample Application
Execute the following command to run the development server:
npm run dev
You can now visit http://localhost:3000/
to access the application.
You can proceed to interact with the app as if you were a user: create an account, navigate to the settings, explore the identity capabilities.
Guard the SSO Tab Behind an Entitlement
Now that we've decided that the SSO capability will be treated as a premium feature in our app, we need to display only the SSO tab based on a feature entitlement so only customers with this entitlement can use it.
First, we'll need to create the "SSO" capability as a Boolean feature in Stigg (learn how to create a Boolean feature here) so we can reference it in our app's code.
Let's start by installing and initializing the Stigg Node SDK.
npm install @stigg/node-server-sdk
You'll need to get your environment's Server API Key from the Account Settings page.
You can store it in the .env.local
file for local development.
Now, we'll need to initialize the Node SDK and provide the API key. Create a file lib/stigg.ts
and copy this content:
import { Stigg } from "@stigg/node-server-sdk"export const stiggClient = Stigg.initialize({apiKey: process.env.STIGG_SERVER_API_KEY,})export async function waitForStiggInit() {try {await stiggClient.waitForInitialization()} catch (error) {console.error("Stigg failed to initialize", error)}}
Then, update the app/layout.tsx
file with the following code to ensure Stigg is initialized:
// ...import { waitForStiggInit } from "@/lib/stigg"// ...export default async function RootLayout({}: Readonly<{children: React.ReactNode}>) {// initialize Stigg before rendering the app, this blocks only onceawait waitForStiggInit()// ...}
For convenience, we'll add a small helper module that exposes a checkAccess
method:
import { Claims } from "@auth0/nextjs-auth0"import { stiggClient } from "@/lib/stigg"export const features = {sso: "feature-sso"// ...}export type Feature = keyof typeof featuresfunction getCustomerId(user: Claims) {return user.org_id}export async function checkAccess(user: Claims, feature: Feature) {const customerId = getCustomerId(user)const featureId = features[feature]const { hasAccess } = await stiggClient.getBooleanEntitlement({customerId,featureId,})return hasAccess}
Using our checkAccess
helper function, we can add an entitlement check to ensure only authorized organizations can access the SSO tab. Since this is a Next.js project and the SSO page is an asynchronous React Server Component, the check executes on the server side:
// ...import { checkAccess } from "@/lib/entitlements"// ...export default async function SSO() {const session = await appClient.getSession()const hasAccess = await checkAccess(session!.user, "sso")// ...return (<div className="space-y-2"><PageHeadertitle="Single Sign-On"description="Configure SSO for your organization."/>{!hasAccess ? (<NoAccess />) : (<ConnectionsList ... />)}</div>)}
Now, if a user tries to access the SSO tab when their organization is missing the SSO feature entitlement, the user will see the <NoAccess/>
component instead of the actual tab's content.
All the code changes above can be found here.
Add the Billing Tab Using Stigg's React Components
To let users manage their subscriptions, view their invoices, and track their usage, we'll introduce a self-service customer portal by embedding Stigg's CustomerPortal
, Paywall
, and Checkout
components using Stigg's React SDK.
Let's start by installing and initializing the Stigg React SDK:
npm install @stigg/react-sdk
You'll need to get your environment's Client API Key from the Account Settings page.
You can store it in the .env.local
file for local development.
Now, we'll need to initialize StiggProvider
and provide the API key:
"use client"import * as React from "react"import { StiggProvider as ReactStiggProvider } from "@stigg/react-sdk"import { providerTheme } from "@/components/stigg-theme"type StiggProviderProps = {customerId?: string | undefinedcustomerToken?: string | undefinedchildren: React.ReactNode}export function StiggProvider({children,customerId,customerToken,}: StiggProviderProps) {return (<ReactStiggProvidertheme={providerTheme}apiKey={process.env.NEXT_PUBLIC_STIGG_CLIENT_API_KEY}customerId={customerId}customerToken={customerToken}>{children}</ReactStiggProvider>)}
Our next step is to import and render the CustomerPortal
component. It's essential to render the CustomerPortal
component beneath our StiggProvider
in the component tree, as shown in this example:
"use client"import * as React from "react"import { CustomerPortal as StiggCustomerPortal } from "@stigg/react-sdk"// ...import { StiggProvider } from "@/components/stigg-provider"import { Paywall } from "@/app/dashboard/organization/billing/paywall"// ...type CustomerPortalProps = {customerId: stringcustomerToken: string}export function CustomerPortal({customerId,customerToken,}: CustomerPortalProps) {return (<div><StiggProvider customerId={customerId} customerToken={customerToken}><StiggCustomerPortalpaywallComponent={<Paywall />}.../></StiggProvider></div>)}
Let's add the Billing tab so our users will be able to access the customer portal:
// ...const sidebarNavItems = [// ...{title: "Billing",href: "/dashboard/organization/billing",},]// ...
import { createHmac } from "crypto"import { appClient } from "@/lib/auth0"import { PageHeader } from "@/components/page-header"import { CustomerPortal } from "./customer-portal"function generateCustomerToken(customerId: string) {const secret = process.env.STIGG_CUSTOMER_TOKEN_SIGNING_SECRET || ""const signature = createHmac("sha256", secret).update(customerId).digest("hex")return `HMAC-SHA256 ${customerId}:${signature}`}export default async function Billing() {const session = await appClient.getSession()const customerId = session!.user.org_idconst customerToken = generateCustomerToken(customerId)return (<div className="space-y-2"><PageHeadertitle="Billing"description="Manage your organization's billing settings."/><CustomerPortal customerId={customerId} customerToken={customerToken} /></div>)}
Having the self-service customer portal in place, we complete the purchase experience by including the Paywall
and the Checkout
components to handle subscription upgrades, downgrades, and payments.
Import the Checkout
component:
import * as React from "react"import { Plan, Checkout as StiggCheckout } from "@stigg/react-sdk"// ...type CheckoutProps = {plan: PlanonCheckout: () => Promise<void>}export function Checkout({ plan, onCheckout }: CheckoutProps) {return (<StiggCheckout...planId={plan.id}onCheckoutCompleted={async ({ success, error }) => {if (success) {await onCheckout()} else {console.error(error)}}}/>)}
Paywall
component, the Checkout
will be rendered instead when a plan is selected by the user:
import * as React from "react"import { useState } from "react"import {Plan,Paywall as StiggPaywall,useStiggContext,} from "@stigg/react-sdk"import { Checkout } from "@/app/dashboard/organization/billing/checkout"export function Paywall() {const { refreshData } = useStiggContext()const [selectedPlan, setSelectedPlan] = useState<Plan | undefined>()return (<>{selectedPlan ? (<Checkoutplan={selectedPlan}onCheckout={async () => {await refreshData()setSelectedPlan(undefined)}}/>) : (<StiggPaywall onPlanSelected={({ plan }) => setSelectedPlan(plan)}/>)}</>)
Test the Integration
We have successfully integrated all the three components within our demo app, and this is how our Billing tab should look like when running the app:
All the code changes above and the styles applied for the dark theme can be found in this commit.
Source code
The full source code for the sample app is available in this GitHub repo and can serve as a starting template for your next Auth0 + Stigg project.
Live demo: https://stigg-saastart-app.vercel.app/