Skip to main content

Why LTI® Launches Break Without Third-Party Cookies

The short answer

An LTI® 1.3 launch is a multi-step exchange, and the tool has to remember one value between the steps. That value is usually kept in a cookie — and because the tool is running in an iframe inside the LMS, it is a third-party cookie. When the browser drops it, the tool cannot match the launch response to the request it made, and rejects a launch that was perfectly valid.

Why this is an LTI® problem and not a general web problem

Plenty of things break without third-party cookies. LTI® breaks in a specific way that is worth understanding, because it determines which fixes actually work.

The launch is not one request. It is at minimum three, and the tool is involved in the first and the third:

  1. The platform sends the browser to the tool's login initiation endpoint. The tool generates a state value here and has to store it.
  2. The tool redirects the browser back to the platform's authentication endpoint.
  3. The platform POSTs the ID Token to the tool's launch URL. The tool reads its stored state back and checks it matches.
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
Where an LTI® launch keeps its state, and what happens when the browser will not hold it.

That check is not optional. state is what proves the response belongs to a request this tool actually made, rather than one an attacker initiated — see the security model. A tool that skips it has a CSRF hole.

So the tool must write something in step 1 and read it in step 3. Both happen while the tool is a third-party context inside the LMS's page. If the browser discards storage between those two moments, the launch fails — and it fails at the security check, which means the error message usually talks about an invalid state rather than about cookies.

Common symptoms, all the same root cause:

SymptomWhat is actually happening
Invalid state or Missing state paramStep 3 could not read what step 1 wrote
Blank white iframeTool errored server-side, LMS shows the empty frame
Redirect loop back to your login pageSession cookie dropped, tool thinks nobody is logged in
"Works for me, broken for one customer"That user is on Safari, or in Incognito

Partitioning is not the same as blocking

This distinction matters and is almost always missed.

Browsers have converged on partitioning third-party storage: a cookie or a localStorage entry written inside an iframe is scoped to the pair (top-level site, frame origin). Your tool's storage inside University A's LMS is a different bucket from your storage inside University B's.

Partitioning does not break an LTI® launch. The write in step 1 and the read in step 3 happen under the same top-level site and the same frame origin, so they land in the same bucket. What partitioning breaks is using an LMS launch to pick up a session the user established on your own site directly — which was never something to depend on anyway.

Blocking does break it. Some browsers, and some user configurations, deny storage in a third-party frame outright rather than partitioning it. Then step 3 has nothing to read. Where a browser offers the Storage Access API, a frame can ask the user for access — a prompt, which is not something to put in the middle of a launch.

The useful way to think about it: your tool needs somewhere to put a value for thirty seconds, and in a growing number of browsers the iframe is not that place.

The four fixes

In rough order of how well they hold up.

1. Do not store anything on your origin

The launch state can be held somewhere other than your tool's browser storage. LTI® Platform Storage is a 1EdTech-specified protocol for asking the LMS to hold the value, over postMessage. Nothing is written to your origin, so nothing can be blocked.

This is the fix the specification itself provides, and it is the only one that does not depend on browser storage policy. Its limit is that the LMS has to implement it, and not all do yet.

If the value the tool needs after launch travels as a request parameter, browser storage stops being involved.

This is how LTIAAS works. The launch hands your application an ltik as a query parameter, and your back end exchanges it for the launch data:

const idtoken = await axios.get('https://your.ltiaas.com/api/idtoken', {
headers: { Authorization: `LTIK-AUTH-V2 ${API_KEY}:${ltik}` }
})

The ltik is a signed token, valid for 24 hours, and redeeming it also requires your API key — which lives on your server, not in the browser. A token in a URL alone is not enough to impersonate a user.

The same idea works for your own session: after you authenticate the user, pass your own token as a parameter rather than setting a cookie.

3. Partitioned cookies (CHIPS)

If you control the cookie, adding SameSite=None; Secure; Partitioned; keeps it working in browsers that partition rather than block. See the cookies guide for the detail.

This fixes most users, not all. A partitioned cookie is still a cookie, and a user who has blocked them entirely still will not get one. Support is also strongest in Chromium browsers and weaker elsewhere, which is the wrong way round given Safari is where the problem is worst.

4. Leave the iframe

Open the tool in a new tab, where it is a first-party context and ordinary cookies work. This is the fallback that always works and always costs something — the integration stops feeling seamless, and deep linking needs care to not break. Launching outside the iframe covers how to do it without losing the launch context.

How to test it

Do not wait for a customer to report it.

  1. In Safari, open the tool through a real LMS launch. Safari's defaults are the strictest of the major browsers, so it is the best single test.
  2. In Chrome, open an Incognito window, which blocks third-party cookies, and launch again.
  3. Test the deep linking flow separately. It has an extra postMessage step back to the LMS and can fail where a plain launch succeeds.

If all three work, you are not depending on third-party cookies.

What LTIAAS does

LTIAAS has set no browser cookies since February 2022.

Launch state is written to localStorage and read back to confirm the write succeeded before the flow continues. If that read-back fails and the platform supports it, LTIAAS falls back to LTI® Platform Storage and asks the LMS to hold the value instead. If neither is available, the launch fails closed with an error rather than proceeding without the security check.

After the launch, nothing is stored in the browser at all — your application gets the ltik in the URL and everything else happens server to server.

That removes the problem from the LTI® layer. It does not remove it from yours: if your own application sets a session cookie after launch, that cookie is still a third-party cookie, and fixes 2 through 4 above are still yours to apply.

Common questions

Why do third-party cookies break an LTI® launch?

The launch is a multi-step exchange. The tool has to remember a state value it generated in the first step and check it again when the ID Token arrives, and that value is traditionally kept in a cookie. Inside an LMS iframe that cookie is third-party, so if the browser drops it the tool cannot match the response to its own request and rejects the launch.

Which browsers block third-party cookies?

Safari blocks them by default and has since 2020. Firefox partitions them by default. Chrome announced a full deprecation, delayed it, then reversed it — they still work there by default but not in Incognito, and any user can turn them off.

Does storage partitioning break LTI® too?

No. A partitioned store is scoped to the combination of the top-level site and the frame's origin, and both the write and the read in a launch happen in that same combination. Partitioning is survivable; outright blocking is the problem.

Does LTIAAS need third-party cookies?

No. LTIAAS has set no cookies at all since February 2022. It uses localStorage with LTI Platform Storage as a fallback, and everything after the launch is keyed off the ltik, which travels in the URL.

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.