I have this web application that is going to be all client-side technology (HTML, CSS, JavaScript/AngularJS, etc…). This web application is going to be interacting with REST API in order to access and modify data. Right now it is undecided on what type of authentication system the REST API is going to use.
From my understanding, any type of API authentication system (API Keys, OAuth 1/2, etc…) is going to have certain data that needs to be kept secret otherwise access can be compromised. For API Keys, they keys themselves need to be secret, for OAuth 2 the client secret/access tokens/refresh tokens need to be kept secret, I am sure a few of the 4 keys involved in OAuth 1 needs to be kept secret (not too much experience with OAuth 1). I have been trying to think if there is a way to store this secret stuff in a pure client-side web application without a middle layer of sorts on the server side.
I have been trying to think about this and I can’t think of any place to do that. I mean I can’t store it in javascript because anyone can just view the source or open up the console and get the data. I am not 100% sure how secure localStorage is and if users can access/modify that data. Even if local storage was secure, the two ways I can think of getting data into it are not. One way is to just store the data in the javascript source code which is the most insecure thing I can think of. Now if I was using something like OAuth 2 in which the rest api itself would give me the tokens, that would still not be that secure (better than the first option) because those tokens would be returned as plain text that anyone who can see the requests the computer is making could see.
Is there any way to have an application that is completely running client side be able to store secret pieces of data securely without some sort of middle layer on the server side?
3
No, it can never be completely secure. The user is in control of the hardware, and you are trying to keep something out of their hands. Ultimately, they CAN get it through one means or another. Since you are working from javascript, your position is MUCH worse than a normal computer application, as not only does the user control the hardware, they control the sandbox that you are running in.
You can hide things, and make it hard to get to stuff, but in the end they CAN get it out, if they try hard enough.
2
When designing security systems, one always needs to think about the threat model. “Make it secure” is a silly requirement, not actionable or verifiable. “Prevent the user from extracting the access tokens from the application” is much better, and defines the boundaries of the solution. “Prevent others from obtaining a user’s access tokens” is also better, and defines a completely different solution space. Solutions for one won’t necessarily solve the other (e.g., the latter absolutely requires SSL if WiFi is involved, but that won’t affect the former at all).
one option is for the REST API to grant access or not based on a user login; it can return a session-based token (guid, hashed string, whatever you like) which can be passed to the other REST API calls to authenticate access
if you’re worried about storing the user login info on the client machine, then don’t, but the user will have to enter the account and password information every time
not that familiar with OAuth et al, but I see no compelling reason above to store authentication information persistently at all…
1
@Michael Kohne is mistaken, there is 1 very established way to protect data in the browser. Banks do it, every site on the internet that shows you content that only you should see can do it securely.
@Ross Patterson started strong and is so close to being a perfect answer. The right approach is using a threat model and apply a risk based decision. But what was missing is something actionable for you.
Simply put; it will be deemed “secure” by the user, if the user is “challenged” before the sensitive information is sent to the browser.
A challenge can be an interaction like a simple passphrase or something more complicated like MFA, or it can be out-of-band like most password-less options (hardware token, bio-metric, or magic link emailed to the user).
There is also the non-interactive answer, like public key cryptography that is used by many companies like protonmail to ensure zero-knowledge email service that only the “browser user” can read their emails and even the email providers can’t. You may have noticed in 2018 reCAPTURE v3 has a zero-interaction solution (but most sites still use the annoying v2 that asks you to click annoying images for 5mins).
All of this to say;
- Challenge the user, or use client-side crypto, and after the server validates the individual you can share a secret with the browser user securely
- Make sure your transfer is secure too, TLSv1.2 or newer with only Forward Anonymity cipher permitted – no fallback allowed
- If you don’t consider this secure, you’re pretty much alone in that opinion and should disconnect, move to the mountains of Antarctica, and make yourself a tin-foil hat
Hope that gives you, and other readers, the tools to make good choices
5