Skip to main content

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 (LMS)Tool1. Login initiation2. Generate and store the statelocalStorage→ LTI® Platform Storage→ fail closedA cookie set hereis a third-partycookie3. Redirect to authentication endpoint4. POST signed ID Token5. Read the state back, compareNo stored value meansthe launch is rejected6. Verified — launch proceeds
Step 2 is where Platform Storage substitutes for the tool's own browser storage.

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:

  1. Writes the state to localStorage — and reads it back to confirm the write actually succeeded, because a blocked write does not always throw.
  2. If the read-back fails and the platform sent an lti_storage_target, falls back to Platform Storage.
  3. 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

All trademarks, logos, and service marks displayed on this website are the property of their respective owners. LTIAAS is a trademark of GatherAct, LLC, doing business as LTIAAS. Learning Tools Interoperability (LTI)® and LTI® are trademarks of 1EdTech Consortium, Inc. LTIAAS is not affiliated with, endorsed or sponsored by 1EdTech Consortium, Inc. or by any other owners of third-party trademarks used on this website. LTIAAS is not responsible for the content, quality, or accuracy of any websites linked to or from this website that are not owned by LTIAAS. If you have any questions or concerns about the use of any trademarks or content on this website, please contact us.