I am trying to setup MFA. Enabling the MFA is pretty straight forward but disabling is quite challenging. The use case is:
- Users looses MFA device.
- User logs in using recovery code
- User disables MFA to remove the old enrollment
- User re-enables MFA to setup new enrollment with new device
This issue has been covered a bit on this post but the answer is unsatisfactory:
The answer basically indicates the app administrator has to manually reset the user’s MFA.
It does mention possibly using the API. After a bit of digging I found:
https://auth0.com/docs/multifactor-authentication/api/manage
While WAY more work than it should be it appears the steps might be:
- Have user authorize a new authorization token (they would use the recovery code to do so)
- Exchange that authorization token for an access token.
- Use the access token to make an API call to get a list of the authenticators
- Use the access token to make individual API calls to delete each authenticators
Ughhh… So I get working on this. I make a link for step one. Rough code is:
...
params = {
scope: 'openid profile email read:authenticators remove:authenticators',
response_type: 'code',
client_id: client_id,
state: '....',
redirect_uri: redirect,
audience: "https://#{ENV['AUTH0_DOMAIN']}/mfa/",
}
link_to "Disable Two-factor Security", "https://#{ENV['AUTH0_DOMAIN']}/authorize?#{params.to_query}"
This successfully links me off to authenticate (password and 2-factor which I would be using the backup codes in this case). When redirected back to my app I can successfully exchange the authorization code for an access token (I’m actually piggybacking on the omniauth functionality already in my app for this).
Now with my access token I have the following function:
def reset_mfa access_token
authenticators = JSON.parse RestClient.get(
"https://#{ENV["AUTH0_DOMAIN"]}/mfa/authenticators",
Authorization: "Bearer #{access_token}",
'Content-Type' => 'application/json'
).body
for authenticator in authenticators
RestClient.delete "https://#{ENV['AUTH0_DOMAIN']}/mfa/authenticators/#{authenticator['id']}", Authorization: "Bearer #{access_token}"
end
end
When the HTTP GET
request is made I get back the following response:
"{\"error\":\"invalid_grant\",\"error_description\":\"The mfa_token provided is invalid. Try getting a new token.\"}"
This feels like it’s looking for a MFA code rather than an access token. The only thing I could find was:
But this is for someone making an association so passing Auth0 an MFA token makes sense. But to get a list of current authenticators the error doesn’t make sense.