This led to an afternoon-long exploration.
My searching led to a WebKit bug - https://bugs.webkit.org/show_bug.cgi?id=24175 - which indicated that Safari didn't preserve URL fragments across a redirect. So, if you navigate to foo/a.html#42 and foo's server redirects you to foo/b.html, you'll not have that #42 applied when the browser loads the b.html page. However, this didn't seem to apply, as Instagram was putting the hash in the URL it sent.
My authentication with Instagram uses redirection. I send the user to a URL on the Instagram site, they handle having the user log in and allow my app, and the server then uses a HTTP 302 redirection to return them to my page with the token in the fragment.
After lots of testing various things, I found myself looking in the network monitor tab in Firefox again, and I noticed an extra 302 redirect. It turns out that my page was hosted at www.combee.net, but I'd specified combee.net in the URLs for Instagram. My web host did a 302 redirect to www.combee.net, and that second redirect was losing the hash with the authentication token.
Chaning my redirect URL to use www.combee.net directly fixed it, and now its working on all the platforms.