2

I needed a way to sync user data across multiple domains that I own, so I figured I might as well implement an OAuth server, since others have already spent lots of effort in making sure its design is secure.

But it occurred to me that there are a lot of steps needed to securely deliver the access token to a client. Specifically PKCE and sending a code which can be exchanged for a token, rather than sending the token directly.

So I was wondering why the OAuth spec doesn't recommend that the token gets transferred via window.opener.postMessage() instead. This seems a lot less complex since you don't need a dedicated callback url, and it comes with the benefit that you can call window.close() so the user doesn't end up with multiple tabs and the state of their existing tab isn't lost. On top of that, you can use the targetOrigin parameter of postMessage() to ensure that the token ends up with the exact same domain that requested it in the first place.

Of course this wouldn't hold for server apps, since it would be safer to not send any access token to the client at all in that case, but for SPAs this seems a lot less complex and maybe even more secure.

Either way, this all seems a bit too good to be true to me. If it really was this straight forward, surely OAuth/OpenID Connect would have used this method in their recommendations.

So I was wondering if someone could point out a major reason why this approach couldn't be possible. Is it simply that OAuth/OpenID Connect was created during a time with fewer browser capabilities or is there something obvious I'm missing?

    2 Answers 2

    6

    It's technically possible to implement an OAuth-like workflow with window.open(), but it would have been very unwise to use this instead of redirects in the OAuth procotol:

    • OAuth is supposed to be a generic protocol which works in many different scenarios. Relying on window.open() would require the user agent to support JavaScript and the authorization server to provide suitable JavaScript code. This may be acceptable in some cases, but it's far less universal than a redirect-based approach which only uses basic HTTP and doesn't require JavaScript at all.
    • There are major accessibility concerns regarding window.open(). For example, even user agents which have JavaScript enabled often block JavaScript-triggered windows by default, because this feature has been abused far too often in the past.
    • OAuth purposely avoids specifying low-level details. For example, it doesn't even say how exactly the redirect should be implemented (a 302 status code is only used as in example). In comparison, your approach would require the specification to explicitly name individual JavaScript calls, making it longer and more complex.
    1
    • Ah that's a somewhat comforting answer. I was worried there was some technical flaw that made this insecure, but this gives me hope that it is at least somewhat feasible. I wouldn't be surprised if Google's Sign In SDK uses a similar approach.CommentedFeb 12 at 1:07
    1

    oAuth is an authorization protocol, Open ID Connect (OIDC) is an authentication protocol on top of oAuth 2.

    Both are designed for multiple usecase, SPA being only one of them. SPA’s have a singular problem though, you cannot trust the client.

    Postmessage doesn’t magically solve this problem and you just diluted the security you had. For such a setup you would need a service worker that would handle the Auth process. Something that might just be as secure as a MPA solution with server side Auth.

    Also consider that you need to do some hefty amount of crypto to properly verify the proces, on top of the crypto of the transport layer.

    Finally, the JavaScript engine isn’t designed to have postmessage as a secure communication channel, meaning it’s ill suited to communicate secret information over it. Secrets like authentication tokens. Something that your suggestion would require. And a problem not present in the current solution with multiple request.

    10
    • You are referring to a use case where a server makes all the api calls once it has received the access token. But there are legitimate use cases where a server doesn't even need to be involved. This is precisely why PKCE was added (initially for mobile apps but later for SPAs). Furthermore, postMessage is very well suited for secure communication as long as you set the correct targetOrigin parameter when sending and check MessageEvent.origin when handling messages.CommentedFeb 12 at 1:13
    • 1
      No. I am not. And PKCE was introduced for cases where you cannot trust the consumer (initiator) of the auth flow. The problem of postmessage are not solved by setting targetOrigin or by checking messageEvent.origin. Both of these can be trivially bypassed to intercept the message (since it’s not designed to not allow that). Specifically by things like browser extensions. Don’t abuse things there not made for when it comes to security, it just lowers it and most likely will just allow abuse or worse.
      – LvB
      CommentedFeb 12 at 8:06
    • 1
      But wouldn't extensions be able to intercept the access token response from the request that the client makes just as easily?CommentedFeb 12 at 12:47
    • At least the Mozilla documentation explicitly claims that postMessage() “safely enables cross-origin communication” as long as the sender and receiver verify each other. I also don't see how the method creates any new security issues (but it's perfectly possible I'm overlooking something).
      – Ja1024
      CommentedFeb 12 at 14:11
    • 1
      @LvB With the traditional flow, data gets sent via the address bar of the user. Which causes it unnecessarily get sent to the webserver and is prone to getting stored in the browser history of the user. How can postmessage have less protection than that?CommentedFeb 13 at 21:25

    You must log in to answer this question.

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.