I have multiple companies utilising my GET endpoint, each company needs to have their own API key which they will provide as a url parameter.
I need to keep generating these token whenever new company will join in (there is a table reflecting this).
Is it safe to just:
company_token pivot table
– generate token as
str_random(32) (because GET request might have maximum url length)
? Or is there a safer, better method?
The best solution I guess would be to use JWT.
You can generate token for each company and distribute them.
Instead of sending the token in the URL as a query parameter, use the HTTP request authorization header and send the token as bearer token.
The simpler and most secure way of keeping a company-level API token would be what you are already doing – using a secure PRNG to get a HTTP-safe token, which is what
str_random() does, and having a UNIQUE constraint on the API token table to be sure you don’t get duplicates.
You could also supply a way of changing the API token by the company, after a suitable login, in order to allow them to get rid of obsolete or leaked tokens. Since you would update the API row and not keep old values, keeping track of obsolete tokens would not be a concern.
Security (as much as possible)
To avoid sending the token visibly in the URL, you could also receive them from a custom HTTP Header, as @AbdurRahman suggested.
Finally, you could use the token only once per session and per client: the API token can be consumed only by a
/nonce API, which will reply with a longer token in the form of “IP:DATE:HASH” (e.g. “192.168.168.192:2020.02.16.15.35:ee2998d477ee4a1b50e886590d228239”), which would be around 64 bytes. The hash would be produced by MD5(“IP:DATE:SECRET”), which guarantees that the information has not been tampered with. All subsequent APIs just verify that this token is untampered with, the IP matches and the date is not too far in the past (or the future).
The advantage is that the token being sent is now different for each client and changes every time, so even if it gets intercepted, little damage would be done. The “real” token that would be harmful if intercepted is sent only once per session; there are more secure schemes than this, but this would already be an improvement.