Deep Linking Workflow
How to perform secured Deep Linking interactions, between platforms and tools.
Workflow
You can find below a Deep Linking workflow diagram, with steps numbers:
Each step will be detailed below, from both platform and tool perspectives.
1 - Platform side: deep linking request generation
You can find below required steps to generate a deep linking request message, needed only if you're acting as a platform.
Create the message
As a platform, you can create a deep linking request message for a tool within the context of a registration.
Platforms can drive the tool behaviour on deep linking interactions by providing deep linking settings.
You have to first provide a DeepLinkingSettingsInterface implementation to configure your settings:
<?php
use OAT\Library\Lti1p3Core\Resource\Link\LinkInterface;
use OAT\Library\Lti1p3Core\Resource\LtiResourceLink\LtiResourceLinkInterface;
use OAT\Library\Lti1p3DeepLinking\Settings\DeepLinkingSettings;
// Create deep linking settings
$deepLinkingSettings = new DeepLinkingSettings(
'http://platform.com/deep-linking-return', // [required] platform url where to return content items
[
LinkInterface::TYPE, // [required] array of accepted content items types
LtiResourceLinkInterface::TYPE,
],
[ // [required] array of accepted presentation document targets
'window',
'iframe'
],
'image/*,text/html', // [optional] list of accepted media types, comma separated
true, // [optional] if should accept multiple content items (default true)
false, // [optional] if should auto create content items tool side (default false)
'Title', // [optional] title
'Description' // [optional] description
);
Then, you can use the DeepLinkingLaunchRequestBuilder to create the message:
<?php
use OAT\Library\Lti1p3Core\Registration\RegistrationRepositoryInterface;
use OAT\Library\Lti1p3DeepLinking\Message\Launch\Builder\DeepLinkingLaunchRequestBuilder;
// Create a builder instance
$builder = new DeepLinkingLaunchRequestBuilder();
// Get related registration of the launch
/** @var RegistrationRepositoryInterface $registrationRepository */
$registration = $registrationRepository->find(...);
// Build a deep linking request launch message
$message = $builder->buildDeepLinkingLaunchRequest(
$deepLinkingSettings, // [required] deep linking settings
$registration, // [required] related registration
'loginHint', // [required] login hint that will be used afterwards by the platform to perform authentication
'http://platform.com/deep-linking-return', // [optional] will launch to provided url, or fallback to tool's default deep linking url if null
null, // [optional] will use the registration default deployment id, but you can pass a specific one
['http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'], // [optional] roles
['myCustomClaim' => 'myCustomValue'] // [optional] supplementary claims if needed
);
Launch the message
As a result of the build, you get a LtiMessageInterface instance that has to be used in the following ways:
<?php
use OAT\Library\Lti1p3Core\Message\LtiMessageInterface;
/** @var LtiMessageInterface $message */
// Main message properties you can use as you want to offer the launch to the platform users
echo $message->getUrl(); // url of the launch
echo $message->getParameters()->all(); // array of parameters of the launch
// Or use those helpers methods to ease the launch interactions
echo $message->toUrl(); // url with launch parameters as query parameters
echo $message->toHtmlLink('click me'); // HTML link, where href is the output url
echo $message->toHtmlRedirectForm(); // HTML hidden form, with possibility of auto redirection
Implement OpenId Connect launch flow
Like any platform originating message, when the deep linking request message is launched, an OIDC flow will start between the tool and the platform.
The underlying core library offers everything you need to securely implement this flow, as documented in the platform originating messages documentation.
2 - Tool side: deep linking request handling
You can find below required steps to handle a deep linking launch request, needed only if you're acting as a tool.
Validate the request
As a tool, you'll receive an HTTP request containing the Deep Linking request message, generated by the platform, received after OIDC flow completion.
You can use the ToolLaunchValidator to validate it:
<?php
use OAT\Library\Lti1p3Core\Message\Launch\Validator\Tool\ToolLaunchValidator;
use OAT\Library\Lti1p3Core\Registration\RegistrationRepositoryInterface;
use OAT\Library\Lti1p3Core\Security\Nonce\NonceRepositoryInterface;
use Psr\Http\Message\ServerRequestInterface;
/** @var RegistrationRepositoryInterface $registrationRepository */
$registrationRepository = ...
/** @var NonceRepositoryInterface $nonceRepository */
$nonceRepository = ...
/** @var ServerRequestInterface $request */
$request = ...
// Create the validator
$validator = new ToolLaunchValidator($registrationRepository, $nonceRepository);
// Perform validation
$result = $validator->validatePlatformOriginatingLaunch($request);
if (!$result->hasError()) {
// Your logic to handle the deep linking request and offer content items selection
}
Offer content items selection
When a deep linking request is received by a tool, the tool may offer the user content items selection according to the platform deep linking settings.
For example:
<?php
use OAT\Library\Lti1p3Core\Message\Launch\Validator\Result\LaunchValidationResultInterface;
/** @var LaunchValidationResultInterface $result */
$result = $validator->validatePlatformOriginatingLaunch($request);
if (!$result->hasError()) {
// You have access to platform deep linking settings claim
$settings = $result->getPayload()->getDeepLinkingSettings();
// You can extract from it the information to build and offer relevant content items selection
var_dump($settings->getDeepLinkingReturnUrl()); // 'http://platform.com/deep-linking-return'
var_dump($settings->getAcceptedTypes()); // ['link', 'ltiResourceLink']
var_dump($settings->getAcceptedPresentationDocumentTargets()); // ['window', 'iframe']
...
}
From here, up to you to decide if / how you offer content items selection: you can offer the user an HTML Form
for example.
Since this process can differ a lot between tool applications, this library does not provide any tooling for this (to leave you free to provide your own process).
The library will take care of the rest of the process, when the tool will return the selected content items to the platform.
3 - Tool side: deep linking response generation
You can find below required steps to provide a deep linking response to return the content items selection, needed only if you're acting as a tool.
Collect the content items to be returned
Depending on if / how you offered content items selection tool side, you can afterwards aggregate selected resources in a ResourceCollectionInterface implementation:
<?php
use OAT\Library\Lti1p3Core\Resource\Link\Link;
use OAT\Library\Lti1p3Core\Resource\LtiResourceLink\LtiResourceLink;
use OAT\Library\Lti1p3Core\Resource\ResourceCollection;
// Get selected content items (resources)
$link = new Link('linkIdentifier', 'http://tool.com/some-link');
$ltiResourceLink = new LtiResourceLink('ltiResourceLinkIdentifier', ['url' => 'http://tool.com/launch']);
// Aggregate them in a collection
$resourceCollection = new ResourceCollection();
$resourceCollection
->add($link)
->add($ltiResourceLink);
Create the message
Once the resource collection ready, you can return it to the platform in a deep linking response message, by using the DeepLinkingLaunchResponseBuilder:
<?php
use OAT\Library\Lti1p3Core\Message\Launch\Validator\Result\LaunchValidationResultInterface;
use OAT\Library\Lti1p3Core\Registration\RegistrationRepositoryInterface;
use OAT\Library\Lti1p3DeepLinking\Message\Launch\Builder\DeepLinkingLaunchResponseBuilder;
/** @var LaunchValidationResultInterface $result */
$result = $validator->validatePlatformOriginatingLaunch(...);
// Create a builder instance
$builder = new DeepLinkingLaunchResponseBuilder();
// Related deep linking platform settings claim from previous steps
$deepLinkingSettingsClaim = $result->getPayload()->getDeepLinkingSettings();
// Get related registration of the launch
/** @var RegistrationRepositoryInterface $registrationRepository */
$registration = $registrationRepository->find(...);
// Build a deep linking response launch message
$message = $builder->buildDeepLinkingLaunchResponse(
$resourceCollection, // [required] content items collection
$registration, // [required] related registration
$deepLinkingSettingsClaim->getDeepLinkingReturnUrl(), // [required] platform url whereto return content items
null, // [optional] will use the registration default deployment id, but you can pass a specific one
$deepLinkingSettingsClaim->getData(), // [optional] platform settings data, must be returned unaltered if provided
'2 content items provided with success' // [optional] to override the default feedback message
);
Launch the message
As a result of the build, you get a LtiMessageInterface instance that has to be sent as a form POST:
<?php
use OAT\Library\Lti1p3Core\Message\LtiMessageInterface;
/** @var LtiMessageInterface $message */
echo $message->toHtmlRedirectForm(); // HTML form containing the auto generated JWT parameter
4 - Platform side: deep linking response handling
You can find below required steps to validate a deep linking response, needed only if you're acting as a platform.
Validate the response
As a platform, you'll receive an HTTP request containing the deep linking response message.
The PlatformLaunchValidator can be used for this:
- it requires a registration repository and a nonce repository implementations as explained here
- it expects a PSR7 ServerRequestInterface to validate
- it will output a LaunchValidationResult representing the launch validation, the related registration and the deep linking response payload itself.
<?php
use OAT\Library\Lti1p3Core\Message\Launch\Validator\Platform\PlatformLaunchValidator;
use OAT\Library\Lti1p3Core\Registration\RegistrationRepositoryInterface;
use OAT\Library\Lti1p3Core\Security\Nonce\NonceRepositoryInterface;
use Psr\Http\Message\ServerRequestInterface;
/** @var RegistrationRepositoryInterface $registrationRepository */
$registrationRepository = ...
/** @var NonceRepositoryInterface $nonceRepository */
$nonceRepository = ...
/** @var ServerRequestInterface $request */
$request = ...
// Create the validator
$validator = new PlatformLaunchValidator($registrationRepository, $nonceRepository);
// Perform validation
$result = $validator->validateToolOriginatingLaunch($request);
if (!$result->hasError()) {
// Your logic to handle the returned content items
}
Handle the returned content items
Once the deep linking response validation done, you can access the returned content items from the response payload:
<?php
use OAT\Library\Lti1p3Core\Message\Launch\Validator\Result\LaunchValidationResultInterface;
use OAT\Library\Lti1p3Core\Resource\Link\LinkInterface;
use OAT\Library\Lti1p3Core\Resource\LtiResourceLink\LtiResourceLinkInterface;
use OAT\Library\Lti1p3DeepLinking\Factory\ResourceCollectionFactory;
/** @var LaunchValidationResultInterface $result */
$result = $validator->validateToolOriginatingLaunch($request);
if (!$result->hasError()) {
// You have access to tool deep linking content items claim
$contentItems = $result->getPayload()->getDeepLinkingContentItems();
// You can use the ResourceCollectionFactory to ease the resources extraction as collection
$returnedResourceCollection = (new ResourceCollectionFactory())->createFromClaim($contentItems);
// Then perform your resources manipulations, for example:
$returnedLink = current($returnedResourceCollection->getByType(LinkInterface::TYPE));
echo $returnedLink->getIdentifier(); // 'linkIdentifier'
echo $returnedLink->getUrl(); // 'http://tool.com/some-link'
$returnedLtiResourceLinkLink = current($returnedResourceCollection->getByType(LtiResourceLinkInterface::TYPE));
echo $returnedLtiResourceLinkLink->getIdentifier(); // 'ltiResourceLinkIdentifier'
echo $returnedLtiResourceLinkLink->getUrl(); // 'http://tool.com/launch'
...
}
Note: if an LtiResourceLink instance is returned, you can easily create a launch from it by following the platform originating messages documentation.