This depends a lot on the kind of game you’re making, but at the end of the day it boils down to something pretty simple. The authoritative server model requires that the actions the clients take meet the rules the server enforces, however - all the actions still have to take place on the client. The reason you would still include all the appropriate calculations client side is to reduce the amount of information you send back and forth. It’s not a security issue to do the calculations on the client, because what actually takes place (for everyone else) is dictated by the server. If that’s confusing I can provide a few examples.
Let’s take a simple example of a player throwing a grenade, and damage being applied to a few players and maybe the side of a building. Even if you ‘hacked’ your local client to say you have a grenade, if the server doesn’t agree - you can try to throw them all day long, the event will never take place on the other clients. Even if you could trick your client into displaying the grenade and the effects, it wouldn’t actually affect anyone else - you would just be displaying some effects on your screen that did nothing. So why would we still need the code in the client for what happens when you throw a grenade? Well it all has to do with latency and amount of data sent. If you didn’t have everything in place on the client, you would have to send the data back for the trajectory/path of the grenade, and when the explosion happens you’d have to tell it where all the little things flew, debris etc. You’d also not see the effects until the round trip time between your client and server, this delay would be noticeable and would be kind of shocking to what people expect. So what really happens is you simulate everything on the client, and send the minimum information possible to the server. You’re just sending rotations/key inputs at the moment the grenade is thrown. At that point in time, your client is simulating the results of the action, while the information travels to the server. The server checks the appropriate information (are you where you say you are, do you have a grenade, can you throw it, did it hit anything in the way, whatever), it calculates the damage from the explosion and sends the information back to the clients. So even if you have the code on the client side to apply damage, spawn inventory items, whatever - it doesn’t matter if the server disagrees it doesn’t happen. The way to insure the type of security that you’re curious about is by only allowing some pieces of information to flow one way. Never let a client tell you what damage it did, what it’s inventory is - etc.
You need to always have the appropriate information in the client to calculate everything that’s happening in the game. The server will do the same calculations and send the result (of neccessary things) to the clients, overriding anything that they’ve done locally - this is why rubberbanding happens in games like Counter Strike - the server is correcting the position your client thinks something is, with the position it really is. Your client becomes a simulation which derives all of it’s essential data from the server. The server must absolutely be authoritative (meaning, even if the client calculated something different, it gets overridden and replaced with the server’s result) when it comes to things like - world position, health, damage, inventory/trades, etc. Clients would say “this is my current direction and velocity”, the server checks if based on their previous position and velocity (that the server already knew from the last tick), if this is possible within the rules of the game and what the client is doing, if it is - the server just confirms that’s the new position, if it’s not it sends back corrections. Client sends “fire weapon” event, server responds with hit (and damage if necessary) or miss, the client might have determined it was a hit - but the server determines it’s a miss which means in the actual game no damage is taken by the other player, regardless of what your client insists happened.
Anything that you think a client would cheat about, just make the server double check and refuse to do it if the information is wrong. The problem with this is the more things you check, the more you have to check per client and the more bandwidth/CPU time is used, that’s why sometimes there are tradeoffs for trusting the client - but if you want to make a game (like an MMO) then you have to not trust the client, ever. Clients are not on your hardware and not in your control, you have to assume that any connected client is 100% malicious and a liar, think of it this way from the start and you won’t have many problems.
Edited to add - if you have time, read this article from Gaffer on Games What Every Programmer Needs To Know About Game Networking | Gaffer On Games