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:
| Step type | Description |
|---|---|
|
Indicates a step in the middle of the authentication journey. Call |
|
Represents a bad request, such as invalid credentials. For example a bad password or incorrect one-time passcode (OTP). Access the error message using |
|
Indicates successful authentication. Obtain the user session details using |
|
You can get the raw data for a step by using |
Handle the different step types as follows:
// 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:
// 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:
-
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
4xxor5xxstatus 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:
| Method | Description |
|---|---|
|
Returns the HTTP status code associated with the failure, for example Returns: |
|
Returns the detailed reason for the failure, which often includes policy requirements that were not met. Returns: |
|
Returns a general, human-readable error message from the server. Returns: |
|
Returns a short, machine-readable string describing the reason for the failure, such as "Invalid credentials". Returns: |
|
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: |
|
You can also access the raw server response directly by using the |
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:
| Method | Description |
|---|---|
|
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: |
|
Returns the URL where the application should redirect the user upon successful authentication. Returns: |
|
Returns the realm in which the authentication took place. Returns: |
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.');
}
}