We are pleased to announce the availability of our Multi-Factor Authentication API. Up to now, we have provided support for MFA through a simple switch in the Auth0 Dashboard, following our premise of simplicity and ease of use. However, we also believe in providing powerful building blocks for our users. For this reason we have developed a new API to perform the full MFA flow, even with multiple authenticators, in a flexible and convenient way. In this article we will take a look at the API and build a simple CLI app to demonstrate how to use it. Read on!
“The MFA API is now available, learn how to embed MFA in your apps taking full control of the experience!”
Tweet This
Note: for most MFA scenarios, we still recommend the use of Universal Login whenever possible. This new API is meant for advanced use cases where Universal Login is not flexible enough. Universal Login is the best alternative in most cases.
Why?
Up to now, enabling MFA at Auth0 was simply a matter of flipping a switch and optionally selecting which application you wanted to enable MFA for. When MFA is enabled, hitting the
/authorize
endpoint or starting an authorization flow through one of our libraries was enough to trigger MFA. Simple, convenient.However, some of our customers have requested to have more control over the MFA process. For this reason, we have been working with ATEA Norge and other customers under a private BETA program to find the right implementation for this feature. The result: a new API for MFA to give back control to you when required. Let's check it out.
Note: for most MFA scenarios, we still recommend the use of Universal Login whenever possible. This new API is meant for advanced use cases where Universal Login is not flexible enough. Universal Login is the best alternative in most cases.
A Simple API
The API works by introducing some changes to how the
/token
endpoint behaves. Let's take a look.“The new MFA API is simple, it works on top of the existing /token endpoint.”
Tweet This
The API works in four simple steps:
- Access token request to
./token
- Challenge request to
./challenge
- Asking the user for a code (if necessary).
- Final request to
./token
This scenario assumes the user is already enrolled in MFA and has at least one authenticator enabled. There's also a new API for enrollment to have full control over the enrollment process. This API also allows for obtaining a list of associated authenticators, useful for using multiple authenticator, as we will see in step 2 below.
1. Access Token Request to /token
/token
When a request is made to the
/token
endpoint to get an access token, normally you either get an error, or you get an access token. However, when the MFA API is enabled, the /token
endpoint may return a new error code: mfa_required
.POST /oauth/token HTTP/1.1 ... { "username": "...", "password": "...", "grant_type": "password" ... }
Response:
HTTP/1.1 403 Forbidden ... { "error": "mfa_required", "mfa_token": "..." }
The
mfa_token
in the response value must be used in the following requests.MFA is also supported for the
grant type. This allows for use cases in which you want to require 2FA (TOTP, SMS, push notifications) when refreshing an access token, useful for extra security and step-up authentication.refresh_token
2. Perform an MFA Challenge
When the
mfa_required
error is returned, the client must then perform a challenge
. This is done by sending a request to the /mfa/challenge
endpoint.POST /mfa/challenge HTTP/1.1 ... { "mfa_token": "<from step 1>", "challenge_type": "otp oob", "authenticator_id": "optional, if known" }
Response:
HTTP/1.1 200 OK ... { "challenge_type": "oob", "binding_method": "prompt", "oob_code": "..." }
The response tells the client which type of authenticator will be used (
challenge_type
) and also returns additional arguments relevant for that method. The binding_method
parameter tells the client it should ask the user for a code.The client may optionally request a specific authenticator through
authenticator_id
. This allows for multiple authenticators, even for the same resource.means "out-of-band". All methods that are not TOTP are OOB.OOB
3. Prompt For Input (If Necessary)
If the
challenge_type
is otp
or the binding_method
parameter is set to prompt
, the client should ask the user to input a code before continuing.4. Get The Access Token
Finally, a new request to the
/token
endpoint is performed.POST /oauth/token HTTP/1.1 ... { "mfa_token": "<from step 1>", "oob_code": "<from step 2, optional>", "binding_code": "<from step 3, if 'binding_method' === 'prompt'>", "otp": "<from step 3, if challenge_type === 'otp'>", "grant_type": "<one of two strings, see below>" }
Grant type must be one of two values: - For OTP:
http://auth0.com/oauth/grant-type/mfa-otp
- For OOB: http://auth0.com/oauth/grant-type/mfa-oob
Response:
HTTP/1.1 200 OK ... { "access_token": "...", "expires_in": "...", ... }
Note that certain methods do not require the user to input anything (push notifications, for example). For those cases, this request must be performed repeatedly until an access token is returned or the authorization is denied. If the client is expected to repeat the request again in the future (after a certain amount of time) the response will be:
HTTP/1.1 400 Bad Request ... { "error": "authorization_pending" }
This means the user has not performed any actions yet and the client should wait a bit before trying again. The
error
can also be slow_down
if the client is not waiting enough between requests.That's it! If all went well, you now have an access token issued through MFA!
Example: A CLI App with MFA
To give you a better understanding of how the API works we have developed a simple CLI app that uses MFA.
Take a look at the full code in GitHub. You will find the interesting bits in the
/token-endpoint.mjs
file, particularly in the token
function.To use the app, make sure that: - You have created a new Application in the Auth0 Dashboard. Select the
Machine-to-Machine type
.
- The token authentication method
is set to none
in the Auth0 Application settings.
- You have enabled the Password
and MFA
grants in Application -> Advanced Settings -> Grant Types
.
- You have MFA enabled. Go to Multifactor Auth and enable SMS and push notifications for Guardian.
- You have set the right client ID (get this from the application settings area) in the MFA rule in the Multifactor Auth section. Otherwise MFA will be enabled for all clients.To use the app simply do:
git clone git@github.com:auth0-blog/oauth2-mfa-cli-example.git cd oauth2-mfa-cli-example npm install node src/index.js login
The app supports some other commands. You can take a look at them by running it with no arguments.
Other Use Cases
The sky is the limit! Here are some scenarios where using the new MFA API could make sense:
- Protect a VPN like OpenVPN (Pritnul) or Juniper with a second factor.
- Integrate with a PAM module to do second factor with SSH.
- Integrate with an LDAP service to provide a second factor.
- Step up authentication when refreshing an
(access_token
grant).refresh_token
- Trigger second factor from any backend process.
You are now free to build powerful MFA flows wherever you want!
Conclusion
The MFA API brings flexibility to the use of MFA in your apps. One thing you may have noticed is that we are using the OAuth 2.0
endpoint. In fact, we designed this to be compatible with OAuth 2.0 right from the start. We have prepared two specification drafts, one for MFA, the other for authenticator association, to be sent to the IETF OAuth 2.0 Working Group. Other implementations of OAuth 2.0 can follow these specifications to implement MFA in a flexible, yet powerful way, while remaining compatible. We will have more information about this in an upcoming post./token
We can't wait to see how you use this API to build powerful multi-factor flows! Let us know what you think in the comments.
“We can't wait to see how you use this API to build powerful multi-factor flows!”
Tweet This
About the author
Sebastian Peyrott
Senior Engineer