Use window.opener in OAuth flow only when localStorage doesn't work.

Move OAuth._endOfLoginResponse HTML/JS into asset instead of piecing it
together inline.

Fixes #2302.