fedidcg / FedCM

A privacy preserving identity exchange Web API
https://fedidcg.github.io/FedCM
Other
357 stars 66 forks source link

OAuth draft for browser based apps and Access Tokens in JavaScript #514

Open obfuscoder opened 7 months ago

obfuscoder commented 7 months ago

The recent OAuth draft for browser based apps (https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps) focuses on the threat of malicious JavaScript. There is always the risk of XSS or injected code and the draft seemingly argues towards not having Access Tokens (AT) in the JS client, but rather have the BFF take care of the AT and bind the JS client with a session cookie. As far as I can see that, the discussed JS attack threats also apply to FedCM. At its current state, FedCM only works with a JS client. There cannot be a BFF or any other backend in between client app and IdP to avoid having the Tokens in the JS part. Are there any plans to have a flow which allows the client to initiate FedCM, but essentially the Tokens are transfered from IdP to a backend-system of the RP?

npm1 commented 7 months ago

I don't follow why there cannot be any other backend between the client app and the IdP. If the RP wanted to create a BFF they could do so, have it be 'the IdP' for the FedCM API, and interact with the actual IdP server-side.

obfuscoder commented 7 months ago

Well in this case, neither the client/RP nor the IdP would need to use FedCM, as the BFF and client are usually on the same site and can use first party context. However the login session cookie set at the IdP domain in the browser of the user is not available when doing a B2B communication between BFF and IdP. It would require a redirect request instead of a simple call.

achimschloss commented 7 months ago

For my understanding, the security concerns revolve around that the FedCM API today will always return the opaque token issued by the IDP (as received by the browser from the the id-assertion-endpoint) when resolving the promise to the navigator.credentials.get call. Which makes to token available client side an thus susceptible of malicious JS on the RP side.

aaronpk commented 1 month ago

A pattern I've implemented is to have the IDP return an authorization code in the FedCM response, and the JavaScript sends that to its backend which completes the OAuth flow so that the access token is only ever on the server, never in the browser.

Once the JavaScript is able to pass arbitrary parameters to the assertion endpoint (#556), we can even add PKCE support for even better security of the flow.

obfuscoder commented 1 month ago

@aaronpk That sounds reasonable and it is quite similar to what we came up with.

We don't return an Access Token with the FedCM id_assertion_endpoint, but something (we call itt FedCM token) containing the authorization code which can then be used to obtain Access Token, Refresh Token and Id Token at the Token endpoint of the IdP. The request to the Token endpoint could be done by the JS running iin the browser (with its inherant vulnerability to XSS) or by a BFF which the JS part passes to the BFF. In tthe second case, client credentialls can be used as well as proper Token binding.

I'm looking forward for the arbitrary input paramters to the id assertion endpoint for that PKCE support.

I wonder if we should add this pattern in some BCP (probably too early) or security consideration section in the FedCM spec.

brockallen commented 1 month ago

@aaronpk and @obfuscoder, I've not looked at details, but I wanted to ask if there was some nonce-like protection in your approaches to validate correlation from the request and response when you are using a back-end/BFF that ultimately issues a cookie in the RP for the user's authentication session?

For example, I was imagining something in the JS before the FedCM flow begins that pings a backend/BFF to initiate the workflow. That response issues some correlation cookie and returns a nonce value. This nonce is then used in the FedCM workflow. Once the JS gets the FedCM response, it would send it to the backend and the backend would need to validate that nonce along with the response (like the code or this FedCM token).

So again, apologies for not having looked into the details yet, but I wanted to ensure there was something like this (much like how nonce is used in OIDC). I guess if PKCE was somehow also worked into this, then it would serve a similar purpose.

Thanks in advance.

aaronpk commented 1 month ago

Yes, I sent the PKCE code challenge in the FedCM "nonce" field. Once we can pass arbitrary parameters this will get cleaned up.

obfuscoder commented 1 month ago

In our implementation we allow the client to specify a nonce and return it in the ID token which the client should validate afterwards. Whether the client generates tthe nonce in the JS client or the BFF can be decided by the client. We do not use the nonce as PKCE, though. The purpose is different, but I can see why @aaronpk used it that way as that is currently the only way to pass any parameter like a required PKCE code challenge to the IdP.

aaronpk commented 1 month ago

Yep, and I don't use ID tokens so there's no need for the OpenID Connect nonce.

and fwiw I did implement it by having the frontend ping the backend when starting the flow and the backend generates the PKCE code verifier and sends the challenge to the frontend to include in the FedCM call.

brockallen commented 1 month ago

and fwiw I did implement it by having the frontend ping the backend when starting the flow and the backend generates the PKCE code verifier and sends the challenge to the frontend to include in the FedCM call.

Yes, I see this as the safe approach since a backend can't ever trust what's happening in the JS.

aaronpk commented 1 week ago

Can this issue be closed? I believe we've demonstrated that it is possible to accomplish the original goals in the issue with the current spec, and will be even better with the final resolution of #556

If you haven't seen it yet, here's my notes on implementing OAuth on top of FedCM, keeping the access token entirely out of the JavaScript layer: https://github.com/aaronpk/oauth-fedcm-profile

obfuscoder commented 1 week ago

The new FedCM API definitly enables such a flow. However, my original question was about whether the FedCM spec should at least mention (security considerations) that using only browser-based JS to obtain and use security tokens is prone to XSS attacks.

npm1 commented 1 week ago

Do you mind taking a stab at adding a "Note: " to the spec? I think you understand the issue better than anyone and can probably write it best. Happy to review and get it merged.