Suspend and resume authentication with magic links
The Ping SDKs support the Suspended Authentication feature provided by PingAM.
Suspended authentication lets you pause a user’s progress through an authentication tree, and later resume from the same point.
Any input provided during authentication is saved when the authentication tree is suspended, and restored when the authentication tree is resumed. This lets the authentication tree continue after closing the browser, using a different browser, or even on a different device.
When suspending an authentication tree, you provide the user with a URL that contains a unique ID that lets them resume their authentication. The unique identifier for retrieving the saved progress can only be used once. These URLs are sometimes referred to as "magic links".
Note that the "magic link" represents a users' authentication journey up to the point it was paused. Ensure appropriate additional authentication is used in the remainder of a suspended authentication journey.
Typical use cases include password-less authentication, and email verification during progressive profile completion.
Prepare for suspended authentication
To use suspended authentication within your application, configure your server as follows:
-
Enable outgoing email.
Configure PingIDM to be able to send outbound email.
When targeting applications that use the Ping SDK for JavaScript, alter the email template to include a URI that points to the application, rather than an instance of PingAM.
Your app can then handle the URI the user clicks, and route it appropriately to resume the authentication.
For more information, see the IDM Self-Service reference.For more information, see Configure outbound email in the IDM documentation.
-
Add an "Email Suspend Node" into an authentication tree.
Enable suspended authentication by adding the node to a tree.
For more information, see Suspended authentication in the PingAM documentation.
Handle the suspended authentication callback
The Ping SDKs receive a SuspendedTextOutputCallback
when a "Email Suspend Node" is reached:
{
"type": "SuspendedTextOutputCallback",
"output": [{
"name": "message",
"value": "An email has been sent to the address you entered. Click the link in that email to proceed."
}, {
"name": "messageType",
"value": "0"
}]
}
Your application should display the message
field, which instructs the user on how to proceed.
Authentication is now suspended.
The Ping SDKs can resume authentication by using the suspendedId
parameter that was emailed to the user.
Capture the resume URI
Your application must be able to capture the URI that the user is emailed.
That URI contains the suspendedId
parameter that is used to resume the user’s authentication or registration journey.
Exact details on how to capture or intercept the URI from the email are beyond the scope of this documentation. However, the following resources may prove useful:
Android:
iOS:
Ensure your application is able to intercept the resume URI, and obtain the value of the suspendedId
parameter it contains, before continuing to the next section.
Resume a suspended authentication
After obtaining the value of the suspendedId
parameter, use it in you application to continue the user’s authentication or registration journey, as follows:
Resume authentication in an Android app
The FRSession
interface accepts the resume URI, including the suspendedId
parameter:
FRSession.authenticate(Context, Uri, NodeListener<FRSession>)
If the specified URI scheme, host, or port does not match with those of the PingAM instance configured for the app, the SDK throws an exception. |
For example, you could retrieve the resume URI from the 'intent', and pass it into the SDK as follows:
Uri resumeURI = getIntent().getData();
//Note that SuspendedAuthSessionException (401) is returned if suspendedId is invalid or expired
FRSession.authenticate(Context context, Uri resumeUri, NodeListener<FRSession>)
Resume authentication in an iOS app
The FRSession
interface accepts the resume URI, including the suspendedId
parameter:
@objc public class FRSession: NSObject {
public static func authenticate<T>(resumeURI: URL, completion:@escaping NodeCompletion<T>)
}
Examples:
AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
// This method is one of AppDelegate protocol that is invoked when
// iOS tries to open the app using the app's dedicated URL
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
// validate the resumeURI contains 'suspendedId' parameter
let resumeURL = url
// With given resumeURI, use FRSession to resume authenticate flow
FRSession.authenticate(resumeURI: resumeURL) { (token: Token?, node, error) in
// Handle Node, or the result of continuing the the authentication flow
}
}
}
SceneDelegate.swift
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
if let url = URLContexts.first?.url {
let resumeURL = url // validate the resumeURI contains 'suspendedId' parameter
// With given resumeURI, use FRSession to resume authenticate flow
FRSession.authenticate(resumeURI: resumeURL) { (token: Token?, node, error) in
// Handle Node, or the result of continuing the the authentication flow
}
}
}
}
Resume authentication in a JavaScript app
The method next()
in the FRAuth
class has been updated to accept the suspendedID
value:
interface StepOptions extends ConfigOptions {
query: {
suspendedId: string; // you must have captured the suspendedId from the users' resumeURI
};
}
abstract class FRAuth {
public static async next(
previousStep?: FRStep,
options?: StepOptions,
): Promise<FRStep | FRLoginSuccess | FRLoginFailure> {
const nextPayload = await Auth.next(previousStep ? previousStep.payload : undefined, options);
// ... continue as normal
}
}
For example, your app code may resemble the following:
const step = await FRAuth.next(null, {query: {suspendedId: 'i1PUHHWq6bTi3HxNjFGIqEask4g'}});