Every time you refresh a sandbox, a new instance of your connected apps are created/installed. That's why your consumer key and consumer secret are changing.
One thing we can take advantage of is that you can install a connected app from one org into another org. Since the connected app itself only "lives" in a single org, it only has a single consumer key/secret pair. This means that you'd use the same consumer key/secret to go through your OAuth 2.0 flow for the org where the connected app "lives" and each other org that it's installed in.
"Installing" a connected app in another org is basically just:
- Start by going through the Web Server OAuth 2.0 flow, using
https://test.salesforce.com/services/oauth2/authorize?client_id=<your client id>&redirect_uri=<your redirect uri>&response_type=code
- Use "login.salesforce.com" if it's another production org (test.salesforce.com is for sandboxes, not sure what you'd use for a scratch org)
- You need to go through a flow that can give you a refresh token first before you can use the JWT flow
- Enter the credentials for the org that you want to install the connected app in
- Click "Allow"
If the connected app was already installed in your sandbox, then you'll need to first uninstall (completely remove) that sandbox's copy before installing a copy from a different org. I'm not sure if that's something that can be scripted (outside of something like Selenium at least). Working with scratch orgs instead of sandboxes would be much easier in that regard.
It is possible to use a plain 'ol browser to go through this process, but using something like Postman makes it easier/more repeatable. I've written up a procedure for using Postman to go through the web server flow in another question.
I also don't remember if there are any additional steps that are required to "finish" the install (i.e. go to the Connected App OAuth Usage page and click "install") before you can use the JWT flow.
So in the end, there are some parts of this process that can definitely be scripted/automated but I haven't put effort into trying to fully automate it. Using Apex for this is probably out of the question.