Http-Only Cookies w/ OAuth Authorization Grant
-
I recently setup FusionAuth and I've been loving it. I'm having trouble figuring out the best way to store my OAuth access and refresh tokens though.
Background
I've setup my client-side JavaScript app to log users in using OAuth's authorization code grant. I've turned off authentication on FusionAuth's
/oauth2/authorize
endpoint so that I can call it from my client-side app without a secret. I'm using PKCE to prevent auth code interception. When I receive an authorization code via the redirect from FusionAuth, I POST it to the/oauth2/token
endpoint to exchange it for an access and refresh token. The tokens come back as in a JSON object in the response body. So far so good.Problem
The problem is that I don't want to store the tokens in JavaScript, but that's my only option if FusionAuth sends them to me in a response body. I would rather have the tokens be send as HTTP Only cookies so that they get sent along with requests to my backend (which can validate them) but they're not vulnerable to JS on the client. Is there any way to get FusionAuth's
/oauth2/token
endpoint to pass the tokens back as cookies? And if so, is there any way to get the same endpoint to accept a refresh token via cookies (since I won't have access to it in JS and won't be able to provide it via a request parameter)?Half-baked solution
The best thing I can think of so far is to add an endpoint on my backend that will reflect the tokens back as HTTP Only cookies (I send the tokens via POST request parameters and it sends cookies back). Is that as secure as I think it is? If so that solves the issue with
/oauth2/authorize
redirect not sending cookies (although it would be nice to solve auth purely with requests between my client-side app and FusionAuth). The remaining problem is how to use my refresh token to get a new access token - the/oauth2/token
endpoint requires the refresh token be passed as a parameter, but I'll only be able to send it as a cookie. Are there any solutions to this? -
Ok so it sounds like once the tokens have been sent to the client via the
/oauth2/token
response body they've technically been exposed - if malicious JS was on the page it could intercept them regardless of whether I store them in non-http-only cookies or local storage. So it seems like the only option is to do the code-for-token exchange on my backend server. Then I can send the http-only cookies down the pipe myself. Can anyone validate my thinking? -
What you are looking for is some of the Auth Flows that we have outlined (pay attention to the recommended ones for a secure setup). Specifically, this one might be helpful.
The common pattern is to have a BFF (backend for frontend) to keep things secure.
We have a nice example of how to securely complete the OAuth handshake in our 5-minute guide, with a section on how to use cookies. I would start there for an overview on how to complete the OAuth handshake using express and nodeJS.
https://fusionauth.io/docs/v1/tech/5-minute-setup-guide#cookies-for-a-single-page-applicationI hope this is a good starting point. Let us know if you have other questions.
Thanks,
Josh