Guides and TutorialsMFA and Step-UpMFA (Multi-factor Authentication)With SDKs

Implementing MFA Authentication with Descope Backend SDKs

Install SDK

Terminal
npm i --save @descope/node-sdk
Terminal
pip3 install descope
Terminal
go get github.com/descope/go-sdk
// Include the following in your `pom.xml` (for Maven)
<dependency>
    <artifactId>java-sdk</artifactId>
    <groupId>com.descope</groupId>
    <version>sdk-version</version> // Check https://github.com/descope/descope-java/releases for the latest versions
</dependency>
Terminal
gem install descope

Import and initialize Management SDK

import DescopeClient from '@descope/node-sdk';

const managementKey = "xxxx"

try{
    //  baseUrl="<URL>" // When initializing the Descope clientyou can also configure the baseUrl ex: https://auth.company.com  - this is useful when you utilize a custom domain within your Descope project.
    const descopeClient = DescopeClient({ projectId: '__ProjectID__', managementKey: managementKey });
} catch (error) {
    // handle the error
    console.log("failed to initialize: " + error)
}
from descope import (
    REFRESH_SESSION_TOKEN_NAME,
    SESSION_TOKEN_NAME,
    AuthException,
    DeliveryMethod,
    DescopeClient,
    AssociatedTenant,
    RoleMapping,
    AttributeMapping
)

management_key = "xxxx"

try:
    # You can configure the baseURL by setting the env variable Ex: export DESCOPE_BASE_URI="https://auth.company.com  - this is useful when you utilize a custom domain within your Descope project."
    descope_client = DescopeClient(project_id='__ProjectID__', management_key=management_key)
except Exception as error:
    # handle the error
    print ("failed to initialize. Error:")
    print (error)
import "github.com/descope/go-sdk/descope"
import "github.com/descope/go-sdk/descope/client"
import "fmt"

// Utilizing the context package allows for the transmission of context capabilities like cancellation
//      signals during the function call. In cases where context is absent, the context.Background()
//      function serves as a viable alternative.
//      Utilizing context within the Descope GO SDK is supported within versions 1.6.0 and higher.
import (
	"context"
)

managementKey = "xxxx"

// DescopeBaseURL // within the client.Config, you can also configure the baseUrl ex: https://auth.company.com  - this is useful when you utilize a custom domain within your Descope project.
descopeClient, err := client.NewWithConfig(&client.Config{ProjectID:"__ProjectID__", managementKey:managementKey})
if err != nil {
    // handle the error
    log.Println("failed to initialize: " + err.Error())
}
import com.descope.client;

// Initialized after setting the DESCOPE_PROJECT_ID env var (and optionally DESCOPE_MANAGEMENT_KEY)
var descopeClient = new DescopeClient();

// ** Or directly **
var descopeClient = new DescopeClient(Config.builder()
        .projectId("__ProjectID__")
        .managementKey("management-key")
        .build());
require 'descope'

descope_client = Descope::Client.new(
  {
    project_id: '__ProjectID__',
    management_key: 'management_key'
  }
)

Sign-Up, Sign-in, or Sign-Up-Or-In

The next step after adding the Descope backend SDK within your application is to utilize one of the Sign-Up, Sign-in, or Sign-Up-Or-In functions for the supported authentication methods. Once you have successfully received a JWT from the authentication method, you should store it for the next step in the MFA process.

MFA the user's authentication

Now that you have a valid JWT for your authenticated user, you can utilize Sign-in or Sign-Up-Or-In for one of the supported authentication methods, adding the user Login Options. This example will focus on the mfa parameter of the Login Options; however, for further details on Login Options, navigate here.

The below example implements MFA authentication via OTP Sign-In after the user successfully signed up via TOTP Sign-Up. After a successful MFA sign-in, you will need to process the verification code via OTP Verify. After verifying, the user will then have MFA authentication.

// Args:
//    deliveryMethod: Delivery method to use to send OTP. Supported values include "email", "voice, or "sms"
const deliveryMethod = "email"
//    loginId: email or phone - email or phone - the loginId for the user
const loginId = "email@company.com"
//    loginOptions: login options for MFA, stepup, or custom claims. Ex: {stepup: true, mfa: false, customClaims: {}}
const loginOptions = {mfa: true}
//    token: refresh token from the successful sign-in of the user
const token = "xxxx"

var resp =  await descopeClient.otp.signIn[delivery_method](loginId, loginOptions, token);
if (!resp.ok) {
  console.log("Failed to initialize mfa flow")
  console.log("Status Code: " + resp.code)
  console.log("Error Code: " + resp.error.errorCode)
  console.log("Error Description: " + resp.error.errorDescription)
  console.log("Error Message: " + resp.error.errorMessage)
}
else {
  console.log("Successfully initialized mfa flow")
  console.log(resp.data)
}
# Args:
#    delivery_method: Delivery method to use to send OTP. Supported values include DeliveryMethod.SMS, DeliveryMethod.Voice, or DeliveryMethod.EMAIL
delivery_method = DeliveryMethod.EMAIL
#    login_id: email or phone - email or phone - the loginId for the user
login_id = "email@company.com"
#    login_options (LoginOptions): login options for MFA, stepup, or custom claims. Ex: LoginOptions(stepup: True, mfa: False, customClaims: {})
login_options = LoginOptions(mfa=True)
#    refresh_token: refresh token from the successful sign-in of the user
refresh_token = "xxxxx"

try:
  resp = descope_client.otp.sign_in(method=delivery_method, login_id=login_id, login_options=login_options, refresh_token=refresh_token)
  print ("Successfully initialized MFA flow")
except AuthException as error:
  print ("Failed to initialize MFA flow")
  print ("Status Code: " + str(error.status_code))
  print ("Error: " + str(error.error_message))
// Args:
//    ctx: context.Context - Application context for the transmission of context capabilities like
//        cancellation signals during the function call. In cases where context is absent, the context.Background()
//        function serves as a viable alternative.
//        Utilizing context within the Descope GO SDK is supported within versions 1.6.0 and higher.
ctx := context.Background()
//    deliveryMethod: Delivery method to use to send OTP. Supported values include descope.MethodEmail, descope.MethodVoice, or descope.MethodSMS
deliveryMethod := descope.MethodEmail
//    loginID: email or phone - the loginId for the user
loginID := "email@company.com"
//    r: HttpRequest for the update call. This request should contain refresh token for the authenticated user.
//    loginOptions: Optional login options for MFA, stepup, or custom claims.
loginOptions := &descope.LoginOptions{mfa: true}

err := descopeClient.Auth.OTP().SignIn(ctx, deliveryMethod, loginID, r, loginOptions)
if (err != nil){
  fmt.Println("Failed to initialize MFA flow: ", err)
} else {
  fmt.Println("Successfully initialized MFA flow")
}

// Every user must have a loginID. All other user information is optional
String loginId = "email@company.com";
User user = User.builder()
    .name("Joe Person")
    .phone("+15555555555")
    .email(loginId)
    .build();
var loginOptions = LoginOptions.builder()
        .mfa(true)
        .build();
OTPService otps = descopeClient.getAuthenticationServices().getOtpService();
try {
  String maskedAddress = otps.signIn(DeliveryMethod.EMAIL, loginId, loginOptions);

} catch (DescopeException de) {
  // Handle the error
}
Was this helpful?

On this page