Step-up Authentication

The Descope service provides the ability to add layered security to your application by implementing Step-up authentication. There are two ways to implement Step-up authentication within your application: Descope flows and SDKs.

If you are utilizing the SDKs within your application, you can add the login options to the various authentication methods. Details on implementing Step-up utilizing the client sdks and backend SDKs can be found below.

Once Step-Up has been successfully authenticated, the user JWT will be updated and su will be true. See below.

{
  "amr": [
    "xxxx"
  ],
  "drn": "xx",
  "exp": xxxxx,
  "iat": xxxxx,
  "iss": "xxxxx",
  "rexp": "xxxxx",
  "su": true,
  "sub": "xxxxx"
}

Implementing Step-up Authentication with Descope Flows

If you are utilizing Descope flows within your application, you can utilize the out of the box step-up flow. Here is the default step-up flow when creating a Descope project:

Default step-up flow

This flow will begin by loading the user from the available refresh token and marking the flow as step-up. This will lead into the screen where the step-up authentication method can be selected. By default, magic link, passkeys, and social login are supported but this can be customized within the flow. Once the user completes the selected auth method, the step-up is complete.

Add this flow to your project by following the steps below:

Install SDK

You can install the Descope React SDK as described below.

Terminal
npm i --save @descope/react-sdk

Import SDK

Next step is to import the Descope React SDK using the sample code below.

import { AuthProvider, useDescope, useSession, useUser } from '@descope/react-sdk'
import { Descope } from '@descope/react-sdk'

Start Step-up flow

At this point, your application is integrated with Descope, and the next step is to trigger the Descope step-up Flow. The flow will fetch and display the step-up screen within your desired location of your application. As the user interacts with these screens, the flows continue and will Step-up the user's authentication. After successful Step-up (flow ends), the client SDK will store the stepped-up JWT in your browser local storage and cookies, and the cookie will be sent to your application server automatically with every request.

// Wrap your application with the Descope AuthProvider
const AppRoot = () => {
    return (
        <AuthProvider
            projectId='__ProjectID__'
            //  baseUrl="<URL>" // you can also configure the baseUrl ex: https://auth.company.com  - this is useful when you utilize CNAME within your Descope project.
        >
         <App />
        </AuthProvider>
    )
}
 
const App = () => {
    const { isAuthenticated, isSessionLoading } = useSession()
    const { user, isUserLoading } = useUser()
    const { logout } = useDescope()
 
    const handleLogout = useCallback(() => {
        logout()
    }, [logout])
 
    return (
        {
          <Descope
            flowId="step-up"
            onSuccess={(e) => console.log('Successfully stepped-up authentication!')}
            onError={(e) => console.log('Could not step-up authentication!')}
          />
        }
        {
          (isSessionLoading || isUserLoading) && <p>Loading...</p>
        }
 
        { isAuthenticated &&
            (
              <>
                <p>Hello ${user.name}</p>
                <div>My Private Component</div>
                <button onClick={handleLogout}>Logout</button>
              </>
            )
        }
 
        { !isAuthenticated &&
          (
            <p>You are not logged in</p>
          )
        }
    )
}

Implementing Step-up Authentication with Descope Client SDKs

Client SDK

Install SDK

Terminal
npm i --save @descope/react-sdk

Import and initialize SDK

import { AuthProvider } from '@descope/react-sdk'
import { Descope, useDescope } from '@descope/react-sdk'
 
const AppRoot = () => {
	return (
		<AuthProvider
			projectId="__ProjectID__"
			// If the Descope project manages the token response in cookies,
            // a custom domain must be configured
            // (e.g., https://auth.app.example.com)
			// and should be set as the baseUrl property.
			// baseUrl = "https://auth.app.example.com"
		>
			<App />
		</AuthProvider>
	);
};

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

The next step after adding the Descope client 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 Step-up process.

Step-up 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 stepup parameter of the Login Options; however, for further details on Login Options, navigate here.

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

// Args:
//    loginId: email or phone - becomes the loginId for the user from here on and also used for delivery
const loginId = "email@company.com"
//    deliveryMethod: Delivery method to use to send OTP. Supported values include "email", "voice, or "sms"
const deliveryMethod = "email"
//    loginOptions: login options for MFA, stepup, or custom claims. Ex: {stepup: true, mfa: false, customClaims: {}}
const loginOptions = {stepup: true}
//    token: refresh token from the successful sign-in of the user
const token = "xxxxxx"
 
const resp = await descopeClient.otp.signIn[deliveryMethod](loginId, loginOptions, token);
if (!resp.ok) {
  console.log("Failed to initialize step-up 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 step-up flow")
}

Implementing Step-up Authentication with Descope Backend SDKs

Backend SDK

Install SDK

Terminal
npm i --save @descope/node-sdk

Import and initialize SDK

import DescopeClient from '@descope/node-sdk';
try{
    //  baseUrl="<URL>" // When initializing the Descope clientyou can also configure the baseUrl ex: https://auth.company.com  - this is useful when you utilize CNAME within your Descope project.
    const descopeClient = DescopeClient({ projectId: '__ProjectID__' });
} catch (error) {
    // handle the error
    console.log("failed to initialize: " + error)
}
 
// Note that you can handle async operation failures and capture specific errors to customize errors.
//     An example can be found here: https://github.com/descope/node-sdk?tab=readme-ov-file#error-handling

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 Step-up process.

Step-up 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 stepup parameter of the Login Options; however, for further details on Login Options, navigate here.

The below example implements Step-up authentication via OTP Sign-In after the user successfully signed up via TOTP Sign-Up. After a successful Step-up sign-in, you will need to process the verification code via OTP Verify. After verifying, the user will then have stepped-up 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 = {stepup: 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 step-up 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 step-up flow")
  console.log(resp.data)
}

Validate Stepped Up Authentication

To validate that the session was successfully stepped up, you can utilize the SDK to validate the session and check that su = True.

// Args:
//   sessionToken (str): The session token, which contains the signature that will be validated
const sessionToken="xxxx" // extract from request authorization header. The above sample code sends the the session token in authorization header.
 
try {
  const authInfo = await descopeClient.validateSession(sessionToken);
  console.log("Successfully validated user session:");
  console.log(authInfo);
  if ("su" in authInfo.token) {
    console.log("Session is stepped up.");
  }
} catch (error) {
  console.log ("Could not validate user session " + error);
}

Example of Step-Up Authentication

The B2C Retail Sample App, Tee-Hee Tees uses step-up authentication. When wanting to add items to the cart, the user must be logged in. This is the first authentication. WHen the user attempts to checkout with their items, they are prompted to complete step-up authentication. Using step-up here is helpful so that users can browse the site and add to their cart without having to validate their identity. However once a purchase is being made, it is important to verify the user's identity to prevent fraudulent charges.

Was this helpful?

On this page