generated.tf into the module, then swap the values that differ per environment for variables.
For example, the generator writes the Email OTP block like this, with every optional attribute listed and the dev webhook URL hardcoded:
envs/dev/terraform.tfvars.
Prerequisites
generated.tffrom Generate code from the dev tenant.
1. Delete the null lines
The generator writes out every optional attribute, so most blocks contain a lot of= null lines. Setting an attribute to null is the same as leaving it out, so delete those lines first. The theme block shrinks from around fifty lines to the handful you set in the portal.
Keep every line that has a value, including settings you never changed in the portal, such as the passkey’s user_verification_requirement or the Email OTP rate limits. A setting that isn’t in the module isn’t copied to the other tenants, which get Authsignal’s default instead.
2. Add versions.tf
The module needs its own required_providers block. Without it, terraform init fails looking for a provider called hashicorp/authsignal.
3. Authenticators
The generated code has three dev values hardcoded: the webhook URL, the passkey relying party, and the expected origins. Each becomes a variable. For example,webhook_url = "https://api.dev.example.com/authsignal/email-otp" becomes webhook_url = var.email_otp_webhook_url, and the URL moves to envs/dev/terraform.tfvars.
Keep is_active = true as generated. It matters when Terraform creates the authenticator in a new tenant.
4. The flow
The API takes the flow as JSON, andjsonencode turns the HCL inside it into that JSON. Keep the block as generated. Leave the node and rule IDs alone, such as the node ID rule-b3khtnzl and the rule ID 8b82a51b-607b-4dfe-816f-a932552b24dd. They travel with the flow, and Terraform creates the same IDs in the other tenants.
Terraform normally works out the order to create resources from the references between them. The flow doesn’t reference the authenticators, so add depends_on to tell Terraform to create them first. Without it, Terraform may create the flow in a new tenant before the authenticators it uses.
5. The theme
Keep every value you set in the portal. They make the other tenants look identical. See Branding for what each setting does. The exception isname, which is the tenant name users see in the pre-built UI, so it becomes a variable.
6. Message overrides
The generated block can usually be used as-is. See Message overrides for how overrides work. Keys are the screen ID, a dot, then the part of the screen, grouped by language code.authsignal_message_overrides page on the Terraform Registry describes the resource.
7. Delete the scratch folder
Everything it produced is now in the module.Verify
From the repository root, tidy the formatting and check the code:fmt fixes spacing and alignment after your edits. validate checks for typos and mismatched variable names without contacting the tenant. It should print Success! The configuration is valid.
Import the dev tenant into Terraform then checks the module against the dev tenant.
