Challenge with Recovery Codes

When recovery codes are enabled for your tenant, Auth0 automatically generates them when a user enrolls with multi-factor authentication (MFA). The user should save the recovery code. This code can later be used if the user loses access to the device or account used for MFA.

When recovery codes are disabled the MFA API will not return a recovery code when you associate a user's first MFA factor and users cannot authenticate with a recovery code.

You can enable users to authenticate with a recovery code using the MFA API.

  1. Prompt the user for their recovery code. That value should be entered in the application for the user to authenticate.

  2. Authenticate with recovery code. Call the OAuth Token endpoint with the recovery code to authenticate and generate a new recovery code. You need to specify the following parameters:

    Parameter Value
    grant_type http://auth0.com/oauth/grant-type/mfa-recovery-code
    recovery_code The recovery code provided by the user.
    
    
    curl --request POST \
      --url 'https://{yourDomain}/oauth/token' \
      --header 'content-type: application/x-www-form-urlencoded' \
      --data grant_type=http://auth0.com/oauth/grant-type/mfa-recovery-code \
      --data 'client_id={yourClientId}' \
      --data 'client_secret={yourClientSecret}' \
      --data 'mfa_token={mfaToken}' \
      --data 'recovery_code={recoveryCode}'

    feedbackSection.helpful

    /
    var client = new RestClient("https://{yourDomain}/oauth/token");
    var request = new RestRequest(Method.POST);
    request.AddHeader("content-type", "application/x-www-form-urlencoded");
    request.AddParameter("application/x-www-form-urlencoded", "grant_type=http%3A%2F%2Fauth0.com%2Foauth%2Fgrant-type%2Fmfa-recovery-code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&mfa_token=%7BmfaToken%7D&recovery_code=%7BrecoveryCode%7D", ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);

    feedbackSection.helpful

    /
    package main
    
    import (
    	"fmt"
    	"strings"
    	"net/http"
    	"io/ioutil"
    )
    
    func main() {
    
    	url := "https://{yourDomain}/oauth/token"
    
    	payload := strings.NewReader("grant_type=http%3A%2F%2Fauth0.com%2Foauth%2Fgrant-type%2Fmfa-recovery-code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&mfa_token=%7BmfaToken%7D&recovery_code=%7BrecoveryCode%7D")
    
    	req, _ := http.NewRequest("POST", url, payload)
    
    	req.Header.Add("content-type", "application/x-www-form-urlencoded")
    
    	res, _ := http.DefaultClient.Do(req)
    
    	defer res.Body.Close()
    	body, _ := ioutil.ReadAll(res.Body)
    
    	fmt.Println(res)
    	fmt.Println(string(body))
    
    }

    feedbackSection.helpful

    /
    HttpResponse<String> response = Unirest.post("https://{yourDomain}/oauth/token")
      .header("content-type", "application/x-www-form-urlencoded")
      .body("grant_type=http%3A%2F%2Fauth0.com%2Foauth%2Fgrant-type%2Fmfa-recovery-code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&mfa_token=%7BmfaToken%7D&recovery_code=%7BrecoveryCode%7D")
      .asString();

    feedbackSection.helpful

    /
    var axios = require("axios").default;
    
    var options = {
      method: 'POST',
      url: 'https://{yourDomain}/oauth/token',
      headers: {'content-type': 'application/x-www-form-urlencoded'},
      data: new URLSearchParams({
        grant_type: 'http://auth0.com/oauth/grant-type/mfa-recovery-code',
        client_id: '{yourClientId}',
        client_secret: '{yourClientSecret}',
        mfa_token: '{mfaToken}',
        recovery_code: '{recoveryCode}'
      })
    };
    
    axios.request(options).then(function (response) {
      console.log(response.data);
    }).catch(function (error) {
      console.error(error);
    });

    feedbackSection.helpful

    /
    #import <Foundation/Foundation.h>
    
    NSDictionary *headers = @{ @"content-type": @"application/x-www-form-urlencoded" };
    
    NSMutableData *postData = [[NSMutableData alloc] initWithData:[@"grant_type=http://auth0.com/oauth/grant-type/mfa-recovery-code" dataUsingEncoding:NSUTF8StringEncoding]];
    [postData appendData:[@"&client_id={yourClientId}" dataUsingEncoding:NSUTF8StringEncoding]];
    [postData appendData:[@"&client_secret={yourClientSecret}" dataUsingEncoding:NSUTF8StringEncoding]];
    [postData appendData:[@"&mfa_token={mfaToken}" dataUsingEncoding:NSUTF8StringEncoding]];
    [postData appendData:[@"&recovery_code={recoveryCode}" dataUsingEncoding:NSUTF8StringEncoding]];
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://{yourDomain}/oauth/token"]
                                                           cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                       timeoutInterval:10.0];
    [request setHTTPMethod:@"POST"];
    [request setAllHTTPHeaderFields:headers];
    [request setHTTPBody:postData];
    
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                                completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                    if (error) {
                                                        NSLog(@"%@", error);
                                                    } else {
                                                        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                        NSLog(@"%@", httpResponse);
                                                    }
                                                }];
    [dataTask resume];

    feedbackSection.helpful

    /
    $curl = curl_init();
    
    curl_setopt_array($curl, [
      CURLOPT_URL => "https://{yourDomain}/oauth/token",
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_ENCODING => "",
      CURLOPT_MAXREDIRS => 10,
      CURLOPT_TIMEOUT => 30,
      CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
      CURLOPT_CUSTOMREQUEST => "POST",
      CURLOPT_POSTFIELDS => "grant_type=http%3A%2F%2Fauth0.com%2Foauth%2Fgrant-type%2Fmfa-recovery-code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&mfa_token=%7BmfaToken%7D&recovery_code=%7BrecoveryCode%7D",
      CURLOPT_HTTPHEADER => [
        "content-type: application/x-www-form-urlencoded"
      ],
    ]);
    
    $response = curl_exec($curl);
    $err = curl_error($curl);
    
    curl_close($curl);
    
    if ($err) {
      echo "cURL Error #:" . $err;
    } else {
      echo $response;
    }

    feedbackSection.helpful

    /
    import http.client
    
    conn = http.client.HTTPSConnection("")
    
    payload = "grant_type=http%3A%2F%2Fauth0.com%2Foauth%2Fgrant-type%2Fmfa-recovery-code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&mfa_token=%7BmfaToken%7D&recovery_code=%7BrecoveryCode%7D"
    
    headers = { 'content-type': "application/x-www-form-urlencoded" }
    
    conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
    
    res = conn.getresponse()
    data = res.read()
    
    print(data.decode("utf-8"))

    feedbackSection.helpful

    /
    require 'uri'
    require 'net/http'
    require 'openssl'
    
    url = URI("https://{yourDomain}/oauth/token")
    
    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    
    request = Net::HTTP::Post.new(url)
    request["content-type"] = 'application/x-www-form-urlencoded'
    request.body = "grant_type=http%3A%2F%2Fauth0.com%2Foauth%2Fgrant-type%2Fmfa-recovery-code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&mfa_token=%7BmfaToken%7D&recovery_code=%7BrecoveryCode%7D"
    
    response = http.request(request)
    puts response.read_body

    feedbackSection.helpful

    /
    import Foundation
    
    let headers = ["content-type": "application/x-www-form-urlencoded"]
    
    let postData = NSMutableData(data: "grant_type=http://auth0.com/oauth/grant-type/mfa-recovery-code".data(using: String.Encoding.utf8)!)
    postData.append("&client_id={yourClientId}".data(using: String.Encoding.utf8)!)
    postData.append("&client_secret={yourClientSecret}".data(using: String.Encoding.utf8)!)
    postData.append("&mfa_token={mfaToken}".data(using: String.Encoding.utf8)!)
    postData.append("&recovery_code={recoveryCode}".data(using: String.Encoding.utf8)!)
    
    let request = NSMutableURLRequest(url: NSURL(string: "https://{yourDomain}/oauth/token")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "POST"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data
    
    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
      if (error != nil) {
        print(error)
      } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
      }
    })
    
    dataTask.resume()

    feedbackSection.helpful

    /

  3. Prompt user to capture recovery code. If the call is successful, you'll get the authentication tokens and a new recovery code:

    {
        "access_token": "O3...H4",
        "id_token": "eyJh...w",
        "scope": "openid profile",
        "expires_in": 86400,
        "recovery_code": "K6LGLV3RSH3VERMKET8L7QKU",
        "token_type": "Bearer"
    }

    feedbackSection.helpful

    /

  4. Notify the user that a new recovery code was generated and ask them to capture it.

Learn more