Infrastructure

The edge service is deployed across two platforms: Cloudflare Workers (compute and routing) and Auth0 (identity provider actions and tenant policy). Cloudflare Workers deployments and route bindings are managed via wrangler.toml and wrangler publish. Supporting infrastructure — DNS records, Auth0 actions, and the GrowthBook proxy — is managed by Terraform from the deploy/ directory. Worker binaries are built with webpack and published via wrangler.

The Terraform state backend is S3 at key terraform/edge/terraform.tfstate.

Provider versions in use:

  • cloudflare/cloudflare 4.52.5

  • auth0/auth0 1.33.0

  • hashicorp/aws 6.19.0


Environments

Edge supports multiple named environments controlled by the FLOATME_ENVIRONMENT variable (default: test). Every resource is namespaced by environment so prod and test are fully isolated.

Worker environment split

Each wrangler.toml defines a [env.prod] and [env.test] stanza. The top-level name/route keys are local-dev defaults only. Wrangler is always invoked with --env $FLOATME_ENVIRONMENT so the correct name and route pattern are selected at publish time.

Worker prod route test route

auth

auth.floatme.io/*

auth.test.floatme.io/*

backoffice-auth

auth.backoffice.floatme.io/*

auth.backoffice.test.floatme.io/*

sms

sms.floatme.io/*

sms.test.floatme.io/*

links

links.floatme.io/*

links.test.floatme.io/*

Auth0 tenant split

The auth and backoffice-auth workers point to different Auth0 tenants per environment. This is a hard split — prod and test use entirely separate tenants with separate client IDs, management credentials, and MFA audiences.

Worker prod tenant test tenant

auth

floatme.auth0.com

floatme-test.us.auth0.com

backoffice-auth

floatme-backoffice.us.auth0.com

floatme-backoffice-test.us.auth0.com

Castle blocking (ENABLE_CASTLE_BLOCKING) is set to "true" in prod and "false" in test, so fraud signals are enforced only in production.

Environment → Worker Deployed Name → Cloudflare Route
────────────────────────────────────────────────────────────────
prod   auth              prod-auth          auth.floatme.io/*
prod   backoffice-auth   prod-backoffice-auth auth.backoffice.floatme.io/*
prod   sms               prod-sms           sms.floatme.io/*
prod   links             prod-links         links.floatme.io/*

test   auth              test-auth          auth.test.floatme.io/*
test   backoffice-auth   test-backoffice-auth auth.backoffice.test.floatme.io/*
test   sms               test-sms           sms.test.floatme.io/*
test   links             test-links         links.test.floatme.io/*

Cloudflare Workers

Workers are TypeScript source files. Three workers (auth, sms, waitlist) are compiled by webpack into ES module bundles under dist/cloudflare/workers/<name>/index.mjs. The backoffice-auth and links workers are published directly from source via wrangler without a webpack build step. Each worker has its own wrangler.toml in cloudflare/workers/<name>/.

Worker Source Wrangler config Purpose

auth

cloudflare/workers/auth/index.ts

cloudflare/workers/auth/wrangler.toml

Auth0 proxy for the FloatMe mobile app. Handles login, signup, MFA, social auth, password reset, session tokens, and Castle fraud checks.

backoffice-auth

cloudflare/workers/backoffice-auth/index.ts

cloudflare/workers/backoffice-auth/wrangler.toml

Auth0 proxy for the internal backoffice admin console. Uses a dedicated Auth0 tenant.

sms

cloudflare/workers/sms/index.ts

cloudflare/workers/sms/wrangler.toml

"Text me the app" (TMTA) worker — sends an SMS with the app download link via Twilio.

links

cloudflare/workers/links/index.ts

cloudflare/workers/links/wrangler.toml

Deeplink rewriter (links.floatme.iofloatme://) and .well-known file host (AASA, assetlinks.json).

Worker environment variables

Non-secret configuration is declared inline in wrangler.toml under [env.<name>.vars]. Secrets are uploaded separately via wrangler secret put (see Secrets Management).

Table 1. auth worker vars
Variable prod value test value

WORKER_ENV

prod

test

AUTH0_BASE_URL

https://floatme.auth0.com

https://floatme-test.us.auth0.com

AUTH0_CLIENT_ID

5fDBKS8dtHEcG5yKGf7y2wgej3ioJ09i

z9L42UYyo4B9uKAoR0yqroenFio819Hx

AUTH0_MANAGEMENT_BASE_URL

https://floatme.auth0.com/api/v2/

https://floatme-test.us.auth0.com/api/v2/

FLOATME_USER_SERVICE_URL

https://j72mm4jbii.execute-api.us-east-2.amazonaws.com

https://7oweo0qx8a.execute-api.us-west-2.amazonaws.com

FLOATME_USER_SERVICE_REGION

us-east-2

us-west-2

CASTLE_DOMAIN

https://api.castle.io

https://api.castle.io/v1 ⚠️ bug — the Castle client appends /v1/…​ paths to this value, so test resolves to /v1/v1/…​. Castle blocking is disabled in test (ENABLE_CASTLE_BLOCKING=false) so it has no runtime impact, but this should be corrected to https://api.castle.io.

ENABLE_CASTLE_BLOCKING

true

false

Table 2. backoffice-auth worker vars
Variable prod value test value

AUTH0_BASE_URL

https://floatme-backoffice.us.auth0.com

https://floatme-backoffice-test.us.auth0.com

AUTH0_CLIENT_ID

FmqEiC43Lh4CTmn6Yt7nh0zE7xL4f5EM

XRLwrQ738NdKUIV2YeKmSQhgOAb1UeTF

AUTH0_AUTHENTICATION_AUDIENCE

https://api.backoffice.floatme.io

https://api.backoffice.test.floatme.io

AUTH0_CONNECTION

Username-Password-Authentication

Username-Password-Authentication

Table 3. sms worker vars (same in both environments — single Twilio account)
Variable Value

SMS_TMTA_FROM_NUMBER

+12108641371

SMS_TMTA_TWILIO_MESSAGING_SID

MG6ce087e41e8ac916eda01cacba2090f6

TWILIO_ACCOUNT_SID

ACfb6e3e47c8b47f0c9dc0a8a305705af2

The links worker has no non-secret vars; it uses only WORKER_ENV.


DNS

DNS records are managed in Terraform, all within the floatme.io Cloudflare zone (zone ID supplied via var.cloudflare_zone_id). All records are proxied through Cloudflare.

Resource (Terraform) Type Name (prod) Name (test) Purpose

cloudflare_record.backoffice_auth

AAAA

auth.backoffice.floatme.io

auth.backoffice.test.floatme.io

Discard record (100::, RFC 6666 discard prefix — not IPv6 loopback ::1) — Cloudflare routes the request to the backoffice-auth worker before it ever reaches an origin server. Defined in backoffice_auth_dns.tf.

cloudflare_record.growthbook

CNAME

growthbook.floatme.io

test-growthbook.floatme.io

CNAME to cdn.growthbook.io — routes GrowthBook SDK traffic through Cloudflare’s proxy. Defined in growthbook_proxy.tf.

Worker routes for auth, sms, and links are defined in each worker’s wrangler.toml (not Terraform) and are registered with Cloudflare when wrangler publishes the worker.


GrowthBook Proxy

deploy/growthbook_proxy.tf provisions a Cloudflare DNS CNAME record that points growthbook.floatme.io (prod) or test-growthbook.floatme.io (test) at cdn.growthbook.io. The record is proxied, meaning all GrowthBook SDK requests from FloatMe clients flow through Cloudflare rather than directly to GrowthBook’s CDN.

This provides two benefits:

  1. Cloudflare caches the GrowthBook feature flag payload at the edge, reducing latency for SDK initialization.

  2. FloatMe controls the DNS name, so the GrowthBook CDN URL can be changed without updating client builds.


Auth0 Actions

Auth0 Actions are deployed via Terraform (deploy/auth0_actions.tf). All actions run Node.js 18. They are automatically deployed (deploy = true) when Terraform applies.

Terraform resource Action name (env-prefixed) Trigger Source file

auth0_action.ip_metadata_action

{env}-ip-metadata

post-login v3

auth0/actions/add_ip_to_metadata.js

auth0_action.mfa_action

{env}-mfa-custom-claim

post-login v3

auth0/actions/mfa_action.js

auth0_action.set_mfa_action

{env}-set-mfa

pre-user-registration v2

auth0/actions/enable_mfa.js

The post-login trigger pipeline (auth0_trigger_actions.login_flow) runs ip-metadata first, then mfa-custom-claim, on every post-login event.

The auth0/rules/ directory contains legacy Auth0 rules that have been superseded by Actions and are not deployed or documented.

Secrets Management

Secrets are never stored in wrangler.toml. They are uploaded directly to the Cloudflare Workers secret store using wrangler secret put --env $FLOATME_ENVIRONMENT. Each worker has a secrets.sh script in its source directory.

Run all secrets in one pass:

FLOATME_ENVIRONMENT=prod make secrets.host

Or per-worker:

FLOATME_ENVIRONMENT=prod make secrets.auth.host
FLOATME_ENVIRONMENT=prod make secrets.backoffice-auth.host
FLOATME_ENVIRONMENT=prod make secrets.sms.host
FLOATME_ENVIRONMENT=prod make secrets.links.host
make secrets.host also invokes make secrets.waitlist.host for the deprecated waitlist worker. The waitlist worker is not documented (it is excluded from this documentation per the deprecation policy), but its secret upload target remains in the Makefile and runs as part of the full secrets.host pass.
Table 4. Secrets by worker
Worker Secret name (in Cloudflare) Source env var

auth

AUTH0_CLIENT_SECRET

AUTH0_APP_CLIENT_SECRET

auth

AUTH0_CONNECTION

AUTH0_CONNECTION

auth

AUTH0_AUTHENTICATION_AUDIENCE

AUTH0_AUTHENTICATION_AUDIENCE

auth

AUTH0_AUTHENTICATION_ISSUER

AUTH0_AUTHENTICATION_ISSUER

auth

AUTH0_MFA_AUDIENCE

AUTH0_MFA_AUDIENCE

auth

CASTLE_CLIENT_SECRET

CASTLE_CLIENT_SECRET

auth

FLOATME_AWS_ACCESS_KEY_ID

FLOATME_AWS_ACCESS_KEY_ID

auth

FLOATME_AWS_SECRET_ACCESS_KEY

FLOATME_AWS_SECRET_ACCESS_KEY

auth

AUTH0_MANAGEMENT_CLIENT_ID

AUTH0_MANAGEMENT_CLIENT_ID

auth

AUTH0_MANAGEMENT_CLIENT_SECRET

AUTH0_MANAGEMENT_CLIENT_SECRET

auth

AUTH0_MANAGEMENT_AUDIENCE

AUTH0_MANAGEMENT_AUDIENCE

auth

DATADOG_API_KEY

DATADOG_API_KEY

backoffice-auth

AUTH0_CLIENT_SECRET

BACKOFFICE_AUTH0_CLIENT_SECRET

backoffice-auth

DATADOG_API_KEY

DATADOG_API_KEY

sms

TWILIO_AUTH_TOKEN

SMS_TMTA_TWILIO_AUTH_TOKEN

sms

DATADOG_API_KEY

DATADOG_API_KEY

links

DATADOG_API_KEY

DATADOG_API_KEY

The AWS credentials uploaded to the auth worker (FLOATME_AWS_ACCESS_KEY_ID / FLOATME_AWS_SECRET_ACCESS_KEY) are scoped to the IAM user named by var.cloudflare_workers_iam_user_name and are used to sign SigV4 requests to the user-service API Gateway.


Build and Publish Flow

Building workers

make build        # runs webpack inside the Docker devkit container
make build.host   # runs webpack directly on the host (requires Node + webpack)

Both targets invoke webpack and output compiled bundles to dist/cloudflare/workers/<name>/index.js. A final edge.tar.gz is created in dist/ containing all built artifacts.

The webpack config compiles all four workers in a single pass. The build is a prerequisite of the tarball target.

Publishing workers

After building, publish each worker with wrangler:

FLOATME_ENVIRONMENT=prod \
  wrangler publish dist/cloudflare/workers/auth/index.js \
  --env prod \
  -c cloudflare/workers/auth/wrangler.toml

Repeat for each worker. The --env flag selects which wrangler.toml stanza ([env.prod] or [env.test]) to use for the worker name and route pattern.

For local development, wrangler dev can be started per-worker without building:

make auth.local            # wrangler dev --env test (auth worker)
make backoffice-auth.local # wrangler dev --env test (backoffice-auth worker)
make sms.local             # wrangler dev (no env flag — uses top-level defaults)
make links.local           # wrangler dev (no env flag — uses top-level defaults)

Terraform apply flow

All Terraform is in deploy/. The deploy/Makefile exposes three targets driven by the FLOATME_ENVIRONMENT variable:

cd deploy
FLOATME_ENVIRONMENT=prod make init    # terraform init
FLOATME_ENVIRONMENT=prod make plan    # terraform plan
FLOATME_ENVIRONMENT=prod make apply   # terraform apply

FLOATME_ENVIRONMENT is mapped to TF_VAR_environment automatically by the Makefile. All other TF_VAR_* inputs (Cloudflare zone, Auth0 credentials, Twilio secrets, etc.) are injected from environment variables — see the variable table in deploy/variables.tf for the full list.

The root Makefile also exposes make tf WHAT=<subcommand> which delegates to deploy/Makefile.


Terraform Structure

File Contents

deploy/main.tf

Provider configuration for Cloudflare, Auth0, and AWS. S3 backend definition. A secondary aws provider aliased qa targets us-west-2 for QA-only resources.

deploy/variables.tf

All input variables: environment name, Cloudflare zone/account IDs, Auth0 tenant URLs and credentials, Segment keys, Twilio credentials, user-service API Gateway info, and IAM user name for Cloudflare workers.

deploy/auth0_actions.tf

Three auth0_action resources (ip-metadata, mfa-custom-claim, set-mfa) and the auth0_trigger_actions.login_flow that orders the post-login pipeline.

deploy/backoffice_auth_dns.tf

cloudflare_record.backoffice_auth — the AAAA discard record that anchors the backoffice-auth worker route. The subdomain is auth.backoffice.floatme.io in prod and auth.backoffice.{env}.floatme.io in all other environments.

deploy/growthbook_proxy.tf

cloudflare_record.growthbook — CNAME to cdn.growthbook.io that routes GrowthBook SDK traffic through Cloudflare.