@jarrod We just rolled out such an app to one of our clients, and I'm happy to share my experiences with you.
Do we whitelist a large amount of callback URLs?
We haven't. Same as in your case, the user registers through a self-serve sign-up form where they enter the tenant details, such as the subdomain. During tenant creation on our backend, we simply construct the new tenant URLs for login and Oauth (we configure Oauth because we have a desktop app connecting to this same backend).
const newFusionAuthAppConfig = { name: `"${organizationName}"'s Project`, oauthConfiguration: { ...blueprintAppConfig.oauthConfiguration, enabledGrants: [GrantType.authorization_code, GrantType.refresh_token], authorizedRedirectURLs: [`${newAppUrl}/api/oauth-redirect`], logoutURL: `${newAppUrl}/api/logout`, }, loginConfiguration: blueprintAppConfig.loginConfiguration, };So when the new tenant is set up, it already has everything tenant-specific. We use the default tenant as the blueprint for some of our configurations - blueprintAppConfig.
Do we create an Application per custom domain? (Does this mean we have to sync users?)
This is what we did, but I guess it depends on your use case. For us, it was important that one user can register on different subdomains with the same email.
Do we redirect to the main app and perform some kind of sidechannel/backchannel SSO iframe magic?
I can assure you there's no magic once you correctly set up the tenant creation. The entire front end (React here) works the same as before. Most of the "magic" on the backend is simply realizing from which tenant the request came and constructing a tenant-specific Fusion Auth client to retrieve tenant-specific user details, apps, etc.
FusionAuth's official documentation on multitenant setup was an immense help to us.