LTI® Platform Storage Explained
The short answer
LTI® Platform Storage is a protocol that lets a tool ask the LMS to hold a value
for it, using the browser's postMessage. It exists because a tool running in an
iframe increasingly cannot rely on its own browser storage. If the tool cannot
store its launch state, the LMS stores it instead.
It is specified by 1EdTech and is the specification's own answer to the third-party cookie problem.
The problem it solves
During a launch, the tool generates a state value at login initiation and has to
check it again when the ID Token arrives. Between those two
moments the tool is a third-party context inside the LMS's page, and a browser
that blocks third-party storage leaves it nowhere to put the value.
Platform Storage inverts the arrangement. Rather than the tool storing something and hoping the browser allows it, the tool asks the LMS — which is the first party, and whose storage is never in question — to hold it.
How the protocol works
Four messages, two round trips, one at each end of the launch.
The platform advertises support
On the login initiation request, a supporting platform includes an
lti_storage_target parameter. Its value names the frame that will answer storage
messages, commonly _parent.
The parameter is the capability signal. If it is absent, the platform does not support Platform Storage and the tool needs another approach.
The tool stores the value
Instead of redirecting immediately, the tool renders a page that posts a message to that frame:
targetFrame.postMessage({
subject: 'lti.put_data',
message_id: stateName,
key: stateName,
value: stateValue
}, platformOrigin)
The platform answers with lti.put_data.response carrying the same message_id.
Only once that arrives does the tool redirect on to the authentication endpoint.
The tool reads it back
When the ID Token POST arrives, the tool asks for the value again with
lti.get_data, receives lti.get_data.response, and compares it to the state
that came back through the LMS.
Getting the security right
The whole point is a value that backs a security check, so the retrieval has to be trustworthy. Three things matter, and all three are easy to leave out.
Check the origin. A message event listener receives messages from anywhere.
The handler must verify event.origin matches the platform's expected origin, or
any page that can reach the frame can feed the tool a value.
Check the message_id. Concurrent launches are normal — a user opening two
activities in two tabs. Matching the message_id is what keeps one launch from
consuming another's response.
Fail closed. If neither localStorage nor Platform Storage yields a value,
the launch has to fail. Continuing without it means skipping the state check.
Here is the shape of a correct listener:
window.addEventListener('message', function (event) {
if (
typeof event.data !== 'object'
|| event.data.subject !== 'lti.put_data.response'
|| event.data.message_id !== stateName
|| event.origin !== platformOrigin
) { return; }
if (event.data.error) { /* handle, do not continue silently */ }
redirectToPlatform();
});
Every one of those four conditions is doing a job. Dropping the event.origin
check is the one that turns this from a security mechanism into a liability.
What it is not
It is not general-purpose storage. It is intended for the small, short-lived values a launch needs between its steps. Your application's session is not what this is for.
It is not universally available. It is a comparatively recent addition and platform support is uneven. A tool that relies on it alone will fail against platforms that have not implemented it, which is why the sensible arrangement is to try ordinary storage first and fall back.
It does not solve your application's cookie problem. Once the launch is complete and your application is running in the iframe, the session you establish is still subject to the same browser policy.
What LTIAAS does
LTIAAS implements both paths and prefers the one more likely to be available.
At login initiation it renders a page rather than redirecting, so it has somewhere to run this logic. That page:
- Writes the state to
localStorage— and reads it back to confirm the write actually succeeded, because a blocked write does not always throw. - If the read-back fails and the platform sent an
lti_storage_target, falls back to Platform Storage. - If neither is available, redirects anyway — and the launch then fails at the state check with a clear error, rather than proceeding unverified.
The order is deliberate. localStorage works on more platforms today because it
needs nothing from the LMS; Platform Storage is the more robust mechanism but only
where the LMS has implemented it.
The stored value is not a session identifier. It is a random string signed with an account-specific key, and it has to match a separate signed JWT that travelled through the LMS. Both halves must agree before a launch is accepted.
Common questions
What is LTI® Platform Storage?
A 1EdTech-specified protocol that lets a tool ask the LMS to store a small value on its behalf, using browser postMessage. It exists so a tool can hold launch state without writing to its own browser storage, which browsers increasingly block inside an iframe.
How do I know if a platform supports it?
The platform sends an lti_storage_target parameter on the login initiation request. Its presence is the signal, and its value names the frame to post messages to. No parameter means no support.
Is Platform Storage a replacement for cookies?
For launch state, yes. It is not general-purpose storage — it is capped, short-lived and intended for the values a launch needs between steps, not for your application's session.
What happens if neither storage mechanism works?
A correct implementation fails the launch. The stored value backs the state check that proves the launch response belongs to a request the tool made, so continuing without it would mean skipping a security check.
Next
- Why LTI® launches break without third-party cookies
- The LTI® 1.3 security model — what
stateis protecting - Launching outside the iframe — when neither storage path is available
