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:
- The platform sends the browser to the tool's login initiation endpoint.
The tool generates a
statevalue here and has to store it. - The tool redirects the browser back to the platform's authentication endpoint.
- The platform POSTs the ID Token to the tool's launch URL.
The tool reads its stored
stateback and checks it matches.
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:
| Symptom | What is actually happening |
|---|---|
Invalid state or Missing state param | Step 3 could not read what step 1 wrote |
| Blank white iframe | Tool errored server-side, LMS shows the empty frame |
| Redirect loop back to your login page | Session 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.
2. Carry the session in the URL instead of a cookie
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.
- 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.
- In Chrome, open an Incognito window, which blocks third-party cookies, and launch again.
- Test the deep linking flow separately. It has an
extra
postMessagestep 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
- LTI® Platform Storage explained — the protocol fix
- Launching outside the iframe — the fallback that always works
- Why your LTI® tool shows a blank page — diagnosing the symptom
- Cookies and LTI® — the LTIAAS-specific guide
