So I have this working, but it's not particularly as clean as I would have liked...
When the manifest file is created it puts a single-use token in the start_url. That token can be used once (it also expires if it's not used within 5 minutes). Visiting the start_url address (normally that would just be when the PWA app loads), it checks the token (if it hasn't already been used and hasn't expired), it will automagically log the user in (the user that retrieved the manifest file that the token was embedded into).
Here's what I don't like about it... since there isn't a way to tell the difference between a browser and PWA on the server-side, we end up generating a new single-use login token every time a logged in user requests the webmanifest file. It's
probably okay (can't think of a realistic scenario where the start_url would be leaked to an unintended party), however I don't love the fact that the token exists when it's not needed (even if it's short-lived). I was able to mitigate this being needed
most of the time because when the manifest file is requested, it does at least pass the referrer (so if the referrer has a single-use token, even if it's expired, we don't generate a new token because we are already in the PWA app presumably).
Additionally, I worked out all the other things I wish the PWA app did:
- Use Sec-Fetch-Site header as replacement for CSRF (fallback to CSRF if browser doesn't support Sec-Fetch-Site) - prevent stale sessions causing security error (for example when you open the PWA app that has been idle for awhile). An "up to date" CSRF token is no longer needed.
- Automatic refresh of badge counters when app is loaded/brought to front (I ended up applying this to the site as a whole, not just the PWA app). Like if your browser was minimized for hours or overnight and you bring that page to the front, it will update the counter badges (see above... we don't need an up to date CSRF anymore to do this in a secure way).
- Give more prominent push notification permission message when initially loading app (put it up top and a little bigger rather than pinned to bottom... only applies to app, and even then only on the initial loading of it... if you ignore it and navigate to a different page, it goes back to being pinned to the bottom).