Currently we store credentials for access to other systems in a Custom Metadata Type. Per system, we store development, test and production credentials. The Apex code knows in what kind of org it is running and it always chooses the correct credentials.
But using a Custom Metadata Type is not a best practice. Salesforce recommends using Named Credentials. Not too long ago, Named Credentials have been updated and one of the consequences, according to this, is:
user external credentials from the production org, which store the encrypted access tokens, aren’t included in cloned or refreshed sandboxes [...] To test callouts after you create, refresh, or clone a sandbox, you must authenticate or enter credentials for a non-production environment in the external credential.
This is inconvenient, to say the least. Our current setup works perfectly, a refreshed sandbox can be used right away. But when using Named Credentials, we would have to enter the credentials for the other systems every time after a refresh. This will cause sandboxes to be refreshed less often, which is a risk (in our non-ideal world, changes are made in production that are not always made in the sandboxes).
How do you deal with this?