Withdraw() executed on-chain or off-chain? (msg.sender safe as auth?)

I was building a withdrawal function for a contract that was using msg.sender.call{value: balance}, after checking that the given msg.sender was registered in the contract and had the given balance; however, I then read a couple of threads, e.g.,

that made me wonder whether this is safe. The answers to both of those questions indicate that msg.sender will only be validated for on-chain transactions — but how do I know if a given function will result in an on-chain transaction?

My understanding (see, e.g., the response here) was that no withdrawal functions are executed on-chain. So then how do we authorize users trying to withdraw from a contract?

Here is the relevant portion of my withdrawal function:

function withdraw() public {
    Person storage personData = _people[msg.sender];
    require(personData.personAddress == msg.sender, "Not a person in hash map");

    uint256 balance = personData.balance;
    personData.balance = 0;
    (bool success, ) = msg.sender.call{value: balance}("");
    require(success, "Withdrawal failed");
  }

see figure 5 of https://arxiv.org/pdf/2101.01917.pdf — as well as the sentence: "For instance, the function shown in Figure 5 violates NW [no writes after call], although it is not subject to reentrancy vulnerability. It is because the external call msg.sender.call has no dependency on numWithdraw." — The non-reentrancy vulnerability vs. NW distinction is not as important to me, here, as the fact that the withdraw call in figure 5 is deemed secure.

Hey, saw you linked to my answer.

Just to make a note about internal transactions. It's just bad naming for "contract call from a contract". when a contract calls another it still needs to pack the arguments and make the call just as if that method was called "directly" (by sending a transaction to call the method), this is probably from where the name comes from.

any call to an external contract using the opcodes CREATE, CALL, CALLCODE, DELEGATECALL and SELFDESCTUCT generates an "internal transaction". sites like etherscan trace transaction execution and for some known contracts, it show tokens and eth transfer entries on the "Tokens Transferred" section (of the transaction)

Those are of course part of a transaction, not off-chain