One solution I was able to see in work - LinOTP (https://www.linotp.org/documentation.html) or its fork - PrivacyIDEA (https://privacyidea.readthedocs.io/en/latest/). Both work the same way - they pull user database somehow (via LDAP(s) for example) and act as a proxy, adding MFA bit. For this they keep database of users and their MFA tokens. So, if it's a production system and you need HA, you need to make sure this database is also properly clustered. They offer admin portal, self-service portal for users to issue tokens (HOTP or TOTP for example), and REST API interface which can be used by RADIUS plugins as well as custom software.
Another way is Azure MFA. For this user base has to be in Azure AD and have MFA enabled. Self-service and admin portals are provided by MS. You don't need to worry about clustering and backend DBs sync though.
https://docs.fortinet.com/document/fortigate-public-cloud/6.2.0/azure-administration-guide/517582/configuring-forticlient-vpn-with-multifactor-authentication - example for FortiGate
They didn't describe installation of MFA NPS extension though, and it's not very transparent too.
https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-nps-extension-vpn
Also they missed
config system global
set remoteauthtimeout 30
end
This is to ensure user has enough time to pull his smartphone, open MS Authenticator app and enter the code.
To switch between SMS/TOTP and "Approve" button in MS Authenticator app (yes, instead of typing all these digits from SMS/email/time-based OTP you can just click button in MS Authenticator app), go to aka.ms/MFASetup