Orchestration SDKs

Navigating an authentication journey in JavaScript

PingOne Advanced Identity Cloud PingAM JavaScript


The start() method returns a promise representing where you are in the authentication journey.

The promise resolves to one of three step types, as follows:

The step types returned by the start() method
Step type Description

Step

Indicates a step in the middle of the authentication journey.

Call journeyClient.next() to submit the collected payload and advance to the next step.

LoginFailure

Represents a bad request, such as invalid credentials. For example a bad password or incorrect one-time passcode (OTP).

Access the error message using step.getMessage().

LoginSuccess

Indicates successful authentication.

Obtain the user session details using step.getSessionToken().

You can get the raw data for a step by using step.payload.

Handle the different step types as follows:

Handling the different step types in a journey
// 1. Initialize the client
const journeyClient = await journey({
  config: {
    serverConfig: {
      wellknown: 'https://openam-forgerock-sdks.forgeblocks.com/am/oauth2/realms/alpha/.well-known/openid-configuration',
    }
  }
});

try {
  // 2. Start the authentication journey
  let step = await journeyClient.start({journey: 'sdkUsernamePasswordJourney'});

  // 3. Handle each step type in a loop until success or failure
  while (step.type === 'Step') {
    console.log('Current step: ', step.payload);

    // Loop through callbacks and capture input from user

    // Submit the current step and get the next one
    step = await journeyClient.next(step);
  }

  // 3. Check for success
  if (step.type === 'LoginSuccess') {
    console.log('Login successful!', step.getSessionToken());

    // You can now use the session token for subsequent authenticated requests

  } else if (step.type === 'LoginFailure') {
    console.error('Login failed:', step.getMessage());

    // Display error message to the user

  } else {
    console.warn('Unexpected step type:', step.type, step.payload);
  }
} catch (error) {
  console.error('An error occurred during the authentication journey:', error);
  // Handle network errors or other unexpected issues
}

Handling the Step type

The Step type often contains a list of callbacks that require input from the client.

You can access the different types of callback by using step.getCallbacksOfType(), and provide the necessary information to each one. Then call next() to submit the collected data, and traverse to the next node in the authentication journey:

Handling different callbacks
// 1. Configure the Journey client
const client = await journey({
  config: {
    serverConfig: {
      wellknown: 'https://openam-forgerock-sdks.forgeblocks.com/am/oauth2/realms/alpha/.well-known/openid-configuration',
    },
  },
});

try {
  // 2. Start the authentication journey
  let step = await client.start({journey: 'sdkUsernamePasswordJourney'});

  // 3. Handle steps in a loop until success or failure
  while (step.type === 'Step') {
    console.log('Current step:', step.payload);

    // Example: Handle NameCallback
    if (step.getCallbacksOfType(callbackType.NameCallback).length > 0) {
      const nameCallback = step.getCallbackOfType<NameCallback>(callbackType.NameCallback);
      console.log('Prompt for username:', nameCallback.getPrompt());
      nameCallback.setName('demo'); // Set the username
    }

    // Example: Handle PasswordCallback
    if (step.getCallbacksOfType(callbackType.PasswordCallback).length > 0) {
      const passwordCallback = step.getCallbackOfType<PasswordCallback>(
        callbackType.PasswordCallback,
      );
      console.log('Prompt for password:', passwordCallback.getPrompt());
      passwordCallback.setPassword('password'); // Set the password
    }

    // ... handle other callback types as needed

    // Submit the current step and get the next one
    step = await client.next(step);
  }

  if (step.type === 'LoginSuccess') {
    console.log('Login successful!', step.getSessionToken());

    // You can now use the session token for subsequent authenticated requests

  } else if (step.type === 'LoginFailure') {
    console.error('Login failed:', step.getMessage());

    // Display error message to the user

  } else {
    console.warn('Unexpected step type:', step.type, step.payload);
  }
} catch (error) {
  console.error('An error occurred during the authentication journey:', error);
  // Handle network errors or other unexpected issues
}

Specific callback types provide their own properties for accessing labels and setting values:

Accessing callback prompts and setting input data
  • NameCallback

  • PasswordCallback

  • DeviceProfileCallback

callback.getPrompt(); string // Access the prompt/label
callback.setName('demo'); // Set the user’s name
callback.getPrompt(); string // Access the prompt/label
callback.setPassword('5tr0ngP@S5w0rd!'); // Set the user’s password
callback.setProfile(DeviceProfileData) // Sets the device profile data for the callback.

Learn about supported callbacks in Supported Nodes and Callbacks.

Handling LoginFailure type

If an issue prevents the journey from completing you will receive the LoginFailure step type. Issues that cause this step type includes the following:

  • Network problems or data parsing errors.

  • An error response from the authentication server, typically an HTTP 4xx or 5xx status code.

  • Errors related to invalid user input or issues server-side.

You can use the following methods to gather more information about the issue preventing the journey from completing:

Methods for getting details from the LoginFailure step type
Method Description

getCode()

Returns the HTTP status code associated with the failure, for example 401.

Returns: number

getDetail()

Returns the detailed reason for the failure, which often includes policy requirements that were not met.

Returns: FailureDetail | undefined

getMessage()

Returns a general, human-readable error message from the server.

Returns: string | undefined

getReason()

Returns a short, machine-readable string describing the reason for the failure, such as "Invalid credentials".

Returns: string | undefined

getProcessedMessage()

Parses the policy-related errors from the detail object and returns them in a more structured format, which is useful for displaying specific validation errors in a user interface.

Returns: ProcessedPropertyError[]

You can also access the raw server response directly by using the payload property.

Handling the LoginFailure step type
if (step.type === 'LoginFailure') {

  const detail = step.getDetail(); // Detailed policy information
  const message = step.getMessage(); // For example, "Authentication Failed"
  const reason = step.getReason(); // For example, "Invalid credentials"

  console.error(`Failure Details: ${detail}`);
  console.error(`Failure Message: ${message}`);
  console.error(`Failure Reason: ${reason}`);


  // The raw payload is also available
  console.error('Raw Payload:', step.payload);
}

Handling LoginSuccess

When the Journey client reaches the LoginSuccess step type it stores the session token.

You can use the following methods to gather more information about the issue preventing the journey from completing:

Methods for getting details from the LoginSuccess step type
Method Description

getSessionToken()

Returns the session JSON Web Token (JWT) that confirms the user’s authenticated session.

This is the most important piece of data, as you will use it to make authenticated requests to other protected resources.

Returns: string | undefined

getSuccessUrl()

Returns the URL where the application should redirect the user upon successful authentication.

Returns: string | undefined

getRealm()

Returns the realm in which the authentication took place.

Returns: string | undefined

Handling LoginSuccess
if (step.type === 'LoginSuccess') {
  console.log('Authentication successful! Processing the result...');

  // 1. Get the Session Token
  const sessionToken = step.getSessionToken();

  if (sessionToken) {
    console.log('Retrieved Session Token:', sessionToken.substring(0, 15) + '...'); // Only log a snippet for security
  } else {
    console.warn('Login succeeded, but no session token was returned.');
  }

  // 2. Get the Success URL
  // This URL is where the authentication server recommends you redirect the user.
  const successUrl = step.getSuccessUrl();

  if (successUrl) {
    console.log('Redirect URL provided:', successUrl);
    // In a real web application, you would perform the redirection:
    // window.location.href = successUrl;
  } else {
    console.log('No specific success URL was provided. Staying on the current page.');
  }
}