I'm getting quite involved in a web browser game to take my mind away from my dev work for a few hours. It appears the community playing this game are big fans of user scripts, allowing them to change certain aspects of the UI. Many of the community also host their own servers which allow them to organise and add structure outside of the game.
As a true dev at heart, I've also become one of those people. Hosting my own additional systems and producing my own scripts to augment the in-game experience with new data.
I'm looking into safe methods of passing data from my own server, via a user script to the users' browser once they are logged into the game. A live link between their browser and my system tools will allow for context related and personalised data to be injected into their game, such as live stats.
Since I only have the option of a user script, there are no open APIs for this game I am thinking of authenticating the user by the usage of a user API key which they generate from my system (once logged in) and then once they are logged into the game I can request this key via a form to authenticate their browser for any subsequent calls to my API endpoints.
There are a few questions I have and to be honest I absolutely love doing work like this as it allows me to gain knowledge in areas I take for granted in my day to day work. I've listed them below and it would be great for others to chip in with their thoughts and experiences.
I did a little research and my initial thought of just using a UUID as an API key brought up some interesting conversations from StackExchange. UUID generation can sometimes have too little entropy, which means to ensure an attacker does not just cycle through generating and trying these ID's I should also add some crypto on top of this. I've seen many approaches of hashing, adding salt, base64 encoding and then I stumbled upon this https://www.npmjs.com/package/generate-safe-id Am I right in thinking this is the only consideration I need to make?
This is quite an open-ended question. I've noticed when dealing with certain APIs in the real world they often show an API Key and an API Secret. What is the purpose of the differentiation between the two?
I do not plan on storing any information within my API Key, it is purely a random string without clashes (I hope) that I can run through my middleware policies to look up the user making the request and checking their access levels/look up their profile from such key. Are there any better approaches here? I wanted something lightweight and the usage of JWT with meta-data seems like overkill to me.
Where does it make sense to store the API Key on the client side? Since I am effectively injecting in code via my user script I have the option to store the key in a cookie or local storage. Which is better for persistence or which is typically best practice?
I plan to allow the user to login to my system and locate their profile page where they can generate their unique API Key. I will then store that key against their profile, with the option for them to re-generate (revoke the old) if they so wish. As an admin, I could re-generate / remove keys as I wish also. For the storage of API keys, I'm thinking it is perfectly fine for me to just store "as-is" within my DB, without any extra hashing. The reason being, if an attacker has access to the database then I have bigger problems, but also I wanted to keep this lightweight and any deciphering during my middleware policy checks will just add overhead to the request being made. Does this sound like a sensible approach?
Dealing with authentication of a users browser is one thing, but you can't ignore authorisation. As mentioned I will use the API key to authenticate the user against a profile stored in my database. During the middleware policy check, the user profile will be retrieved and I will then check to see if they have an access level of "member" or above. For those who have a key which is not associated with a profile and for those requests which return a profile with an access below "member", I will just send a 403 forbidden response back to the request. As far as I can see, this should satisfy my authorisation needs, but are there other practices/checks I should be making? I'm thinking along the lines of browser fingerprinting to check if the key is being used by a browser that initially saved the key to its storage.