LTI Message - Platform
How to use the bundle to make your application act as a platform in the context of LTI messages.
Generating platform originating LTI messages
In this section, you'll see how to generate platform originating LTI messages for tools, compliant to IMS Security and OIDC specifications.
Generic messages
You can use the provided PlatformOriginatingLaunchBuilder to build easily platform originating LTI messages.
For example:
<?php
declare(strict_types=1);
namespace App\Action\Platform\Message;
use OAT\Library\Lti1p3Core\Message\Launch\Builder\PlatformOriginatingLaunchBuilder;
use OAT\Library\Lti1p3Core\Message\LtiMessageInterface;
use OAT\Library\Lti1p3Core\Registration\RegistrationRepositoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class MyPlatformAction
{
/** @var PlatformOriginatingLaunchBuilder */
private $builder;
/** @var RegistrationRepositoryInterface */
private $repository;
public function __construct(PlatformOriginatingLaunchBuilder $builder, RegistrationRepositoryInterface $repository)
{
$this->builder = $builder;
$this->repository = $repository;
}
public function __invoke(Request $request): Response
{
$message = $this->builder->buildPlatformOriginatingLaunch(
$this->repository->find('local'),
LtiMessageInterface::LTI_MESSAGE_TYPE_RESOURCE_LINK_REQUEST,
'http://tool.com/launch',
'loginHint'
);
return new Response($message->toHtmlLink('launch'));
}
}
Note: you can find more details about the PlatformOriginatingLaunchBuilder
in the related documentation
LTI Resource Link launch request messages
This bundle also allow you to perform easily launches of an LTI Resource Link.
This becomes handy when a platform owns an LTI Resource Link to a tool resource (previously fetched with DeepLinking for example).
First of all, you need to create or retrieve an LtiResourceLink instance:
<?php
use OAT\Library\Lti1p3Core\Resource\LtiResourceLink\LtiResourceLink;
$ltiResourceLink = new LtiResourceLink(
'resourceLinkIdentifier',
[
'url' => 'http://tool.com/resource',
'title' => 'Some title'
]
);
Once your LtiResourceLinkInterface
implementation is ready, you can use the LtiResourceLinkLaunchRequestBuilder to create an LTI Resource Link launch message:
<?php
declare(strict_types=1);
namespace App\Action\Platform\Message;
use OAT\Library\Lti1p3Core\Message\Launch\Builder\LtiResourceLinkLaunchRequestBuilder;
use OAT\Library\Lti1p3Core\Registration\RegistrationRepositoryInterface;
use OAT\Library\Lti1p3Core\Resource\LtiResourceLink\LtiResourceLink;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class MyPlatformAction
{
/** @var LtiResourceLinkLaunchRequestBuilder */
private $builder;
/** @var RegistrationRepositoryInterface */
private $repository;
public function __construct(LtiResourceLinkLaunchRequestBuilder $builder, RegistrationRepositoryInterface $repository)
{
$this->builder = $builder;
$this->repository = $repository;
}
public function __invoke(Request $request): Response
{
$ltiResourceLink = new LtiResourceLink(
'resourceLinkIdentifier',
[
'url' => 'http://tool.com/resource',
'title' => 'Some title'
]
);
$message = $this->builder->buildLtiResourceLinkLaunchRequest(
$ltiResourceLink,
$this->repository->find('local'),
'loginHint'
);
return new Response($message->toHtmlLink('launch LTI Resource Link'));
}
}
Note: you can find more details about the LtiResourceLinkLaunchRequestBuilder
in the related documentation
Provide platform OIDC authentication
During the OIDC flow, the platform will be asked to provide (or delegate) authentication for a login hint.
The OidcAuthenticationAction is automatically added to your application via the associated flex recipe, in file config/routes/lti1p3.yaml
.
Default route: [GET,POST] /lti1p3/oidc/authentication
You then just need to ensure your platform's oidc_authentication_url
is configured accordingly:
# config/packages/lti1p3.yaml
lti1p3:
platforms:
myPlatform:
name: "My Platform"
audience: "http://platform.com"
oidc_authentication_url: "http://platform.com/lti1p3/oidc/authentication"
oauth2_access_token_url: "http://platform.com/lti1p3/auth/platformKey/token"
To personalise how the actual authentication will be handled, you need to provide a UserAuthenticatorInterface implementation, as explained here.
For example:
<?php
namespace App\Security\User;
use OAT\Library\Lti1p3Core\Registration\RegistrationInterface;
use OAT\Library\Lti1p3Core\Security\User\Result\UserAuthenticationResult;
use OAT\Library\Lti1p3Core\Security\User\Result\UserAuthenticationResultInterface;
use OAT\Library\Lti1p3Core\Security\User\UserAuthenticatorInterface;
use OAT\Library\Lti1p3Core\User\UserIdentity;
class UserAuthenticator implements UserAuthenticatorInterface
{
public function authenticate(RegistrationInterface $registration, string $loginHint): UserAuthenticationResultInterface
{
// Perform user authentication based on the registration and login hint
// (ex: owned session, LDAP, external auth service, etc)
...
return new UserAuthenticationResult(
true, // success
new UserIdentity('userIdentifier', 'userName') // authenticated user identity
);
}
}
You then need to activate it in your application services:
# config/services.yaml
services:
OAT\Library\Lti1p3Core\Security\User\UserAuthenticatorInterface:
class: App\Security\User\UserAuthenticator
Validating tool originating LTI messages
Plaforms can also receive LTI messages from tools (see DeepLinking response for example).
This bundle offers you a way to protect your platform application endpoints that will receive tool originating messages.
Considering you have the following platform endpoint:
#config/routes.yaml
platform_return:
path: /platform/return
controller: App\Action\Platform\ReturnAction
To protect your endpoint, this bundle provides the lti1p3_message_platform
security firewall to put in front of your routes:
# config/packages/security.yaml
security:
firewalls:
secured_platform_area:
pattern: ^/platform/return
stateless: true
lti1p3_message_platform: true
You can optionally restrict allowed message types on this firewall:
# config/packages/security.yaml
security:
firewalls:
secured_platform_area:
pattern: ^/platform/return
stateless: true
lti1p3_message_platform: { types: ['LtiDeepLinkingResponse'] }
It will automatically handle the provided JWT parameter validation, and add a LtiPlatformMessageSecurityToken in the security token storage, that you can use to retrieve your authentication context.
For example:
<?php
declare(strict_types=1);
namespace App\Action\Platform;
use OAT\Bundle\Lti1p3Bundle\Security\Authentication\Token\Message\LtiPlatformMessageSecurityToken;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Security;
class ReturnAction
{
/** @var Security */
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
public function __invoke(Request $request): Response
{
/** @var LtiPlatformMessageSecurityToken $token */
$token = $this->security->getToken();
// Related registration
$registration = $token->getRegistration();
// Related LTI message payload
$payload = $token->getPayload();
// You can even access validation results
$validationResults = $token->getValidationResult();
// Your service endpoint logic ...
return new Response(...);
}
}