Is it a bad idea to send username and password with every request from a mobile/web app to the backend api

This would make a great security interview question, because it measures very well the level of understanding in the security domain.

Sending username/password in each request is not advisable, but the other answer does not even touch on the real reasons why.

Technically, a username/password is pretty much the same as something like an API key, they are equivalent for the time they are valid. An API key is even worse in a sense, because depending on implementation, you would typically store API keys plaintext in the database, as opposed to properly hashed passwords (sidenote, but please use something like bcrypt or pbkdf2 when hashing). You are totally right, a password could be sent the same way as an API key on each request, you can revoke it the same way, etc. The API key is the password. There is absolutely no difference in this regard.

However, you should still probably not do it in most cases, for at least the following reasons.

Passwords are weak if chosen by users. If you have many users, many will have passwords like 123456 and similar. It will be easy to guess some of them. You don't need to run this risk in an API app, however, sending it in every request or not barely modifies this risk, but it does a little bit, because of the next point.

Sometimes there are weaknesses in SSL/TLS. It does happen from time to time that a new attack against TLS is disclosed, which is then patched eventually. For some time though, it may be possible for an attacker to deduce bits from an encrypted stream, which may be made easier if the encrypted content is partially known (ie. common passwords). Chances are not very high, but the problem is, with many TLS cipher suites, an attacker can record traffic now, and decrypt it later (because it takes long, or the method is not yet invented). If he only decrypts an API key that has been obsolete for 3 years, fine, but if it's a user password... Not so good.

Server vulnerabilities can also be a problem. A while ago there was a vulnerability in the openssl implementation where you could practically read parts of the server memory (the webserver process). If the webserver receives the user password all the time, it will be in memory probably multiple times. If it's just a temporary API key (or a session id or whatever), that's less value for the attacker. It's still good, but at least not the password.

Internal attackers are also something to consider. If you have an attacker already on the server, he may not be able to access the database to directly read/modify credentials, but he may be able to observe the web server process for a limited time. The same as above, it's much better if he can only observe temporary ids instead of actual passwords.

You need to store the password on the client if you want to send it with each request. Storing sensitive stuff on the client is not usually a good idea, opens up possibilities for an attacker. It's usually better if the user enters credentials, receives a temporary token and the client forgets about the actual password until the token expires and the user has to provide his password again. This of course may or may not be acceptable from a user experience point of view - but security is always a balance. :)

So as you can see, sending the username/password in each request is not a direct vulnerability. In fact, it may even be acceptible in many scenarios. But you can make it more secure by using temporary credentials, and why would you not, if the cost is reasonable?


Yes, it is

This is generally a terrible idea. WEP was an old network security protocol that ended up being replaced due to its intrinsic weakness to be able to get the password from a packet (beacon) without even being authenticated with the network. This is why we don't store credentials like this in transit.

What should I do instead?

I'd recommend using an API key. This is a private key that you can send with each request that the program can look up in the database and correlate to a particular user. For example, if a user (let's call him Bob) signs up and requests an API key, you will give him a key (e.g. asdf12345) the equivalent of a ticket. He can use that ticket to perform certain actions, as long as he presents his ticket each time he does something. Similar to how you can order drinks and food in a hotel's bar / restaurant and just show your room card, you'd need to show it each time you order drinks. Each time Bob performs a requests to your server, he will need to present the ticket number asdf12345 and this will allow you to see that Bob is allowed to access these methods. Mary doesn't have a ticket, so when she requests some data, she will be denied because she does not have a token.

How do I do this?

Each time a user signs up for an account with your website and requests a token (and perhaps agrees to some T&Cs you have), you generate a GUID / random hash and store it in a dbo.ApiKeys table which should contain both the API key and a UserId. The user's application should add this key so that any time it performs an API request, they can include this token. This prevents you from giving up user's credentials in each request. It also means that if a user manages to have their API key compromised by whatever means, it's generally their fault (they were in starbucks on an insecure connection, they had it saved in a .txt file on their desktop, they wrote it on a sticky note on their desk etc.)

EDIT: The OWASP Standards

If you're interested in further reading and would like to know the industry standard for this, OWASP has a page dedicated to this particular task. They are the universal go-to wiki for best practises in computer security.